{ lib, config, ... }: let configDir = "/var/lib/hass"; dbUser = "hass"; in { options.services.home-assistant = { subdomain = lib.mkOption { type = lib.types.str; description = "subdomain of base domain that home-assistant will be hosted at"; default = "home-assistant"; }; database = lib.mkOption { type = lib.types.enum [ "builtin" "postgres" ]; description = "what database do we want to use"; default = "builtin"; }; extensions = { sonos = { enable = lib.mkEnableOption "enable the sonos plugin"; port = lib.mkOption { type = lib.types.int; default = 1400; description = "what port to use for sonos discovery"; }; }; jellyfin = { enable = lib.mkEnableOption "enable the jellyfin plugin"; }; }; }; config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [ { host = { reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = { target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; websockets.enable = true; forwardHeaders.enable = true; extraConfig = '' add_header Upgrade $http_upgrade; add_header Connection \"upgrade\"; proxy_buffering off; proxy_read_timeout 90; ''; }; }; services.home-assistant = { configDir = configDir; extraComponents = [ "met" "radio_browser" "isal" "zha" "webostv" "tailscale" "syncthing" "analytics_insights" "unifi" "openweathermap" "ollama" ]; config = { http = { server_port = 8123; use_x_forwarded_for = true; trusted_proxies = ["127.0.0.1" "::1"]; ip_ban_enabled = true; login_attempts_threshold = 10; }; recorder.db_url = "postgresql://@/${dbUser}"; "automation manual" = []; "automation ui" = "!include automations.yaml"; }; extraPackages = python3Packages: with python3Packages; [ hassil numpy gtts ]; }; # TODO: configure /var/lib/hass/secrets.yaml via sops systemd.tmpfiles.rules = [ "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" ]; } (lib.mkIf (config.services.home-assistant.extensions.sonos.enable) { services.home-assistant.extraComponents = ["sonos"]; networking.firewall.allowedTCPPorts = [ config.services.home-assistant.extensions.sonos.port ]; }) (lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) { services.home-assistant.extraComponents = ["jellyfin"]; # TODO: configure port, address, and login information here }) (lib.mkIf (config.services.home-assistant.database == "postgres") { host = { postgres = { enable = true; extraUsers = { ${dbUser} = { isClient = true; createUser = true; }; }; extraDatabases = { ${dbUser} = { name = dbUser; }; }; }; }; services.home-assistant = { extraPackages = python3Packages: with python3Packages; [ psycopg2 ]; }; systemd.services.home-assistant = { requires = [ config.systemd.services.postgresql.name ]; }; }) (lib.mkIf config.host.impermanence.enable { assertions = [ { assertion = config.services.home-assistant.configDir == configDir; message = "home assistant config directory does not match persistence"; } ]; environment.persistence."/persist/system/root" = { enable = true; hideMounts = true; directories = [ { directory = configDir; user = "hass"; group = "hass"; } ]; }; }) ]); }