From 027be96f9c3d64c70edacc72ddb507882d976451 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sat, 9 Dec 2023 22:55:41 +0100 Subject: [PATCH] add home-assistant nix configuration --- hosts/fw.cloonar.com/configuration.nix | 2 +- hosts/fw.cloonar.com/modules/dhcp4.nix | 2 +- hosts/fw.cloonar.com/modules/firewall.nix | 6 - .../fw.cloonar.com/modules/home-assistant.nix | 47 --- .../modules/home-assistant/ac.nix | 103 ++++++ .../modules/home-assistant/battery.nix | 91 +++++ .../modules/home-assistant/default.nix | 183 ++++++++++ .../modules/home-assistant/enocean.nix | 12 + .../modules/home-assistant/ldap.nix | 59 +++ .../modules/home-assistant/light.nix | 335 ++++++++++++++++++ .../modules/home-assistant/locks.nix | 117 ++++++ .../modules/home-assistant/multimedia.nix | 270 ++++++++++++++ .../modules/home-assistant/notify.nix | 15 + .../modules/home-assistant/pc.nix | 46 +++ .../modules/home-assistant/presence.nix | 23 ++ .../modules/home-assistant/pushover.nix | 16 + .../modules/home-assistant/roborock.nix | 28 ++ .../modules/home-assistant/scene-switch.nix | 21 ++ .../modules/home-assistant/sleep.nix | 59 +++ .../modules/home-assistant/snapcast.nix | 66 ++++ hosts/fw.cloonar.com/modules/unbound.nix | 1 - hosts/fw.cloonar.com/secrets.yaml | 8 +- 22 files changed, 1450 insertions(+), 60 deletions(-) delete mode 100644 hosts/fw.cloonar.com/modules/home-assistant.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/ac.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/battery.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/default.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/enocean.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/ldap.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/light.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/locks.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/multimedia.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/notify.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/pc.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/presence.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/pushover.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/roborock.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/scene-switch.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/sleep.nix create mode 100644 hosts/fw.cloonar.com/modules/home-assistant/snapcast.nix diff --git a/hosts/fw.cloonar.com/configuration.nix b/hosts/fw.cloonar.com/configuration.nix index 736fcb3..339fedf 100644 --- a/hosts/fw.cloonar.com/configuration.nix +++ b/hosts/fw.cloonar.com/configuration.nix @@ -31,7 +31,7 @@ # ./modules/podman.nix # home assistant - ./modules/home-assistant.nix + ./modules/home-assistant # ./modules/mopidy.nix # ./modules/mosquitto.nix # ./modules/snapserver.nix diff --git a/hosts/fw.cloonar.com/modules/dhcp4.nix b/hosts/fw.cloonar.com/modules/dhcp4.nix index c737aac..a3947bf 100644 --- a/hosts/fw.cloonar.com/modules/dhcp4.nix +++ b/hosts/fw.cloonar.com/modules/dhcp4.nix @@ -99,7 +99,7 @@ server-hostname = "git.cloonar.com"; } { - hw-address = "1a:c4:04:6e:29:01"; + hw-address = "c2:4f:64:dd:13:0c"; ip-address = "10.42.97.20"; server-hostname = "home-assistant.cloonar.com"; } diff --git a/hosts/fw.cloonar.com/modules/firewall.nix b/hosts/fw.cloonar.com/modules/firewall.nix index faebaa3..d83d238 100644 --- a/hosts/fw.cloonar.com/modules/firewall.nix +++ b/hosts/fw.cloonar.com/modules/firewall.nix @@ -143,12 +143,6 @@ "multimedia" } udp dport { 67, 68 } counter accept - # Allow networks to access web proxy - iifname { - "lan", - "wg_cloonar", - } tcp dport { 80, 443 } counter accept - # Accept mDNS for avahi reflection # iifname "multimedia" ip saddr tcp dport { llmnr } counter accept # iifname "multimedia" ip saddr udp dport { mdns, llmnr } counter accept diff --git a/hosts/fw.cloonar.com/modules/home-assistant.nix b/hosts/fw.cloonar.com/modules/home-assistant.nix deleted file mode 100644 index 02bdeb9..0000000 --- a/hosts/fw.cloonar.com/modules/home-assistant.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ ... }: { - users.users.homeassistant = { - isSystemUser = true; - group = "homeassistant"; - home = "/var/lib/homeassistant"; - createHome = true; - }; - users.groups.homeassistant = { }; - - # TODO: check if we can run docker service as other user than root - virtualisation = { - oci-containers.containers = { - homeassistant = { - autoStart = true; - image = "ghcr.io/home-assistant/home-assistant:2023.9.3"; - volumes = [ - "/var/lib/homeassistant:/config" - ]; - environment.TZ = "Europe/Vienna"; - extraOptions = [ - "--network=server" - "--mac-address=1a:c4:04:6e:29:01" - "--device=/dev/serial/by-id/usb-EnOcean_GmbH_EnOcean_USB_300_DC_FT5OI9YG-if00-port0:/dev/serial/by-id/usb-EnOcean_GmbH_EnOcean_USB_300_DC_FT5OI9YG-if00-port0" - ]; - }; - }; - }; - - services.nginx.virtualHosts."home-assistant.cloonar.com" = { - forceSSL = true; - enableACME = true; - acmeRoot = null; - extraConfig = '' - proxy_buffering off; - ''; - locations."/".extraConfig = '' - proxy_pass http://10.42.97.20:8123; - proxy_set_header Host $host; - proxy_redirect http:// https://; - proxy_http_version 1.1; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - ''; - }; -} - diff --git a/hosts/fw.cloonar.com/modules/home-assistant/ac.nix b/hosts/fw.cloonar.com/modules/home-assistant/ac.nix new file mode 100644 index 0000000..bfc909f --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/ac.nix @@ -0,0 +1,103 @@ +{ + services.home-assistant.extraComponents = [ + "daikin" + ]; + + services.home-assistant.config = { + sensor = [ + { + name = "Living Room Window Handle"; + platform = "enocean"; + id = [ 129 0 227 53 ]; + device_class = "windowhandle"; + } + ]; + "automation ac_livingroom" = { + alias = "ac_livingroom"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "sensor.windowhandle_living_room_window_handle"; + to = [ "open" "tilt" ]; + }; + action = { + service = "climate.set_hvac_mode"; + target = { + entity_id = "climate.livingroom_ac"; + }; + data = { + hvac_mode = "off"; + }; + }; + }; + "automation ac_eco" = { + alias = "ac_eco"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = [ + "climate.livingroom_ac" + "climate.bedroom_ac" + ]; + to = [ + "heat" + "cold" + ]; + }; + action = { + service = "climate.set_preset_mode"; + target = { + entity_id = "{{ trigger.entity_id }}"; + }; + data = { + preset_mode = "eco"; + }; + }; + }; + "automation bedroom_ac_on" = { + alias = "bedroom ac on"; + hide_entity = true; + trigger = { + platform = "time"; + at = "00:30:00"; + }; + action = { + choose = [ + { + conditions = [ "{{ states('sensor.bedroom_ac_inside_temperature') > 25 and states('sensor.bedroom_ac_outside_temperature') > 22 }}" ]; + sequence = [ + { + service = "climate.set_hvac_mode"; + target = { + entity_id = "climate.bedroom_ac"; + }; + data = { + hvac_mode = "cold"; + }; + } + ]; + } + ]; + }; + }; + "automation bedroom_ac_off" = { + alias = "bedroom ac on"; + hide_entity = true; + trigger = { + platform = "template"; + value_template = '' + {{ now().timestamp() | timestamp_custom('%H:%M') == (as_timestamp(strptime(states('sensor.bedtime_alarm'), "%H:%M")) - 1800) | timestamp_custom('%H:%M', false) }} + ''; + }; + action = { + service = "climate.set_hvac_mode"; + target = { + entity_id = "climate.bedroom_ac"; + }; + data = { + hvac_mode = "off"; + }; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/battery.nix b/hosts/fw.cloonar.com/modules/home-assistant/battery.nix new file mode 100644 index 0000000..35eff34 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/battery.nix @@ -0,0 +1,91 @@ +{ + services.home-assistant.config = { + sensor = [ + { + platform = "template"; + sensors = { + sensors_lowest_battery_level = { + friendly_name = "Lowest battery level (Sensors)"; + entity_id = "sun.sun"; + device_class = "battery"; + unit_of_measurement = "%"; + value_template = '' + {% set domains = ['sensor', 'battery'] %} + {% set ns = namespace(min_batt=100, entities=[]) %} + {%- set exclude_sensors = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level'] -%} + {% for domain in domains %} + {% set ns.entities = states[domain] %} + {% for sensor in exclude_sensors %} + {% set ns.entities = ns.entities | rejectattr('entity_id', 'equalto', sensor) %} + {% endfor %} + {% set batt_sensors = ns.entities | selectattr('attributes.device_class','equalto','battery') | map(attribute='state') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %} + {% set batt_attrs = ns.entities | selectattr('attributes.battery_level','defined') | map(attribute='attributes.battery_level') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %} + {% set batt_lvls = batt_sensors + batt_attrs %} + {% if batt_lvls|length > 0 %} + {% set _min = batt_lvls|min %} + {% if _min < ns.min_batt %} + {% set ns.min_batt = _min %} + {% endif %} + {% endif %} + {% endfor %} + {{ ns.min_batt }} + ''; + }; + }; + } + ]; + binary_sensor = [ + { + platform = "template"; + sensors = { + sensor_low_battery = { + value_template = "{{ states('sensor.sensors_lowest_battery_level')|int <= 30 }}"; + friendly_name = "A sensor has low battery"; + device_class = "problem"; + }; + }; + } + ]; + alert = { + sensor_low_battery = { + name = "Sensor has low battery!"; + message = '' + {%- set domains = ['sensor', 'battery'] -%} + {%- set threshold = 30 -%} + {%- set exclude_entities = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level'] -%} + Sensors are below 50% battery: + {%- for domain in domains -%} + {%- for item in states[domain] -%} + {%- if item.entity_id not in exclude_entities -%} + {%- if item.attributes.battery_level is defined -%} + {%- set level = item.attributes.battery_level|int -%} + {% if level > 0 and level < threshold %} + - {{ item.attributes.friendly_name }} ({{ item.attributes['battery_level']|int}}%) + {%- endif -%} + {%- endif -%} + {%- if item.attributes.device_class is defined and item.attributes.device_class == 'battery' -%} + {%- set level = item.state|int -%} + {% if level > 0 and level <= threshold %} + - {{ item.attributes.friendly_name }} ({{ item.state|int }}%) + {%- endif -%} + {%- endif %} + {%- endif -%} + {%- endfor -%} + {%- endfor -%} + ''; + entity_id = "binary_sensor.sensor_low_battery"; + state = "on"; + repeat = [ + 5 + 60 + 360 + ]; + skip_first = true; + can_acknowledge = true; + notifiers = [ + "NotificationGroup" + ]; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/default.nix b/hosts/fw.cloonar.com/modules/home-assistant/default.nix new file mode 100644 index 0000000..b1d48ab --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/default.nix @@ -0,0 +1,183 @@ +{ config, pkgs, ... }: +let + domain = "home-assistant.cloonar.com"; +in +{ + users.users.hass = { + home = "/var/lib/hass"; + createHome = true; + group = "hass"; + uid = config.ids.uids.hass; + }; + users.groups.hass.gid = config.ids.gids.hass; + + security.acme.certs."${domain}" = { + group = "nginx"; + }; + + sops.secrets."home-assistant-secrets.yaml" = { + owner = "hass"; + restartUnits = [ "container@hass.service" ]; + }; + + sops.secrets."home-assistant-ldap" = { + owner = "hass"; + }; + + containers.hass = { + autoStart = true; + ephemeral = true; # because of ssh key + macvlans = [ "vserver" ]; + bindMounts = { + "/var/lib/hass" = { + hostPath = "/var/lib/hass/"; + isReadOnly = false; + }; + "/var/lib/acme/hass/" = { + hostPath = "${config.security.acme.certs.${domain}.directory}"; + isReadOnly = true; + }; + "/run/secrets/home-assistant-ldap" = { + hostPath = config.sops.secrets."home-assistant-ldap".path; + isReadOnly = true; + }; + "/var/lib/hass/secrets.yaml" = { + hostPath = config.sops.secrets."home-assistant-secrets.yaml".path; + isReadOnly = true; + }; + }; + config = { lib, config, pkgs, ... }: { + imports = [ + ./ac.nix + # ./aeg.nix + ./battery.nix + ./enocean.nix + ./ldap.nix + ./light.nix + ./locks.nix + ./multimedia.nix + ./notify.nix + ./pc.nix + ./pushover.nix + ./roborock.nix + ./scene-switch.nix + ./sleep.nix + ./snapcast.nix + ]; + + networking = { + hostName = "home-assistant"; + nameservers = [ "10.42.97.10" ]; + interfaces.mv-vserver = { + useDHCP = true; + }; + firewall = { + enable = true; + allowedTCPPorts = [ 80 443 ]; + allowedUDPPorts = [ 5683 ]; + }; + }; + + services.nginx.enable = true; + services.nginx.virtualHosts."${domain}" = { + sslCertificate = "/var/lib/acme/hass/fullchain.pem"; + sslCertificateKey = "/var/lib/acme/hass/key.pem"; + sslTrustedCertificate = "/var/lib/acme/hass/chain.pem"; + forceSSL = true; + extraConfig = '' + proxy_buffering off; + ''; + locations."/".extraConfig = '' + proxy_pass http://127.0.0.1:8123; + proxy_set_header Host $host; + proxy_redirect http:// https://; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + ''; + }; + + services.home-assistant = { + enable = true; + }; + + services.home-assistant.extraComponents = [ + "mobile_app" + "backup" + "denonavr" + "androidtv" + "rainbird" + ]; + + services.home-assistant.config = + let + hiddenEntities = [ + "sensor.last_boot" + "sensor.date" + ]; + in + { + homeassistant = { + name = "Home"; + latitude = "!secret home_latitude"; + longitude = "!secret home_longitude"; + elevation = "!secret home_elevation"; + unit_system = "metric"; + currency = "EUR"; + country = "AT"; + time_zone = "Europe/Vienna"; + external_url = "https://${domain}"; + }; + automation = "!include automations.yaml"; + frontend = { }; + http = { + use_x_forwarded_for = true; + trusted_proxies = [ + "127.0.0.1" + "::1" + ]; + }; + history.exclude = { + entities = hiddenEntities; + domains = [ + "automation" + "updater" + ]; + }; + "map" = { }; + enocean = { + device = "/dev/serial/by-id/usb-EnOcean_GmbH_EnOcean_USB_300_DC_FT5OI9YG-if00-port0"; + }; + # logbook.exclude.entities = "hiddenEntities"; + logger = { + default = "info"; + }; + + #icloud = { + # username = "!secret icloud_email"; + # password = "!secret icloud_password"; + # with_family = true; + #}; + network = { }; + zeroconf = { }; + system_health = { }; + default_config = { }; + system_log = { }; + sensor = [ + { + platform = "template"; + sensors.bedtime_alarm = { + friendly_name = "Bedtime Alarm"; + value_template = "09:00"; + }; + } + ]; + }; + + users.users.hass.extraGroups = [ "dialout" ]; + + system.stateVersion = "23.05"; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/enocean.nix b/hosts/fw.cloonar.com/modules/home-assistant/enocean.nix new file mode 100644 index 0000000..e637036 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/enocean.nix @@ -0,0 +1,12 @@ +{ + services.home-assistant.config = { + "binary_sensor pc_0" = [ + { + platform = "enocean"; + id = [ 254 235 105 198 ]; + name = "enocean_switch_pc"; + } + ]; + logger.logs."homeassistant.components.enocean" = "debug"; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/ldap.nix b/hosts/fw.cloonar.com/modules/home-assistant/ldap.nix new file mode 100644 index 0000000..3d0a4c0 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/ldap.nix @@ -0,0 +1,59 @@ +{ pkgs +, config +, lib +, ... }: +let + ldap-auth-sh = pkgs.stdenv.mkDerivation { + name = "ldap-auth-sh"; + + src = pkgs.fetchFromGitHub { + owner = "efficiosoft"; + repo = "ldap-auth-sh"; + rev = "93b2c00413942908139e37c7432a12bcb705ac87"; + sha256 = "1pymp6ki353aqkigr89g7hg5x1mny68m31c3inxf1zr26n5s2kz8"; + }; + + nativeBuildInputs = [ pkgs.makeWrapper ]; + installPhase = '' + mkdir -p $out/etc + cat > $out/etc/home-assistant.cfg << 'EOF' + CLIENT="ldapsearch" + SERVER="ldaps://ldap.cloonar.com:636" + USERDN="cn=home-assistant,ou=system,ou=users,dc=cloonar,dc=com" + PW="$( 4 }}" ]; + sequence = [ + { + service = "light.turn_on"; + target = { + entity_id = "{{ trigger.entity_id }}"; + }; + data = { + brightness_pct = 100; + color_temp = 250; + }; + } + ]; + } + ]; + } + ]; + }; + "automation bathroom light small" = { + alias = "bathroom light small"; + mode = "restart"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = [ + "light.bathroom_switch_channel_1" + ]; + from = "on"; + to = "off"; + }; + action = [ + { + service = "switch.turn_off"; + target = { + entity_id = "switch.bathroom_small"; + }; + } + ]; + }; + "automation bathroom light" = { + alias = "bathroom light"; + mode = "restart"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = [ + "light.bathroom_switch_channel_1" + ]; + from = "off"; + to = "on"; + }; + action = [ + { + delay = 3600; + } + { + service = "light.turn_off"; + target = { + entity_id = "light.bathroom_switch_channel_1"; + }; + } + ]; + }; + "automation bed_led" = { + alias = "bed_led"; + mode = "restart"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = [ + "light.bedroom_led" + ]; + from = "off"; + to = "on"; + }; + action = [ + { + delay = 10800; + } + { + service = "light.turn_off"; + target = { + entity_id = "{{ trigger.entity_id }}"; + }; + } + ]; + }; + "automation hallway_motion" = { + alias = "Hallway Motion"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "binary_sensor.hallway_motion_motion"; + }; + action = { + service_template = "light.turn_{{ trigger.to_state.state }}"; + target = { + entity_id = "light.hallway_lights"; + }; + }; + }; + "automation bed_button_1" = { + alias = "bed_button_1"; + trigger = { + platform = "event"; + event_type = "shelly.click"; + event_data = { + device = "shellybutton1-E8DB84AA196D"; + }; + }; + action = [ + { + choose = [ + { + conditions = [ "{{ trigger.event.data.click_type == \"single\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bed_reading_1"; + } + ]; + } + { + conditions = [ "{{ trigger.event.data.click_type == \"double\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bedroom_lights"; + } + ]; + } + { + conditions = [ "{{ trigger.event.data.click_type == \"triple\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bedroom_bed"; + } + ]; + } + ]; + } + ]; + }; + "automation bed_button_2" = { + alias = "bed_button_2"; + trigger = { + platform = "event"; + event_type = "shelly.click"; + event_data = { + device = "shellybutton1-E8DB84AA136D"; + }; + }; + action = [ + { + choose = [ + { + conditions = [ "{{ trigger.event.data.click_type == \"single\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bed_reading_2"; + } + ]; + } + { + conditions = [ "{{ trigger.event.data.click_type == \"double\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bedroom_lights"; + } + ]; + } + { + conditions = [ "{{ trigger.event.data.click_type == \"triple\" }}" ]; + sequence = [ + { + service = "light.toggle"; + entity_id = "light.bedroom_bed"; + } + ]; + } + ]; + } + ]; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/locks.nix b/hosts/fw.cloonar.com/modules/home-assistant/locks.nix new file mode 100644 index 0000000..83b106f --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/locks.nix @@ -0,0 +1,117 @@ +{ + services.home-assistant.extraComponents = [ + "nuki" + ]; + + services.home-assistant.config = { + "automation house_door" = { + alias = "house_door"; + mode = "restart"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = [ + "person.dominik" + ]; + from = "not_home"; + to = "home"; + }; + action = [ + { + service = "lock.unlock"; + target = { + entity_id = "lock.house_door"; + }; + } + { + delay = "00:05:00"; + } + { + service = "lock.lock"; + target = { + entity_id = "lock.house_door"; + }; + } + ]; + }; + "automation house_door_ring" = { + alias = "house_door_ring"; + trigger = { + platform = "event"; + event_type = "nuki_event"; + event_data = { + type = "ring"; + }; + }; + action = [ + { + choose = [ + { + conditions = [ "{{ state.house_door == \"unlocked\" }}" ]; + sequence = [ + { + service = "lock.lock"; + target = { + entity_id = "lock.house_door"; + }; + } + ]; + } + ]; + } + ]; + }; + binary_sensor = [ + { + platform = "template"; + sensors = { + lock_critical_battery = { + value_template = '' + {% set domains = ['lock'] %} + {% set ns = namespace(crit=battery_critical, entities=[]) %} + {% for domain in domains %} + {% set batt_critical = states[domain] | selectattr('attributes.battery_critical','defined') | map(attribute='attributes.battery_critical') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %} + {% if batt_critical|length > 0 %} + {% set ns.battery_critical = true %} + {% endif %} + {% endfor %} + {{ ns.battery_critical }} + ''; + friendly_name = "A lock has critical battery"; + device_class = "problem"; + }; + }; + } + ]; + alert = { + battery_critical = { + name = "Lock has low battery!"; + message = '' + {%- set domains = ['lock'] -%} + Lock battery is critical: + {%- for domain in domains -%} + {%- for item in states[domain] -%} + {%- if item.attributes.battery_critical is defined -%} + {% if item.attributes.battery_critical %} + - {{ item.attributes.friendly_name }} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- endfor -%} + ''; + entity_id = "binary_sensor.lock_critical_battery"; + state = "on"; + repeat = [ + 5 + 60 + 360 + ]; + skip_first = true; + can_acknowledge = true; + notifiers = [ + "NotificationGroup" + ]; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/multimedia.nix b/hosts/fw.cloonar.com/modules/home-assistant/multimedia.nix new file mode 100644 index 0000000..70d6898 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/multimedia.nix @@ -0,0 +1,270 @@ +{ + services.home-assistant.config = { + # binary_sensor = [ + # { + # name = "ps5_living"; + # platform = "command_line"; + # command = "python /var/lib/hass/ps5.py -q -b 10.42.96.176"; + # device_class = "connectivity"; + # scan_interval = 5; + # } + # { + # platform = "template"; + # sensors = { + # multimedia_device_on = { + # friendly_name = "Any multimedia device on"; + # device_class = "connectivity"; + # value_template = '' + # {% if is_state('binary_sensor.ps5_living', 'on') or states('media_player.fire_tv_firetv_living_cloonar_com') != 'off' or states('device_tracker.xbox') == 'home' %} + # on + # {% else %} + # off + # {% endif %} + # ''; + # }; + # }; + # } + # ]; + # "automation tv scene" = { + # alias = "auto tv scene"; + # hide_entity = true; + # trigger = { + # platform = "event"; + # event_type = "button_pressed"; + # event_data = { + # id = [ 254 235 105 198 ]; + # }; + # }; + # action = { + # service_template = "switch.turn_on"; + # data_template = { + # entity_id = "switch.computer"; + # }; + # }; + # }; + # "automation beamer switch" = { + # alias = "auto beamer scene"; + # hide_entity = true; + # trigger = { + # platform = "state"; + # entity_id = "sensor.computer_power"; + # }; + # condition = { + # condition = "and"; + # conditions = [ + # { + # condition = "numeric_state"; + # entity_id = "sensor.computer_power"; + # below = 15; + # } + # "{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}" + # ]; + # }; + # action = { + # service = "switch.turn_off"; + # target = { + # entity_id = [ "switch.computer" ]; + # }; + # }; + # }; + "automation xbox on" = { + alias = "xbox on"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "device-tracker.xbox"; + to = "home"; + }; + action = [ + { + service = "media_player.select_source"; + target = { + entity_id = "media_player.marantz_sr6015"; + }; + data = { + source = "Xbox"; + }; + } + { + delay = 5; + } + { + service = "denonavr.get_command"; + target = { + entity_id = "media_player.marantz_sr6015"; + }; + data = { + command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY"; + }; + } + ]; + }; + "automation firetv on" = { + alias = "firetv on"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "media_player.fire_tv_firetv_living_cloonar_com"; + from = "off"; + }; + action = [ + { + service = "denonavr.get_command"; + target = { + entity_id = "media_player.marantz_sr6015"; + }; + data = { + command = "/goform/formiPhoneAppDirect.xml?SIMPLAY"; + }; + } + { + delay = 5; + } + { + service = "denonavr.get_command"; + target = { + entity_id = "media_player.marantz_sr6015"; + }; + data = { + command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY"; + }; + } + ]; + }; + # "automation ps5 on" = { + # alias = "ps5 on"; + # hide_entity = true; + # trigger = { + # platform = "state"; + # entity_id = "binary_sensor.ps5_living"; + # to = "on"; + # }; + # action = [ + # { + # service = "denonavr.get_command"; + # target = { + # entity_id = "media_player.marantz_sr6015"; + # }; + # data = { + # command = "/goform/formiPhoneAppDirect.xml?SIBD"; + # }; + # } + # { + # delay = 5; + # } + # { + # service = "denonavr.get_command"; + # target = { + # entity_id = "media_player.marantz_sr6015"; + # }; + # data = { + # command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY"; + # }; + # } + # ]; + # }; + "automation all multimedia off" = { + alias = "all multimedia off"; + trigger = { + platform = "state"; + entity_id = "binary_sensor.multimedia_device_on"; + to = "off"; + }; + action = [ + { + conditions = [ "{{ states('media_player.android_tv_metz_cloonar_com') != 'off'}}" ]; + sequence = [ + { + service = "androidtv.adb_command"; + target = { + device_id = "a5e50f268f3a2dbd0741fb8e9ff7f931"; + }; + data = { + command = "POWER"; + }; + } + ]; + } + { + service = "denonavr.get_command"; + target = { + entity_id = "media_player.marantz_sr6015"; + }; + data = { + command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY"; + }; + } + ]; + }; + "automation all_multimedia_on" = { + alias = "all multimedia on"; + trigger = { + platform = "state"; + entity_id = "binary_sensor.multimedia_device_on"; + to = "on"; + }; + condition = { + condition = "or"; + conditions = [ + { + condition = "state"; + entity_id = "media_player.android_tv_metz_cloonar_com"; + state = "off"; + } + { + condition = "state"; + entity_id = "media_player.android_tv_metz_cloonar_com"; + state = "unavailable"; + } + ]; + }; + action = [ + { + service = "androidtv.adb_command"; + target = { + device_id = "a5e50f268f3a2dbd0741fb8e9ff7f931"; + }; + data = { + command = "POWER"; + }; + } + { + delay = 5; + } + { + service = "androidtv.adb_command"; + target = { + device_id = "a5e50f268f3a2dbd0741fb8e9ff7f931"; + }; + data = { + command = "adb shell am start -a android.intent.action.VIEW -d content://android.media.tv/passthrough/com.mediatek.tvinput%2F.hdmi.HDMIInputService%2FHDMI100004"; + }; + } + ]; + }; + # "automation multimedia input" = { + # hide_entity = true; + # trigger = { + # platform = "state"; + # entity_id = "sensor.computer_power"; + # }; + # condition = { + # condition = "and"; + # conditions = [ + # { + # condition = "numeric_state"; + # entity_id = "sensor.computer_power"; + # below = 15; + # } + # "{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}" + # ]; + # }; + # action = { + # service = "switch.turn_off"; + # target = { + # entity_id = [ "switch.computer" ]; + # }; + # }; + # }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/notify.nix b/hosts/fw.cloonar.com/modules/home-assistant/notify.nix new file mode 100644 index 0000000..e69891d --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/notify.nix @@ -0,0 +1,15 @@ +{ + services.home-assistant.config = { + notify = [ + { + name = "NotificationGroup"; + platform = "group"; + services = [ + { + service = "pushover_dominik"; + } + ]; + } + ]; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/pc.nix b/hosts/fw.cloonar.com/modules/home-assistant/pc.nix new file mode 100644 index 0000000..2380fe8 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/pc.nix @@ -0,0 +1,46 @@ +{ + services.home-assistant.config = { + "automation pc_switch" = { + alias = "switch pc"; + hide_entity = true; + trigger = { + platform = "event"; + event_type = "button_pressed"; + event_data = { + id = [ 254 235 105 198 ]; + }; + }; + action = { + service_template = "switch.turn_on"; + data_template = { + entity_id = "switch.computer"; + }; + }; + }; + "automation pc power" = { + alias = "auto pc power off"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "sensor.computer_power"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "numeric_state"; + entity_id = "sensor.computer_power"; + below = 15; + } + "{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}" + ]; + }; + action = { + service = "switch.turn_off"; + target = { + entity_id = [ "switch.computer" ]; + }; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/presence.nix b/hosts/fw.cloonar.com/modules/home-assistant/presence.nix new file mode 100644 index 0000000..ce93305 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/presence.nix @@ -0,0 +1,23 @@ +{ + services.home-assistant.extraComponents = [ + "mqtt_room" + "opnsense" + ]; + services.home-assistant.config = { + opnsense = { + url = "https://fw.cloonar.com/api"; + api_secret = "!secret opnsense_api_secret"; + api_key = "!secret opnsense_api_key"; + }; + sensor = [ + { + platform = "mqtt_room"; + name = "Dominiks iPhone BLE"; + device_id = "roomAssistant:d2a41d13-16bf-41fb-af4b-c520bdc7b68a"; + # device_id = "0a666fe0ccd0d587414fec9b9946168f"; + state_topic = "espresense/rooms"; + away_timeout = 30; + } + ]; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/pushover.nix b/hosts/fw.cloonar.com/modules/home-assistant/pushover.nix new file mode 100644 index 0000000..d56b7b7 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/pushover.nix @@ -0,0 +1,16 @@ +{ + services.home-assistant.extraComponents = [ + "pushover" + ]; + + # services.home-assistant.config = { + # notify = [ + # { + # name = "pushover_dominik"; + # platform = "pushover"; + # api_key = "!secret pushover_dominik_api_key"; + # user_key = "!secret pushover_dominik_user_key"; + # } + # ]; + # }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/roborock.nix b/hosts/fw.cloonar.com/modules/home-assistant/roborock.nix new file mode 100644 index 0000000..492f63c --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/roborock.nix @@ -0,0 +1,28 @@ +{ + services.home-assistant.extraComponents = [ + "roborock" + ]; + + services.home-assistant.config = { + "automation roborock" = { + alias = "roborock"; + hide_entity = false; + trigger = { + platform = "state"; + entity_id = [ + "person.dominik" + ]; + from = "home"; + to = "not_home"; + }; + action = [ + { + service = "vacuum.start"; + target = { + device_id = "136c307ff46cd968d08e9f9d20886755"; + }; + } + ]; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/scene-switch.nix b/hosts/fw.cloonar.com/modules/home-assistant/scene-switch.nix new file mode 100644 index 0000000..70ba921 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/scene-switch.nix @@ -0,0 +1,21 @@ +{ + services.home-assistant.config = { + "automation scene_switch" = { + alias = "switch scene"; + hide_entity = true; + trigger = { + platform = "event"; + event_type = "button_pressed"; + event_data = { + id = [ 254 242 234 134 ]; + }; + }; + action = { + service_template = "switch.turn_on"; + data_template = { + entity_id = "switch.computer"; + }; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/sleep.nix b/hosts/fw.cloonar.com/modules/home-assistant/sleep.nix new file mode 100644 index 0000000..44a963d --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/sleep.nix @@ -0,0 +1,59 @@ +{ + services.home-assistant.config = { + "automation wakeup" = { + alias = "wakeup"; + hide_entity = true; + trigger = { + platform = "template"; + value_template = '' + {{ now().timestamp() | timestamp_custom('%H:%M') == (as_timestamp(strptime(states('sensor.bedtime_alarm'), "%H:%M")) - 1800) | timestamp_custom('%H:%M', false) }} + ''; + }; + action = { + service_template = "switch.turn_on"; + data_template = { + entity_id = "switch.coffee_switch"; + }; + }; + }; + "automation sleep" = { + alias = "sleep"; + hide_entity = true; + trigger = [ + { + platform = "event"; + event_type = "shelly.click"; + event_data = { + device = "shellybutton1-E8DB84AA196D"; + }; + } + { + platform = "event"; + event_type = "shelly.click"; + event_data = { + device = "shellybutton1-E8DB84AA136D"; + }; + } + ]; + action = [ + { + choose = [ + { + conditions = [ "{{ trigger.event.data.click_type == \"long\" }}" ]; + sequence = [ + { + service = "light.turn_off"; + entity_id = "all"; + } + { + service = "light.turn_on"; + entity_id = "light.bedroom_bed"; + } + ]; + } + ]; + } + ]; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/home-assistant/snapcast.nix b/hosts/fw.cloonar.com/modules/home-assistant/snapcast.nix new file mode 100644 index 0000000..11afc45 --- /dev/null +++ b/hosts/fw.cloonar.com/modules/home-assistant/snapcast.nix @@ -0,0 +1,66 @@ +{ + services.home-assistant = { + extraComponents = [ "snapcast" ]; + config = { + # "media_player" = { + # platform = "snapcast"; + # host = "snapcast.cloonar.com"; + # }; + "automation toilett_music" = { + alias = "toilett music"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "light.toilett_switch"; + }; + action = { + choose = [ + { + conditions = [ "{{trigger.to_state.state == 'on'}}" ]; + sequence = [ + { + service = "media_player.volume_mute"; + target = { + entity_id = "media_player.snapcast_client_e4_5f_01_3c_fb_c3"; + }; + data = { + is_volume_muted = false; + }; + } + ]; + } + { + conditions = [ "{{trigger.to_state.state == 'off'}}" ]; + sequence = [ + { + service = "media_player.volume_mute"; + target = { + entity_id = "media_player.snapcast_client_e4_5f_01_3c_fb_c3"; + }; + data = { + is_volume_muted = true; + }; + } + ]; + } + ]; + }; + }; + "automation piano" = { + alias = "piano"; + hide_entity = true; + trigger = { + platform = "state"; + entity_id = "media_player.snapcast_client_e4_5f_01_96_c1_1e"; + attribute = "is_volume_muted"; + }; + action = { + service = "switch.turn_on"; + target = { + entity_id = "switch.piano_switch_power"; + }; + }; + }; + }; + }; +} diff --git a/hosts/fw.cloonar.com/modules/unbound.nix b/hosts/fw.cloonar.com/modules/unbound.nix index 4526f02..2ca6827 100644 --- a/hosts/fw.cloonar.com/modules/unbound.nix +++ b/hosts/fw.cloonar.com/modules/unbound.nix @@ -32,7 +32,6 @@ let "\"switch.cloonar.com IN A 10.42.97.10\"" "\"drone.cloonar.com IN A 10.42.97.118\"" "\"hv-02.cloonar.com IN A 10.42.97.3\"" - "\"home-assistant.cloonar.com IN A 10.42.97.1\"" "\"deconz.cloonar.com IN A 10.42.97.20\"" "\"mopidy.cloonar.com IN A 10.42.97.20\"" "\"snapcast.cloonar.com IN A 10.42.97.20\"" diff --git a/hosts/fw.cloonar.com/secrets.yaml b/hosts/fw.cloonar.com/secrets.yaml index d0b5ce0..247693d 100644 --- a/hosts/fw.cloonar.com/secrets.yaml +++ b/hosts/fw.cloonar.com/secrets.yaml @@ -8,7 +8,7 @@ wg_ghetto_at_key: ENC[AES256_GCM,data:OIHmoy3SpIi9aefZnZ1PzpyHbEso18ceoTULf2eQkx gitea-runner-token: ENC[AES256_GCM,data:Nd0vsnuJficsdZaqeBZXa9vD7PLMdDtV9sMX0TxUSEMNU7Reu3HLCWuvP0easPU=,iv:4mrfQc1tobg/QiExUuWST6iU9TdNwiS1BMmOnQqCFZU=,tag:85aRoD3IkRq3mcoPdLKaBQ==,type:str] drone: ENC[AES256_GCM,data:S8WTZqGHfcdpSojavZ87GdE5dagcTAdHBVQEbHHgnB4V7aczS6c5QdEJxK920Pjpf6o54OOQYniVsPiiXSxwjExDKPzhs/DG2hfigmf8RgfkP+3tF2W0KiPmV2jxog8w226ZKnI+hSBs8tuIfJBhrpY7Y/YNmTPfq+cnnLS8ibYqytcpzoogI9I8THzHCu3r+yejoGSyTMs9L4gPhOjz5aK4UV6V,iv:zqN/aSBI3xGGNDnpHPGyQnQP2YZOGUk6dAGtON/QlHU=,tag:o9YFDKAB5uR9lPmChyxB8g==,type:str] home-assistant-ldap: ENC[AES256_GCM,data:uZEPbSnkgQYSd8ev6FD8TRHWWr+vusadtMcvP7KKL2AZAV0h1hga5fODN6I5u0DNL9hq2pNM+FwU0E/svWLRww==,iv:IhmUgSu34NaAY+kUZehx40uymydUYYAyte1aGqQ33/8=,tag:BKFCJPr7Vz4EG78ry/ZD7g==,type:str] -home-assistant-secrets.yaml: ENC[AES256_GCM,data:8LH3rrbkpRIFuKZmXe7EHcXPlkzfbdaxX7ssWjIUJ0FQ2QbMUOFsrxVt4diMVHJuaDCoC5gXIwWYDXw4yQj+4Pdf0cwk2MiXj2S9O7GxuOQzP4V1Ab4HeLJOXbGP4cigzNak5epbBiyJY13mVPVgjxX2M4GkuB2TXCOZ5GpvHHv0IvNcc6ymov/XkpJh7MOkyKw45jrYjiV/8dSTORhcWms5J/YgRpSQ/XijWkzucsisNyYk6mKYSq5O4xWFNEF1YC5FFr+rX7xzsbAp0niG3r1d+qcxYHOe0KPB0auxdxif3wQELAp/tosm4l+H+llw3t6STdFVUeBHC+naAwr0QTYB2a7yWLvb6Eh9CYQ7Z3qS/CvvVKs3sB0djRU42FZ9O4c2XcMllP0f3nVaF+DnLpaxgCdLoGPBhYdyTniBij+JudvGZvpWZUFLRlx49zC07RMRG4k+xMA4bAJkiLb+T+b30ur7N+EUgCOyp2FROc1ngCiJqr+cYbnWN1wqougm+pM+GxNZNwakiw1RFJPcOzpjtuwYp/gEKOC+Sz3Qkl4VpYxj7t7fikV0s5r+HzuNFa7gFWpApeRt6YuffQRWhlPVlCOkrQUhRl3YPG9khQ==,iv:r5Vb1ucVrMD0xZOuVnyRJ4El5sCBru/4nOV74pz+tA0=,tag:SwrBmA++GWVzf/0lWSuCpg==,type:str] +home-assistant-secrets.yaml: ENC[AES256_GCM,data:m7uOVo7hPk/RmqqRS6y7NKoMKsR9Bdi1ntatsZdDOAbJMjZmZL2FgPEHi/zF73zCfRfTOca3dwpulR3WXZ9Ic1sbUIggmusJMg4Gellw1CUhx7SbQN5nieAbPbB9GVxMuV4OakD1u7Swz8JggDT6IwojSnuD5omCRCyUH1wvKB+Re59q6EStderlm5MJNVFlVrbKVbLKLcw4yRgTh34BGnTTjcJmgSlQjO1ciu2B7YQmdl0Fw6d8AdbEzgB5TFG5ONc85UhJDE8Wlw==,iv:GCtpcVChN2UMWtfnWURozCfVj2YbRPqp/bH4Jjntybs=,tag:pcxP7gTBtXMNT5iyW5YXTw==,type:str] sops: kms: [] gcp_kms: [] @@ -33,8 +33,8 @@ sops: Tlo3NHBlMkJEaXNOZkxSKytGSDNEMWcKquNuAzbPWwAjqc65BcAA/DMltFjC6Ayb CKmJ7kaYFFUAIuBXhksvlH2b7vRZLT1QlwqUcRIRjxe+mZnsMIqE7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-12-07T23:58:35Z" - mac: ENC[AES256_GCM,data:jhcwsmXWQ7DgK2IPo90zJh7v7XFIe+NHvNUZtLW49oZNC37AA3NXissnVB9bhTIZw/905iGjpuy+CYNAI+21YkWIJQ5ESDTWhdUpXsDOlv+gKcODtW8/VKH0AUsvo1n7EBOGWcI5XliNvFza+59aMW5RKyu7xBX39J+2TOk2gZM=,iv:jLF7Z3JezWshKNGn7juxxsSJyKPcy4WaPMupDGENNmw=,tag:F6pjhdzWMWI048wow2ThBg==,type:str] + lastmodified: "2023-12-09T21:02:39Z" + mac: ENC[AES256_GCM,data:fgpga0FpOsVvBOOkx5mr7U/mcQ/2o3+SED8/Iv9LuGkdg2MBAloIvUWOTgw9AP/OHIj41KMQUYlapNWHXDFd4hd3Vib1Fsk4x856v3sL7TgtwJW6/cvP1D99rV76NolJ3cNH9GNDdI50Bx/prZCB8E/Izyu4jwKWmck8ByRGkZE=,iv:mBGOvop4oLX1an4D6R08p8502EWsMBWFrnrM52T7pB4=,tag:uWtJjQ3iUj1/3BOOyD6nhw==,type:str] pgp: [] unencrypted_suffix: _unencrypted - version: 3.7.3 + version: 3.8.1