From 02085e7ff198601e0271830f8219e32705f2bb15 Mon Sep 17 00:00:00 2001 From: mjallen18 Date: Tue, 26 Aug 2025 20:14:18 -0500 Subject: [PATCH] cleanup hass some --- modules/nixos/homeassistant/default.nix | 412 +----------------- modules/nixos/homeassistant/options.nix | 6 + .../services/homeassistant/default.nix | 270 ++++++++++++ .../services/music-assistant/default.nix | 68 +++ .../services/zigbee2mqtt/default.nix | 61 +++ systems/x86_64-linux/nuc/default.nix | 1 + 6 files changed, 408 insertions(+), 410 deletions(-) create mode 100644 modules/nixos/homeassistant/services/homeassistant/default.nix create mode 100644 modules/nixos/homeassistant/services/music-assistant/default.nix create mode 100644 modules/nixos/homeassistant/services/zigbee2mqtt/default.nix diff --git a/modules/nixos/homeassistant/default.nix b/modules/nixos/homeassistant/default.nix index ea0c90d..754221d 100755 --- a/modules/nixos/homeassistant/default.nix +++ b/modules/nixos/homeassistant/default.nix @@ -1,288 +1,16 @@ { config, lib, - pkgs, namespace, ... }: let cfg = config.${namespace}.services.home-assistant; - mosquittoPort = 1883; - zigbee2mqttPort = 8080; in { imports = [ ./options.nix ]; config = lib.mkIf cfg.enable { - # imports = [ ./hacs ]; - - services.home-assistant = { - enable = true; - openFirewall = true; - configDir = "/var/lib/homeassistant"; - configWritable = true; # todo - extraComponents = [ - "adguard" - "apple_tv" - "analytics" - "backup" - "bluetooth" - "bluetooth_adapters" - "bluetooth_le_tracker" - "bluetooth_tracker" - "brother" - "caldav" - "calendar" - "cloudflare" - "co2signal" - "color_extractor" - "esphome" - "ffmpeg" - "google_translate" - "holiday" - "homekit" - "isal" - "jellyfin" - "met" - "music_assistant" - "mqtt" - "nut" - "nextcloud" - "nws" - "ollama" - "onedrive" - "open_router" - "ping" - "radio_browser" - "samsungtv" - "season" - "shopping_list" - "simplefin" - "smartthings" - "subaru" - "upnp" - "vesync" - "workday" - "wyoming" - "zha" - ]; - - customComponents = with pkgs.home-assistant-custom-components; [ - # nixpkgs - auth-header - localtuya - - # packages - pkgs.${namespace}.ha-anycubic - pkgs.${namespace}.ha-bambulab - pkgs.${namespace}.ha-gehome - pkgs.${namespace}.ha-icloud3 - pkgs.${namespace}.ha-mail-and-packages - pkgs.${namespace}.ha-nanokvm - pkgs.${namespace}.ha-openhasp - pkgs.${namespace}.ha-overseerr - pkgs.${namespace}.ha-petlibro - pkgs.${namespace}.ha-wyzeapi - ]; - - customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [ - atomic-calendar-revive - bubble-card - button-card - hourly-weather - mini-graph-card - mini-media-player - multiple-entity-row - mushroom - vacuum-card - weather-chart-card - zigbee2mqtt-networkmap - ]; - # use postgresql instead of sqlite - extraPackages = - ps: with ps; [ - # Core functionality - aiohttp - aiodns - paho-mqtt - pillow - pytz - pyyaml - sqlalchemy - - # Discovery & networking - zeroconf - netdisco - ifaddr - ssdp - - # Device protocols - pyserial # Serial communications - bluepy # Bluetooth LE - - # Smart home ecosystems - mutagen # Media file metadata - pysonos # Sonos - pywemo # Belkin WeMo - python-miio # Xiaomi devices - python-kasa # TP-Link - - # Sensors & monitoring - meteocalc # Weather calculations - speedtest-cli # Internet speed - - # Visualization & UI - matplotlib # Graphing - - # Security - bcrypt - cryptography - pyjwt - - # Media - ha-ffmpeg # Camera streams - - # Specialized integrations - python-matter-server # Matter protocol - - # System integrations - psutil # System monitoring - - psycopg2 - numpy - hassil - pyturbojpeg - paho-mqtt - pychromecast - pyatv - python-otbr-api - brother - pyipp - govee-ble - adguardhome - nextcord - aiogithubapi - jellyfin-apiclient-python - pylitterbot - dateparser - aionut - nextcloudmonitor - ollama - pynecil - aiopyarr - pysabnzbd - getmac - zigpy - bellows # For Zigbee EmberZNet-based adapters - zigpy-xbee # For XBee adapters - zigpy-deconz # For ConBee/RaspBee adapters - pyicloud # iCloud - pyatv # Apple TV - opencv-python - face-recognition - ibeacon-ble - gehomesdk - onedrive-personal-sdk - python-roborock - pkgs.${namespace}.python-steam - apple-weatherkit - - samsungctl - samsungtvws - - aiohomekit - - icmplib - aioelectricitymaps - wyoming - pysmartthings - wakeonlan - ephem - ]; - - config = { - # Includes dependencies for a basic setup - # https://www.home-assistant.io/integrations/default_config/ - default_config = { }; - - cloud = false; - - frontend = { - themes = "!include_dir_merge_named themes"; - }; - - "automation ui" = "!include automations.yaml"; - "scene ui" = "!include scenes.yaml"; - "script ui" = "!include scripts.yaml"; - - http = { - use_x_forwarded_for = true; - trusted_proxies = [ - "172.30.33.0/24" - "10.0.1.4" - "10.0.1.3" - "10.0.1.18" - "10.0.1.0/24" - ]; - }; - - recorder = { - db_url = "postgresql://@/hass"; - purge_keep_days = 180; - }; - - auth_header = { - debug = false; - username_header = "X-authentik-username"; - }; - - # https://www.home-assistant.io/integrations/ota_updater/ - zha.zigpy_config.ota.z2m_remote_index = "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json"; - - openhasp = { - plate = { - objects = [ - { - obj = "p0b1"; # temperature label on all pages - properties = { - "text" = ''{{ states("sensor.thermostat_current_temperature") }}°F''; - }; - } - { - obj = "p1b2"; # light-switch toggle button - properties = { - "val" = ''{{ 1 if states("light.living_room_lights") == "on" else 0 }}''; - "text" = ''{{ "\uE6E8" if is_state("light.living_room_lights", "on") else "\uE335" | e }}''; - }; - event = { - "up" = { - service = "homeassistant.toggle"; - entity_id = "light.living_room_lights"; - }; - }; - } - { - obj = "p1b3"; # dropdown - event = { - "changed" = { - service = "persistent_notification.create"; - data = { - message = "I like {{ text }}"; - }; - }; - }; - } - ]; - }; - }; - }; - }; - - # https://www.home-assistant.io/integrations/automation/ - # systemd.tmpfiles.rules = [ - # "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" - # ]; - # This bypasses the component validation and places it directly in HA's data directory system.activationScripts.installCustomComponents = '' chown -R hass:hass ${config.services.home-assistant.configDir} @@ -300,147 +28,11 @@ in } ]; }; - - # Enable and configure Mosquitto MQTT broker - mosquitto = { - enable = true; - listeners = [ - { - acl = [ "pattern readwrite #" ]; - omitPasswordAuth = true; - settings.allow_anonymous = true; - } - ]; - }; - - zigbee2mqtt = { - enable = true; - settings = { - homeassistant = { - enabled = config.services.home-assistant.enable; - # Optional: Home Assistant discovery topic (default: shown below) - # Note: should be different from [MQTT base topic](../mqtt.md) to prevent errors in HA software - discovery_topic = "homeassistant"; - # Optional: Home Assistant status topic (default: shown below) - status_topic = "homeassistant/status"; - # Optional: Experimental support for Home Assistant event entities, may break in the future (default: shown below) when enabled: - # - An `event` entity will be discovered for each 'action'. - # - The `event_type` attribute will contain the action itself, additional attributes like `button` will have further information. - experimental_event_entities = false; - # Optional: Home Assistant legacy action sensor (default: `false`), when enabled: - # - Zigbee2MQTT will send an empty 'action' after one has been send - # - A 'sensor_action' will be discovered - legacy_action_sensor = false; - }; - - permit_join = true; - # Web interface - frontend = { - port = zigbee2mqttPort; # Choose an available port - }; - # MQTT configuration - mqtt = { - base_topic = "zigbee2mqtt"; - server = "mqtt://localhost:1883"; - # If using authentication: - # user = "mqttuser"; - # password = "your-password"; - }; - serial = { - port = "/dev/ttyUSB0"; - }; - }; - }; - - music-assistant = { - enable = true; - providers = [ - # "airplay" # music-assistant: airplay support is missing libraop, a library we will not package because it depends on OpenSSL 1.1. - "apple_music" - "bluesound" - "builtin" - "chromecast" - "deezer" - "dlna" - "fanarttv" - "filesystem_local" - "filesystem_smb" - "fully_kiosk" - "hass" - "hass_players" - "jellyfin" - "musicbrainz" - "opensubsonic" - "player_group" - "plex" - "qobuz" - "radiobrowser" - "siriusxm" - "snapcast" - "sonos" - "sonos_s1" - "soundcloud" - "spotify" - "template_player_provider" - "test" - "theaudiodb" - "tidal" - "tunein" - "ytmusic" - ]; - }; - - # Enable AirPlay - pipewire = { - # opens UDP ports 6001-6002 - raopOpenFirewall = true; - - extraConfig.pipewire = { - "10-airplay" = { - "context.modules" = [ - { - name = "libpipewire-module-raop-discover"; - - # increase the buffer size if you get dropouts/glitches - # args = { - # "raop.latency.ms" = 500; - # }; - } - ]; - }; - }; - }; }; - systemd.services.music-assistant.serviceConfig = { - DynamicUser = lib.mkForce false; - StateDirectory = "music-assistant"; - }; - - # Enable required hardware support for the Zigbee adapter - hardware.bluetooth.enable = true; # Some adapters use Bluetooth - - # Ensure proper permissions for Zigbee USB devices - # services.udev.extraRules = '' - # # For CC2531, CC2530, CC1352P-2, CC2538 and similar adapters - # SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="zigbee", MODE="0666" - # SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666" - - # # For ConBee/RaspBee by Dresden Elektronik - # SUBSYSTEM=="tty", ATTRS{idVendor}=="1cf1", ATTRS{idProduct}=="0030", SYMLINK+="zigbee", MODE="0666" - - # # For Electrolama zig-a-zig-ah (zzh!) - # SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666" - # ''; - - environment.systemPackages = with pkgs; [ - mosquitto # MQTT command-line tools - usbutils # For lsusb to help identify your adapter - ]; - networking.firewall.allowedTCPPorts = [ - mosquittoPort - zigbee2mqttPort + cfg.mosquittoPort + cfg.zigbee2mqttPort 8095 8097 ]; diff --git a/modules/nixos/homeassistant/options.nix b/modules/nixos/homeassistant/options.nix index c69c4de..18c8ae1 100644 --- a/modules/nixos/homeassistant/options.nix +++ b/modules/nixos/homeassistant/options.nix @@ -1,7 +1,13 @@ { lib, namespace, ... }: with lib; +let + inherit (lib.${namespace}) mkOpt; +in { options.${namespace}.services.home-assistant = { enable = mkEnableOption "enable home-assistant"; + mosquittoPort = mkOpt types.int 1883 "Port for MQTT"; + zigbee2mqttPort = mkOpt types.int 8080 "Port for zigbee2mqtt web interface"; + zigbeeDevicePath = mkOpt types.str "/dev/ttyUSB0" "Path to zigbee usb device"; }; } diff --git a/modules/nixos/homeassistant/services/homeassistant/default.nix b/modules/nixos/homeassistant/services/homeassistant/default.nix new file mode 100644 index 0000000..513eb68 --- /dev/null +++ b/modules/nixos/homeassistant/services/homeassistant/default.nix @@ -0,0 +1,270 @@ +{ config, lib, pkgs, namespace, ... }: +with lib; +let + cfg = config.${namespace}.services.home-assistant; +in +{ + config = mkIf cfg.enable { + services.home-assistant = { + enable = true; + openFirewall = true; + configDir = "/var/lib/homeassistant"; + configWritable = true; # todo + extraComponents = [ + "adguard" + "apple_tv" + "analytics" + "backup" + "bluetooth" + "bluetooth_adapters" + "bluetooth_le_tracker" + "bluetooth_tracker" + "brother" + "caldav" + "calendar" + "cloudflare" + "co2signal" + "color_extractor" + "esphome" + "ffmpeg" + "google_translate" + "holiday" + "homekit" + "isal" + "jellyfin" + "met" + "music_assistant" + "mqtt" + "nut" + "nextcloud" + "nws" + "ollama" + "onedrive" + "open_router" + "ping" + "radio_browser" + "samsungtv" + "season" + "shopping_list" + "simplefin" + "smartthings" + "subaru" + "upnp" + "vesync" + "workday" + "wyoming" + "zha" + ]; + + customComponents = with pkgs.home-assistant-custom-components; [ + # nixpkgs + auth-header + localtuya + + # /packages + pkgs.${namespace}.ha-anycubic + pkgs.${namespace}.ha-bambulab + pkgs.${namespace}.ha-gehome + pkgs.${namespace}.ha-icloud3 + pkgs.${namespace}.ha-mail-and-packages + pkgs.${namespace}.ha-nanokvm + pkgs.${namespace}.ha-openhasp + pkgs.${namespace}.ha-overseerr + pkgs.${namespace}.ha-petlibro + pkgs.${namespace}.ha-wyzeapi + ]; + + customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [ + atomic-calendar-revive + bubble-card + button-card + hourly-weather + mini-graph-card + mini-media-player + multiple-entity-row + mushroom + vacuum-card + weather-chart-card + zigbee2mqtt-networkmap + ]; + # use postgresql instead of sqlite + extraPackages = + ps: with ps; [ + # Core functionality + aiohttp + aiodns + paho-mqtt + pillow + pytz + pyyaml + sqlalchemy + + # Discovery & networking + zeroconf + netdisco + ifaddr + ssdp + + # Device protocols + pyserial # Serial communications + bluepy # Bluetooth LE + + # Smart home ecosystems + mutagen # Media file metadata + pysonos # Sonos + pywemo # Belkin WeMo + python-miio # Xiaomi devices + python-kasa # TP-Link + + # Sensors & monitoring + meteocalc # Weather calculations + speedtest-cli # Internet speed + + # Visualization & UI + matplotlib # Graphing + + # Security + bcrypt + cryptography + pyjwt + + # Media + ha-ffmpeg # Camera streams + + # Specialized integrations + python-matter-server # Matter protocol + + # System integrations + psutil # System monitoring + + psycopg2 + numpy + hassil + pyturbojpeg + paho-mqtt + pychromecast + pyatv + python-otbr-api + brother + pyipp + govee-ble + adguardhome + nextcord + aiogithubapi + jellyfin-apiclient-python + pylitterbot + dateparser + aionut + nextcloudmonitor + ollama + pynecil + aiopyarr + pysabnzbd + getmac + zigpy + bellows # For Zigbee EmberZNet-based adapters + zigpy-xbee # For XBee adapters + zigpy-deconz # For ConBee/RaspBee adapters + pyicloud # iCloud + pyatv # Apple TV + opencv-python + face-recognition + ibeacon-ble + gehomesdk + onedrive-personal-sdk + python-roborock + pkgs.${namespace}.python-steam + apple-weatherkit + + samsungctl + samsungtvws + + aiohomekit + + icmplib + aioelectricitymaps + wyoming + pysmartthings + wakeonlan + ephem + ]; + + config = { + # Includes dependencies for a basic setup + # https://www.home-assistant.io/integrations/default_config/ + default_config = { }; + + cloud = false; + + frontend = { + themes = "!include_dir_merge_named themes"; + }; + + "automation ui" = "!include automations.yaml"; + "scene ui" = "!include scenes.yaml"; + "script ui" = "!include scripts.yaml"; + + http = { + use_x_forwarded_for = true; + trusted_proxies = [ + "172.30.33.0/24" + "10.0.1.4" + "10.0.1.3" + "10.0.1.18" + "10.0.1.0/24" + ]; + }; + + recorder = { + db_url = "postgresql://@/hass"; + purge_keep_days = 180; + }; + + auth_header = { + debug = false; + username_header = "X-authentik-username"; + }; + + # https://www.home-assistant.io/integrations/ota_updater/ + zha.zigpy_config.ota.z2m_remote_index = "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json"; + + openhasp = { + plate = { + objects = [ + { + obj = "p0b1"; # temperature label on all pages + properties = { + "text" = ''{{ states("sensor.thermostat_current_temperature") }}°F''; + }; + } + { + obj = "p1b2"; # light-switch toggle button + properties = { + "val" = ''{{ 1 if states("light.living_room_lights") == "on" else 0 }}''; + "text" = ''{{ "\uE6E8" if is_state("light.living_room_lights", "on") else "\uE335" | e }}''; + }; + event = { + "up" = { + service = "homeassistant.toggle"; + entity_id = "light.living_room_lights"; + }; + }; + } + { + obj = "p1b3"; # dropdown + event = { + "changed" = { + service = "persistent_notification.create"; + data = { + message = "I like {{ text }}"; + }; + }; + }; + } + ]; + }; + }; + }; + }; + }; +} \ No newline at end of file diff --git a/modules/nixos/homeassistant/services/music-assistant/default.nix b/modules/nixos/homeassistant/services/music-assistant/default.nix new file mode 100644 index 0000000..1b08e7b --- /dev/null +++ b/modules/nixos/homeassistant/services/music-assistant/default.nix @@ -0,0 +1,68 @@ +{ config, lib, namespace, ... }: +with lib; +let + cfg = config.${namespace}.services.home-assistant; +in +{ + config = mkIf cfg.enable { + services = { + music-assistant = { + enable = true; + providers = [ + # "airplay" # music-assistant: airplay support is missing libraop, a library we will not package because it depends on OpenSSL 1.1. + "apple_music" + "bluesound" + "builtin" + "chromecast" + "deezer" + "dlna" + "fanarttv" + "filesystem_local" + "filesystem_smb" + "fully_kiosk" + "hass" + "hass_players" + "jellyfin" + "musicbrainz" + "opensubsonic" + "player_group" + "plex" + "qobuz" + "radiobrowser" + "siriusxm" + "snapcast" + "sonos" + "sonos_s1" + "soundcloud" + "spotify" + "template_player_provider" + "test" + "theaudiodb" + "tidal" + "tunein" + "ytmusic" + ]; + }; + + # Enable AirPlay + pipewire = { + raopOpenFirewall = true; + + extraConfig.pipewire = { + "10-airplay" = { + "context.modules" = [ + { + name = "libpipewire-module-raop-discover"; + } + ]; + }; + }; + }; + }; + + systemd.services.music-assistant.serviceConfig = { + DynamicUser = lib.mkForce false; + StateDirectory = "music-assistant"; + }; + }; +} \ No newline at end of file diff --git a/modules/nixos/homeassistant/services/zigbee2mqtt/default.nix b/modules/nixos/homeassistant/services/zigbee2mqtt/default.nix new file mode 100644 index 0000000..298a251 --- /dev/null +++ b/modules/nixos/homeassistant/services/zigbee2mqtt/default.nix @@ -0,0 +1,61 @@ +{ config, lib, namespace, ... }: +with lib; +let + cfg = config.${namespace}.services.home-assistant; +in +{ + config = mkIf cfg.enable { + services = { + # Enable and configure Mosquitto MQTT broker + mosquitto = { + enable = true; + listeners = [ + { + acl = [ "pattern readwrite #" ]; + omitPasswordAuth = true; + settings.allow_anonymous = true; + } + ]; + }; + + zigbee2mqtt = { + enable = true; + settings = { + homeassistant = { + enabled = config.services.home-assistant.enable; + # Optional: Home Assistant discovery topic (default: shown below) + # Note: should be different from [MQTT base topic](../mqtt.md) to prevent errors in HA software + discovery_topic = "homeassistant"; + # Optional: Home Assistant status topic (default: shown below) + status_topic = "homeassistant/status"; + # Optional: Experimental support for Home Assistant event entities, may break in the future (default: shown below) when enabled: + # - An `event` entity will be discovered for each 'action'. + # - The `event_type` attribute will contain the action itself, additional attributes like `button` will have further information. + experimental_event_entities = false; + # Optional: Home Assistant legacy action sensor (default: `false`), when enabled: + # - Zigbee2MQTT will send an empty 'action' after one has been send + # - A 'sensor_action' will be discovered + legacy_action_sensor = false; + }; + + permit_join = true; + # Web interface + frontend = { + port = cfg.zigbee2mqttPort; + }; + # MQTT configuration + mqtt = { + base_topic = "zigbee2mqtt"; + server = "mqtt://localhost:${toString cfg.mosquittoPort}"; + # If using authentication: + # user = "mqttuser"; + # password = "your-password"; + }; + serial = { + port = cfg.zigbeeDevicePath; + }; + }; + }; + }; + }; +} \ No newline at end of file diff --git a/systems/x86_64-linux/nuc/default.nix b/systems/x86_64-linux/nuc/default.nix index b7b31e2..80ab821 100644 --- a/systems/x86_64-linux/nuc/default.nix +++ b/systems/x86_64-linux/nuc/default.nix @@ -29,6 +29,7 @@ address = "10.0.1.4/24"; gateway = "10.0.1.1"; dns = "10.0.1.1"; + interface = "wlo1"; }; wifi = { enable = true;