# Home Assistant ## Overview [Home Assistant](https://github.com/home-assistant/core) is an open-source home automation platform. In the Ouranos sandbox it runs as a native Python application inside a virtual environment, backed by PostgreSQL for state recording and fronted by HAProxy for TLS termination. **Host:** Oberon **Role:** container_orchestration **Port:** 8123 **URL:** https://hass.ouranos.helu.ca ## Architecture ``` ┌──────────┐ HTTPS ┌──────────────┐ HTTP ┌──────────────┐ │ Client │────────▶│ HAProxy │────────▶│ Home │ │ │ │ (Titania) │ │ Assistant │ └──────────┘ │ :443 TLS │ │ (Oberon) │ └──────────────┘ │ :8123 │ └──────┬───────┘ │ ┌─────────────────┼─────────────────┐ │ │ │ ┌────▼─────┐ ┌──────▼──────┐ ┌─────▼─────┐ │PostgreSQL│ │ Alloy │ │ Prometheus│ │(Portia) │ │ (Oberon) │ │(Prospero) │ │ :5432 │ │ scrape │ │ remote │ │ recorder │ │ /api/prom │ │ write │ └──────────┘ └─────────────┘ └───────────┘ ``` ## Ansible Deployment ### Playbook ```bash cd ansible ansible-playbook hass/deploy.yml ``` ### Files | File | Purpose | |------|---------| | `hass/deploy.yml` | Main deployment playbook | | `hass/configuration.yaml.j2` | Home Assistant configuration | | `hass/requirements.txt.j2` | Python package pinning | | `hass/hass.service.j2` | Systemd service unit | ### Variables #### Host Variables (`host_vars/oberon.incus.yml`) | Variable | Description | Value | |----------|-------------|-------| | `hass_user` | System user | `hass` | | `hass_group` | System group | `hass` | | `hass_directory` | Install directory | `/srv/hass` | | `hass_media_directory` | Media storage | `/srv/hass/media` | | `hass_port` | HTTP listen port | `8123` | | `hass_version` | Pinned HA release | `2026.2.0` | | `hass_db_host` | PostgreSQL host | `portia.incus` | | `hass_db_port` | PostgreSQL port | `5432` | | `hass_db_name` | Database name | `hass` | | `hass_db_user` | Database user | `hass` | | `hass_db_password` | Database password | `{{ vault_hass_db_password }}` | | `hass_metrics_token` | Prometheus bearer token | `{{ vault_hass_metrics_token }}` | #### Host Variables (`host_vars/portia.incus.yml`) | Variable | Description | |----------|-------------| | `hass_db_name` | Database name on Portia | | `hass_db_user` | Database user on Portia | | `hass_db_password` | `{{ vault_hass_db_password }}` | #### Vault Variables (`group_vars/all/vault.yml`) | Variable | Description | |----------|-------------| | `vault_hass_db_password` | PostgreSQL password for hass database | | `vault_hass_metrics_token` | Long-Lived Access Token for Prometheus scraping | ## Configuration ### PostgreSQL Recorder Home Assistant uses the `recorder` integration to persist entity states and events to PostgreSQL on Portia instead of the default SQLite. Configured in `configuration.yaml.j2`: ```yaml recorder: db_url: "postgresql://hass:@portia.incus:5432/hass" purge_keep_days: 30 commit_interval: 1 ``` The database and user are provisioned by `postgresql/deploy.yml` alongside other service databases. ### HTTP / Reverse Proxy HAProxy on Titania terminates TLS and forwards to Oberon:8123. The `http` block in `configuration.yaml.j2` configures trusted proxies so HA correctly reads `X-Forwarded-For` headers: ```yaml http: server_port: 8123 use_x_forwarded_for: true trusted_proxies: - 10.0.0.0/8 ``` ### HAProxy Backend Defined in `host_vars/titania.incus.yml` under `haproxy_backends`: | Setting | Value | |---------|-------| | Subdomain | `hass` | | Backend | `oberon.incus:8123` | | Health path | `/api/` | | Timeout | 300s (WebSocket support) | The wildcard TLS certificate (`*.ouranos.helu.ca`) covers `hass.ouranos.helu.ca` automatically — no certificate changes required. ## Authentication Home Assistant uses its **native `homeassistant` auth provider** (built-in username/password). HA does not support OIDC/OAuth2 natively, so Casdoor SSO integration is not available. On first deployment, HA will present an onboarding wizard to create the initial admin user. ## Monitoring ### Prometheus Metrics Home Assistant exposes Prometheus metrics at `/api/prometheus`. The Alloy agent on Oberon scrapes this endpoint with bearer token authentication and remote-writes to Prometheus on Prospero. | Setting | Value | |---------|-------| | Metrics path | `/api/prometheus` | | Scrape interval | 60s | | Auth | Bearer token (Long-Lived Access Token) | **⚠️ Two-Phase Metrics Bootstrapping:** The `vault_hass_metrics_token` must be a Home Assistant **Long-Lived Access Token**, which can only be generated from the HA web UI after the initial deployment: 1. Deploy Home Assistant: `ansible-playbook hass/deploy.yml` 2. Complete the onboarding wizard at `https://hass.ouranos.helu.ca` 3. Navigate to **Profile → Security → Long-Lived Access Tokens → Create Token** 4. Store the token in vault: `vault_hass_metrics_token: ""` 5. Redeploy Alloy to pick up the token: `ansible-playbook alloy/deploy.yml` Until the token is created, the Alloy hass scrape will fail silently. ### Loki Logs Systemd journal logs are collected by Alloy's `loki.source.journal` and shipped to Loki on Prospero. ```bash # Query in Grafana Explore {job="systemd", hostname="oberon"} |= "hass" ``` ## Operations ### Start / Stop ```bash sudo systemctl start hass sudo systemctl stop hass sudo systemctl restart hass ``` ### Health Check ```bash curl http://localhost:8123/api/ ``` ### Logs ```bash journalctl -u hass -f ``` ### Version Upgrade 1. Update `hass_version` in `host_vars/oberon.incus.yml` 2. Run: `ansible-playbook hass/deploy.yml` The playbook will reinstall the pinned version via pip and restart the service. ## Troubleshooting ### Common Issues | Symptom | Cause | Resolution | |---------|-------|------------| | Service won't start | Missing Python deps | Check `pip install` output in deploy log | | Database connection error | Portia unreachable | Verify PostgreSQL is running: `ansible-playbook postgresql/deploy.yml` | | 502 via HAProxy | HA not listening | Check `systemctl status hass` on Oberon | | Metrics scrape failing | Missing/invalid token | Generate Long-Lived Access Token from HA UI (see Monitoring section) | ### Debug Mode ```bash # Check service status sudo systemctl status hass # View recent logs journalctl -u hass --since "5 minutes ago" # Test database connectivity from Oberon psql -h portia.incus -U hass -d hass -c "SELECT 1" ``` ## References - [Home Assistant Documentation](https://www.home-assistant.io/docs/) - [Home Assistant GitHub](https://github.com/home-assistant/core) - [Recorder Integration](https://www.home-assistant.io/integrations/recorder/) - [Prometheus Integration](https://www.home-assistant.io/integrations/prometheus/) - [HTTP Integration](https://www.home-assistant.io/integrations/http/)