Files
nix-config/modules/nixos/homeassistant/default.nix
2025-08-21 20:54:43 -05:00

444 lines
12 KiB
Nix
Executable File

{
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}
chmod -R 750 ${config.services.home-assistant.configDir}
'';
services = {
postgresql = {
enable = true;
ensureDatabases = [ "hass" ];
ensureUsers = [
{
name = "hass";
ensureDBOwnership = true;
}
];
};
# 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;
# };
}
];
};
};
};
};
# 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
8095
8097
];
};
}