{ depot, lib, pkgs, config, ... }: let inherit (depot.ops) secrets; in { services.zigbee2mqtt = { enable = true; package = depot.nix.pkgs.zigbee2mqtt; settings = { homeassistant = true; serial.port = "/dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_eca6e9ba6596ed11ac206b4ce259fb3e-if00-port0"; mqtt = { server = "mqtt://localhost:1883"; user = "zigbee2mqtt"; password = "zigbee2mqtt"; }; frontend = { port = 8099; host = config.my.ip.tailscale6; }; }; }; services.mosquitto = let localhostUsers = { zigbee2mqtt = { password = "zigbee2mqtt"; acl = [ "readwrite zigbee2mqtt/#" "readwrite homeassistant/#" ]; }; matrix2mqtt = { password = "matrix2mqtt"; acl = [ "readwrite matrix2mqtt/#" "readwrite homeassistant/#" ]; }; homeassistant = { password = "homeassistant"; acl = [ "readwrite matrix2mqtt/#" "readwrite zigbee2mqtt/#" "readwrite homeassistant/#" ]; }; }; in { enable = true; listeners = [{ address = "127.0.0.1"; port = 1883; users = localhostUsers; } { address = "::1"; port = 1883; users = localhostUsers; }]; }; services.home-assistant = { enable = true; configWritable = true; lovelaceConfigWritable = true; config = { homeassistant = { name = "117 Malden Road"; time_zone = "Europe/London"; external_url = "https://ha.lukegb.com"; internal_url = "https://ha.lukegb.com"; }; notify = [{ name = "pushover-luke"; platform = "pushover"; }]; http = { use_x_forwarded_for = true; trusted_proxies = [ "::1" "127.0.0.1" ]; }; lifx.light = {}; light = [{ platform = "group"; name = "Bedroom Lights"; entities = map (x: "light.overhead_${x.side}_${x.n}") (lib.cartesianProduct { side = [ "left" "right" ]; n = [ "1" "2" "3" "4" ]; }); }]; cast = {}; plex = {}; default_config = {}; broadlink = {}; homekit = {}; mqtt = {}; smartthings = {}; google_assistant = { project_id = "malden-homeassistant"; service_account = secrets.homeAssistant.googleServiceAccount; report_state = true; exposed_domains = [ "light" ]; }; scene = let bedroomOverhead = x: ({ color_mode = "color_temp"; brightness = 255; color_temp = 316; } // x); entityDefs = ring: overhead: let o = bedroomOverhead { state = overhead; }; in { "light.overhead_left_1" = o; "light.overhead_left_2" = o; "light.overhead_left_3" = o; "light.overhead_left_4" = o; "light.overhead_right_1" = o; "light.overhead_right_2" = o; "light.overhead_right_3" = o; "light.overhead_right_4" = o; }; in [{ name = "Bedroom Reset"; entities = entityDefs "off" "on"; } { name = "Bedroom Off"; entities = entityDefs "off" "off"; }]; automation = let base = extra: alias: webhook_id: ({ inherit alias; trigger = [{ inherit webhook_id; platform = "webhook"; }]; } // extra); toggleEntity = entity_id: base { action = [{ service = "homeassistant.toggle"; target.entity_id = entity_id; }]; }; playPauseEntity = entity_id: base { action = [{ service = "media_player.media_play_pause"; target.entity_id = entity_id; }]; }; scene = scene_entity_id: base { action = [{ service = "scene.turn_on"; target.entity_id = scene_entity_id; data.transition = 1.0; }]; }; in [ (toggleEntity "light.bedroom_lights" "Desk LHS Switch press - toggle room" "flic_desk_lhs") (scene "scene.bedroom_reset" "Desk LHS Switch hold - reset room" "flic_desk_lhs_hold") (toggleEntity "light.bedside_lamp" "Desk RHS Switch press - toggle bedside" "flic_desk_rhs") (toggleEntity "light.bedroom_lights" "Bed LHS Switch press - toggle room" "flic_bed_lhs") (scene "scene.bedroom_reset" "Bed LHS Switch dblpress - reset room" "flic_bed_lhs_dbl") (scene "scene.bedroom_off" "Bed LHS Switch dblpress - reset room" "flic_bed_lhs_hold") (playPauseEntity "media_player.nebula" "Bed RHS Switch press - play/pause nebula" "flic_bed_rhs") (toggleEntity "light.bedroom_lights" "Bedroom Door Switch press - toggle room" "flic_bedroom_door") (scene "scene.bedroom_off" "Bedroom Door Switch dblpress - room off" "flic_bedroom_door_dbl") (scene "scene.bedroom_off" "Bedroom Door Switch hold - room off" "flic_bedroom_door_hold") ]; }; lovelaceConfig = { title = "117 Malden Road"; views = [{ title = "Luke's Bedroom"; badges = let scene = scene: cfg: lib.mkMerge [{ type = "entity"; show_name = true; show_state = false; show_icon = true; entity = "scene.${scene}"; tap_action.action = "toggle"; } cfg]; in [(scene "bedroom_off" { icon = "mdi:ceiling-light-outline"; }) (scene "bedroom_reset" { icon = "mdi:ceiling-light-multiple"; })]; cards = [{ type = "grid"; square = false; columns = 1; cards = [{ type = "light"; entity = "light.bedroom_lights"; } { type = "entities"; entities = [{ name = "Mosquito Repellent"; entity = "switch.lukes_bedroom_mosquitto_repellent"; }]; }]; } { type = "grid"; square = false; columns = 1; cards = [{ type = "media-control"; entity = "media_player.nebula_3"; } { type = "media-control"; entity = "media_player.shield_2"; }]; } { type = "grid"; square = false; columns = 1; cards = [{ title = "Projector"; type = "entities"; entities = [{ name = "source"; entity = "select.hdmi_matrix_hdmi_1_projector"; } { name = "Power (CEC)"; entity = "switch.hdmi_matrix_hdmi_1_projector_cec_power"; icon = "mdi:power"; }]; } { title = "Sound Bar"; type = "entities"; entities = [{ name = "Source"; entity = "select.hdmi_matrix_hdmi_2_sound_bar"; } { name = "Power (Samsung SmartThings)"; entity = "switch.samsung_soundbar_q930b"; icon = "mdi:power"; } { name = "Power (CEC)"; entity = "switch.hdmi_matrix_hdmi_2_sound_bar_cec_power"; icon = "mdi:power"; }]; } { title = "Side Monitor"; type = "entities"; entities = [{ name = "Source"; entity = "select.hdmi_matrix_hdmi_3_desk_monitor"; } { name = "Power"; entity = "switch.hdmi_matrix_hdmi_3_desk_monitor_cec_power"; icon = "mdi:power"; }]; }]; }]; }]; }; }; services.nginx.virtualHosts."ha.lukegb.com" = { forceSSL = true; locations."/" = { proxyPass = "http://localhost:8123/"; proxyWebsockets = true; }; }; my.vault.acmeCertificates."ha.lukegb.com" = { hostnames = [ "ha.lukegb.com" ]; nginxVirtualHosts = [ "ha.lukegb.com" ]; }; services.node-red = { enable = true; withNpmAndGcc = true; port = 1880; }; systemd.services.matrix2mqtt = { wantedBy = [ "multi-user.target" ]; unitConfig = { StartLimitIntervalSec = "0"; }; serviceConfig = { ExecStart = "${depot.rust.matrix2mqtt}/bin/matrix2mqtt"; User = "matrix2mqtt"; PrivateTmp = true; PrivateDevices = true; RestrictNamespaces = true; RestrictRealtime = true; ProtectKernelLogs = true; ProtectControlGroups = true; ProtectHostname = true; ProtectHome = true; ProtectProc = "invisible"; ProcSubset = "pid"; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectClock = true; CapabilityBoundingSet = ""; LockPersonality = true; PrivateUsers = true; RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; DynamicUser = true; Restart = "always"; RestartSec = "100ms"; RestartSteps = 10; RestartMaxDelaySec = "1min"; }; }; }