nixos-configuration/hosts/iron/services/home-assistant.nix
2025-04-16 22:54:28 +02:00

281 lines
8.3 KiB
Nix

args@{ lib, pkgs, config, custom-utils, ... }:
let
ports = import ../ports.nix args;
interfaces = import ../interfaces.nix;
domain = "hass.jalr.de";
in
{
sops.secrets = {
home-assistant = {
sopsFile = ../secrets.yaml;
owner = "root";
group = "hass";
mode = "0640";
};
"mqtt-users/home-assistant" = {
sopsFile = ../secrets.yaml;
};
"mqtt-users/valetudo" = {
sopsFile = ../secrets.yaml;
};
};
networking.firewall.interfaces = {
"${interfaces.lan}".allowedTCPPorts = [ ports.mqtt.tcp ];
iot.allowedTCPPorts = [ ports.mqtt.tcp ];
};
services = {
home-assistant = {
enable = true;
lovelaceConfig = {
title = "Home";
views = [
{
path = "default_view";
title = "Home";
cards = [
{
title = "Eingang";
type = "entities";
entities = [
{
entity = "light.eingang_deckenleuchte_deckenleuchte";
name = "Deckenleuchte";
}
];
}
{
name = "Esstisch";
type = "entities";
entities = [
{
entity = "light.yeelight_meteorite_ambient_light";
name = "Ambient light";
}
{
entity = "light.yeelight_meteorite_ceiling_light";
name = "Ceiling light";
}
{
entity = "light.yeelight_meteorite_night_light";
name = "Night light";
}
];
}
];
}
];
};
extraComponents = [
# See https://www.home-assistant.io/integrations
"bthome"
"caldav"
"esphome"
"local_todo"
"openweathermap"
"wyoming"
"xiaomi_ble"
"vlc_telnet"
];
customComponents = with pkgs.home-assistant-custom-components; [
adaptive_lighting
];
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
valetudo-map-card
];
lovelaceConfigWritable = false;
configWritable = false;
config = {
http = {
server_host = [ "127.0.0.1" ];
server_port = ports.home-assistant.tcp;
use_x_forwarded_for = true;
trusted_proxies = [ "127.0.0.1" ];
};
homeassistant = {
unit_system = "metric";
time_zone = "Europe/Berlin";
temperature_unit = "C";
inherit (config.location) longitude;
inherit (config.location) latitude;
external_url = "https://${domain}/";
internal_url = "https://${domain}/";
};
default_config = { };
adaptive_lighting = {
lights = [
"light.yeelight_meteorite_ceiling_light"
"light.eingang_deckenleuchte_deckenleuchte"
"light.led_panel_schreibtisch_panel"
"light.kueche_leiste_led_light"
"light.badspiegel_background_light"
"light.badspiegel_front_light"
];
};
"automation nix" = [
{
alias = "Waschmaschine fertig Benachrichtigung";
trigger = {
platform = "state";
entity_id = "sensor.waschmaschine_aktueller_vorgang";
to = "Knitterschutz/Ende";
};
action = [
{
service = "notify.mobile_app_shift6mq";
data = {
message = "Die Waschmaschine hat das Programm beendet.";
title = "Wäsche fertig";
};
}
];
}
];
"automation ui" = "!include automations.yaml";
"scene nix" = [
];
"scene ui" = "!include scenes.yaml";
bluetooth = { };
device_tracker = [
{
platform = "bluetooth_le_tracker";
}
];
"script nix" = [
{
lights_off_except = {
icon = "mdi:home-lightbulb";
fields.exclude_lights.description = "Excluded lights as list";
sequence = [
{
service = "logbook.log";
data_template = {
entity_id = "script.turn_off_lights";
name = "Exclude log";
message = "Turning of all lights except: {{ exclude_lights }}";
};
}
{
service = "light.turn_off";
data_template.entity_id = ''
{{ states.light | rejectattr('entity_id', 'in', exclude_lights) | rejectattr('state', 'in', 'off') | join(',', attribute='entity_id') }}
'';
}
];
};
}
];
"script ui" = "!include scripts.yaml";
calendar = [
{
platform = "caldav";
username = "jalr@jalr.de";
password = "!secret radicale";
url = "https://cal.jalr.de/radicale";
}
];
mqtt = { };
media_player = [
{
platform = "mpd";
name = "mpd@iron";
host = "127.0.0.1";
}
];
};
};
mosquitto = {
enable = true;
persistence = true;
listeners = [
{
port = ports.mqtt.tcp;
users = {
valetudo = {
passwordFile = config.sops.secrets."mqtt-users/valetudo".path;
acl = [
"readwrite homeassistant/+/donald/#"
"readwrite valetudo/donald/#"
];
};
home-assistant = {
passwordFile = config.sops.secrets."mqtt-users/home-assistant".path;
acl = [ "readwrite #" ];
};
};
}
];
};
};
systemd.services = {
home-assistant.serviceConfig.ExecStartPre = [
(
pkgs.writeShellScript "home-assistant-secrets" ''
ln -sf "${config.sops.secrets.home-assistant.path}" "${config.services.home-assistant.configDir}/secrets.yaml"
''
)
];
hass-vlc = {
script = ''
exec ${pkgs.vlc}/bin/cvlc \
--no-video \
-I telnet \
--telnet-password=vlc \
--sout='#transcode{acodec=s16le,channels=2,samplerate=48000}:std{access=file,mux=raw,dst=/run/snapserver/hass.fifo}' \
--aout=none
'';
wants = [ "snapserver.service" ];
after = [ "snapserver.service" ];
serviceConfig = {
BindPaths = [ "/run/snapserver/hass.fifo" ];
BindReadOnlyPaths = [ "/nix/store" "/etc/ssl/certs" "/etc/static/ssl/certs" ];
CapabilityBoundingSet = "";
DynamicUser = "true";
Group = "snapserver";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = lib.mkForce true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "noaccess";
ProtectSystem = "strict";
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RootDirectory = "/run/hass-vlc";
RuntimeDirectory = "hass-vlc";
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" ];
};
wantedBy = [ "multi-user.target" ];
};
};
systemd.tmpfiles.rules = [
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
"f ${config.services.home-assistant.configDir}/scenes.yaml 0755 hass hass"
];
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
kTLS = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString ports.home-assistant.tcp}/";
recommendedProxySettings = true;
proxyWebsockets = true;
};
};
}