From 5598ec5c5cf65d59c79fda2a57aac988de7fc0c6 Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Wed, 8 Apr 2020 16:43:09 +0200 Subject: [PATCH] pepe: add home-assistant wip --- configs/pepe/configuration.nix | 34 +-- configs/pepe/home-assistant.nix | 213 +++++++++++++++ configs/pepe/home-assistant/chaospott.nix | 82 ++++++ configs/pepe/home-assistant/dayOfWeek.nix | 52 ++++ configs/pepe/home-assistant/holiday.nix | 92 +++++++ configs/pepe/home-assistant/kodi.nix | 81 ++++++ configs/pepe/home-assistant/mpd.nix | 37 +++ configs/pepe/home-assistant/mqtt.nix | 28 ++ configs/pepe/home-assistant/sonoff.nix | 119 +++++++++ configs/pepe/home-assistant/timer.nix | 244 +++++++++++++++++ configs/pepe/home-assistant/zigbee2mqtt.nix | 279 ++++++++++++++++++++ configs/pepe/wifi-access-point.nix | 22 +- images/remote-install/config.nix | 14 +- modules/services/home-assistant.nix | 4 +- shell.nix | 3 +- 15 files changed, 1258 insertions(+), 46 deletions(-) create mode 100644 configs/pepe/home-assistant.nix create mode 100644 configs/pepe/home-assistant/chaospott.nix create mode 100644 configs/pepe/home-assistant/dayOfWeek.nix create mode 100644 configs/pepe/home-assistant/holiday.nix create mode 100644 configs/pepe/home-assistant/kodi.nix create mode 100644 configs/pepe/home-assistant/mpd.nix create mode 100644 configs/pepe/home-assistant/mqtt.nix create mode 100644 configs/pepe/home-assistant/sonoff.nix create mode 100644 configs/pepe/home-assistant/timer.nix create mode 100644 configs/pepe/home-assistant/zigbee2mqtt.nix diff --git a/configs/pepe/configuration.nix b/configs/pepe/configuration.nix index 12550b8..0b70fdf 100644 --- a/configs/pepe/configuration.nix +++ b/configs/pepe/configuration.nix @@ -2,37 +2,24 @@ imports = [ - + ./hardware-configuration.nix - #./samba.nix - ./syncthing.nix + #./syncthing.nix ./tinc.nix - #./wifi-access-point.nix + ./wifi-access-point.nix + ./home-assistant.nix ]; - custom.samba-share = { - enable = false; - folders = { public = "/home/palo/movies"; }; + system.custom.wifi = { + enable = true; + interfaces = [ "wlp3s0" ]; + configurationFile = ; }; - system.custom.wifi.interfaces = [ "wlp3s0" ]; - networking.hostName = "pepe"; - security.wrappers = { - pmount.source = "${pkgs.pmount}/bin/pmount"; - pumount.source = "${pkgs.pmount}/bin/pumount"; - }; - - # keybase - services.keybase.enable = false; - services.kbfs.enable = false; - - programs.custom.steam.enable = false; - programs.custom.video.enable = false; - services.printing.enable = true; # fonts @@ -51,10 +38,5 @@ }; }; - configuration.desktop = { - width = 1366; - height = 768; - }; - } diff --git a/configs/pepe/home-assistant.nix b/configs/pepe/home-assistant.nix new file mode 100644 index 0000000..3b5f102 --- /dev/null +++ b/configs/pepe/home-assistant.nix @@ -0,0 +1,213 @@ +{ pkgs, config, lib, ... }: +let unstablePkgs = import { }; +in { + + imports = [ + #./home-assistant/chaospott.nix + #./home-assistant/holiday.nix + #./home-assistant/mpd.nix + ./home-assistant/sonoff.nix + ./home-assistant/mqtt.nix + #./home-assistant/dayOfWeek.nix + #./home-assistant/timer.nix + #./home-assistant/kodi.nix + #./home-assistant/zigbee2mqtt.nix + ]; + + services.homeAssistantConfig = { + + # turn on to edit GUI + # lovelace = {}; + + homeassistant = { + latitude = 51.444847; + longitude = 6.967006; + elevation = 116; + + auth_providers = [{ + type = "trusted_networks"; + trusted_networks = + [ config.module.cluster.services.tinc."private".networkSubnet ]; + }]; + }; + + prometheus.namespace = "hass"; + + automation = [ + + # todo when ich weis ich bin zuhause + #{ + # alias = "Licht and wenn Dunkel"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.night" ]; + # from = "off"; + # to = "on"; + # }; + # action = [ + # { + # service = "switch.turn_on"; + # entity_id = "group.kitchen"; + # } + # { + # service = "switch.turn_on"; + # entity_id = "group.living_room"; + # } + # ]; + #} + + #{ + # alias = "Küchen Sensor An"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.motion_1" ]; + # to = "on"; + # }; + # action = { + # service = "switch.turn_on"; + # entity_id = "group.kitchen"; + # }; + #} + + #{ + # alias = "Küchen Sensor aus"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.motion_1" ]; + # to = "off"; + # for = "00:00:25"; + # }; + # action = { + # service = "switch.turn_off"; + # entity_id = "group.kitchen"; + # }; + #} + ]; + + group = { + bed_room = { + name = "Schlafzimmer"; + view = false; + }; + tv = { + name = "TV"; + view = false; + }; + living_room = { + name = "Wohnzimmer"; + view = false; + }; + kitchen = { + name = "Küche"; + view = false; + }; + today = { + control = "hidden"; + name = "Today"; + view = false; + entities = [ "sensor.weather_temperature" "sun.sun" ]; + }; + all_lights = { + name = "All Lights"; + view = false; + }; + unknown = { + control = "hidden"; + name = "Not Used"; + view = false; + }; + + view_rooms = { + name = "Räume"; + view = true; + entities = [ + "group.all_lights" + "group.bed_room" + "group.living_room" + "group.kitchen" + "group.tv" + ]; + }; + + view_overview = { + name = "Übersicht"; + view = true; + entities = [ "group.today" ]; + }; + + }; + + sun = { }; + + script.turn_all_off.sequence = [ ]; + + script.turn_all_on.sequence = [ ]; + + sensor = [ + # Weather prediction + { + platform = "zamg"; + name = "Weather"; + } + ]; + + # todo: add holidays package to home-assiatnt + binary_sensor = [ + { + name = "before_workday"; + platform = "workday"; + country = "DE"; + province = "NW"; + workdays = [ "mon" "tue" "wed" "thu" "fri" ]; + days_offset = 1; + } + { + name = "workday"; + platform = "workday"; + country = "DE"; + province = "NW"; + workdays = [ "mon" "tue" "wed" "thu" "fri" ]; + } + ]; + + }; + + services.home-assistant = { + enable = true; + package = unstablePkgs.home-assistant.override { + python3 = unstablePkgs.python37; + extraPackages = python: [ + # todo : check which is still needed + python.netdisco + python.xmltodict + python.mpd2 + + # for mqtt + python.hbmqtt + python.paho-mqtt + + # needed for platform workday + #(python.buildPythonPackage rec { + # pname = "holidays"; + # version = "0.9.10"; + # src = python.fetchPypi { + # inherit pname version; + # sha256 = + # "9f06d143eb708e8732230260636938f2f57114e94defd8fa2082408e0d422d6f"; + # }; + # doCheck = false; + # buildInputs = [ pkgs.dateutils ]; + # propagatedBuildInputs = [ python."python-dateutil" python."six" ]; + # meta = with pkgs.stdenv.lib; { + # homepage = "https://github.com/dr-prodigy/python-holidays"; + # license = licenses.mit; + # description = "Generate and work with holidays in Python"; + # maintainers = with maintainers; [ mrVanDalo ]; + # }; + #}) + ]; + }; + + }; + +} diff --git a/configs/pepe/home-assistant/chaospott.nix b/configs/pepe/home-assistant/chaospott.nix new file mode 100644 index 0000000..945d7cd --- /dev/null +++ b/configs/pepe/home-assistant/chaospott.nix @@ -0,0 +1,82 @@ +{ config, pkgs, ... }: +let + + name = "chaospott"; + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/${name}.json"; + +in { + services.homeAssistantConfig = { + + sensor = [ + { + platform = "file"; + name = "${name}_aerie"; + file_path = filePath; + value_template = "{{ value_json.aerie }}"; + } + { + platform = "file"; + name = "${name}_cellar"; + file_path = filePath; + value_template = "{{ value_json.cellar }}"; + } + ]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize = { + "sensor.${name}_aerie" = { + icon = "mdi:store"; + entity_picture = "https://chaospott.de/images/logo.png"; + friendly_name = "ChaosPott Oben"; + }; + "sensor.${name}_cellar" = { + icon = "mdi:store"; + entity_picture = "https://chaospott.de/images/logo.png"; + friendly_name = "ChaosPott Unten"; + }; + }; + }; + + group = { + "${name}" = { + name = "ChaosPott (Essen)"; + control = "hidden"; + entities = [ "sensor.${name}_aerie" "sensor.${name}_cellar" ]; + }; + view_overview.entities = [ "group.${name}" ]; + }; + + }; + + systemd.services."${name}" = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set ${name} for homeassistant"; + script = # sh + '' + ${pkgs.curl}/bin/curl -Ls https://status.chaospott.de/api \ + | ${pkgs.jq}/bin/jq --compact-output \ + '.sensors.door_locked | + [.[] | { "\(.location)" : (if .value then "closed" else "open" end) }] | + reduce .[] as $item ({}; . + $item) ' \ + >> ${filePath} + ''; + }; + + systemd.timers."${name}" = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "hourly"; + Persistent = "true"; + }; + }; + +} diff --git a/configs/pepe/home-assistant/dayOfWeek.nix b/configs/pepe/home-assistant/dayOfWeek.nix new file mode 100644 index 0000000..0aba0d1 --- /dev/null +++ b/configs/pepe/home-assistant/dayOfWeek.nix @@ -0,0 +1,52 @@ +{ config, ... }: +let + + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/dayOfWeek.json"; + +in { + services.homeAssistantConfig = { + + sensor = [{ + platform = "file"; + name = "day_of_week"; + file_path = filePath; + value_template = "{{ value_json.dayOfWeek }}"; + }]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize."sensor.day_of_week" = { + icon = "mdi:calendar-today"; + friendly_name = "Wochen Tag"; + }; + }; + + group = { overview.entities = [ "sensor.day_of_week" ]; }; + + }; + + systemd.services.dayOfWeek = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set day of wek for homeassistant"; + script = # sh + '' + date +'{"dayOfWeek":"%A"}' >> ${filePath} + ''; + }; + systemd.timers.dayOfWeek = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "00:01:00"; + Persistent = "true"; + }; + }; + +} diff --git a/configs/pepe/home-assistant/holiday.nix b/configs/pepe/home-assistant/holiday.nix new file mode 100644 index 0000000..fea17a4 --- /dev/null +++ b/configs/pepe/home-assistant/holiday.nix @@ -0,0 +1,92 @@ +{ config, pkgs, ... }: +let + + state = "NW"; # NRW + # state = "BE"; # Berlin + + name = "holiday"; + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/${name}.json"; + +in { + services.homeAssistantConfig = { + + # todo : use the python tool + sensor = [ + { + platform = "file"; + name = "${name}_date"; + file_path = filePath; + value_template = "{{ value_json.date }}"; + } + { + platform = "file"; + name = "${name}_name"; + file_path = filePath; + value_template = "{{ value_json.name }}"; + } + ]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize = { + "sensor.${name}_date" = { + icon = "mdi:calendar"; + friendly_name = "Nächster Feiertag"; + }; + "sensor.${name}_name" = { + icon = "mdi:calendar"; + friendly_name = "Nächster Feiertag"; + }; + }; + }; + + group = { + + holidays = { + name = "Feiertage"; + view = false; + control = "hidden"; + entities = [ "sensor.${name}_date" "sensor.${name}_name" ]; + }; + + view_overview.entities = [ "group.holidays" ]; + + }; + + }; + + systemd.services."${name}" = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set ${name} for homeassistant"; + script = # sh + '' + ${pkgs.curl}/bin/curl \ + -Ls "https://feiertage-api.de/api/?jahr=$( date +%Y )&nur_land=${state}" \ + | ${pkgs.jq}/bin/jq --compact-output ' + map_values( .datum ) | + to_entries | + map( { date: .value, name : .key } ) | + sort_by( .date ) | + map(select ( .date >= "'`date +%Y-%m-%d`'" )) | + .[0]' \ + >> ${filePath} + ''; + }; + + systemd.timers."${name}" = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "daily"; + Persistent = "true"; + }; + }; + +} diff --git a/configs/pepe/home-assistant/kodi.nix b/configs/pepe/home-assistant/kodi.nix new file mode 100644 index 0000000..b668ae9 --- /dev/null +++ b/configs/pepe/home-assistant/kodi.nix @@ -0,0 +1,81 @@ +{ pkgs, config, lib, ... }: { + + services.homeAssistantConfig = { + + group.view_overview.entities = [ "media_player.kodi" ]; + + media_player = [{ + platform = "kodi"; + host = "127.0.0.1"; + turn_on_action.service = "script.watch_tv"; + turn_off_action.service = "script.stop_watch_tv"; + }]; + + shell_command = { + start_display = + "sudo ${pkgs.systemd}/bin/systemctl start display-manager"; + stop_display = "sudo ${pkgs.systemd}/bin/systemctl stop display-manager"; + }; + + script = { + + turn_all_off.sequence = [ + # todo : use the shell_command here + { + alias = "turn off tv"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + { + alias = "stop kodi"; + service = "shell_command.stop_display"; + } + ]; + + test_display.sequence = [ + { service = "shell_command.start_display"; } + { delay.seconds = 20; } + { service = "shell_command.stop_display"; } + ]; + + watch_tv = { + alias = "Watch TV"; + sequence = [ + { + alias = "turn on tv"; + service = "switch.turn_on"; + data.entity_id = "group.tv"; + } + { delay.minutes = 1; } + { + alias = "start kodi"; + service = "shell_command.start_display"; + } + ]; + }; + + stop_watch_tv = { + alias = "Stop TV"; + sequence = [ + { + alias = "turn off tv"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + { + alias = "stop kodi"; + service = "shell_command.stop_display"; + } + ]; + }; + }; + + group.tv.entities = [ "script.watch_tv" "script.stop_watch_tv" ]; + + }; + + security.sudo.extraConfig = '' + hass ALL= (root) NOPASSWD: ${pkgs.systemd}/bin/systemctl start display-manager + hass ALL= (root) NOPASSWD: ${pkgs.systemd}/bin/systemctl stop display-manager + ''; +} diff --git a/configs/pepe/home-assistant/mpd.nix b/configs/pepe/home-assistant/mpd.nix new file mode 100644 index 0000000..c7650e8 --- /dev/null +++ b/configs/pepe/home-assistant/mpd.nix @@ -0,0 +1,37 @@ +{ lib, ... }: + +{ + services.homeAssistantConfig = { + + group.view_overview.entities = [ "media_player.mpd" ]; + + media_player = [{ + platform = "mpd"; + host = "localhost"; + }]; + + script.turn_all_off.sequence = [{ + alias = "turn mpd off"; + service = "media_player.turn_off"; + data.entity_id = "media_player.mpd"; + }]; + + script.turn_all_on.sequence = [ + { + alias = "turn mpd on"; + service = "media_player.turn_on"; + data.entity_id = "media_player.mpd"; + } + { + alias = "Adjust volume"; + service = "media_player.volume_set"; + data = { + entity_id = "media_player.mpd"; + volume_level = "0.90"; + }; + } + ]; + + }; + +} diff --git a/configs/pepe/home-assistant/mqtt.nix b/configs/pepe/home-assistant/mqtt.nix new file mode 100644 index 0000000..09c1b3b --- /dev/null +++ b/configs/pepe/home-assistant/mqtt.nix @@ -0,0 +1,28 @@ +{ lib, ... }: +{ + services.homeAssistantConfig.mqtt = { + # discovery = false; + + # for mosquitto + broker = "127.0.0.1"; + username = lib.fileContents ; + password = lib.fileContents ; + + }; + + services.mosquitto = { + enable = true; + host = "0.0.0.0"; + users = { + homeassistant = { + password = lib.fileContents ; + acl = [ "topic readwrite #" ]; + }; + zigbee = { + password = lib.fileContents ; + acl = [ "topic readwrite #" ]; + }; + }; + }; + +} diff --git a/configs/pepe/home-assistant/sonoff.nix b/configs/pepe/home-assistant/sonoff.nix new file mode 100644 index 0000000..51bf1ec --- /dev/null +++ b/configs/pepe/home-assistant/sonoff.nix @@ -0,0 +1,119 @@ +{ pkgs, config, lib, ... }: + +let unstablePkgs = import { }; +in { + + services.homeAssistantConfig = let + + sonoffSwitches = { + "pal01" = { + label = "Schlafzimmer"; + icon = "mdi:lightbulb-on"; + }; + "pal02" = { + label = "Schlafzimmer"; + icon = "mdi:lightbulb-on"; + }; + "pal03" = { + label = "Wohnzimmer"; + icon = "mdi:lightbulb-on"; + }; + "pal04" = { + label = "Wohnzimmer"; + icon = "mdi:lightbulb-on"; + }; + "pal05" = { + label = "TV"; + icon = "mdi:television"; + }; + "pal06" = { + label = "Küche"; + icon = "mdi:lightbulb-on"; + }; + "pal07" = { + label = "Nummer 7"; + icon = "mdi:power-plug-off"; + }; + "pal08" = { + label = "Nummer 8"; + icon = "mdi:power-plug-off"; + }; + }; + + toSwitch = name: "switch.${name}"; + + in { + + homeassistant = { + customize = lib.mapAttrs' (entity: value: { + name = toSwitch entity; + value = { + friendly_name = value.label; + icon = value.icon; + }; + }) sonoffSwitches; + }; + + script.turn_all_off.sequence = [ + { + alias = "turn off sonoff"; + service = "switch.turn_off"; + data.entity_id = "group.all_lights"; + } + { + alias = "turn off sonoff"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + ]; + + script.turn_all_on.sequence = [{ + alias = "turn on all lights"; + service = "switch.turn_on"; + data.entity_id = "group.all_lights"; + }]; + + group = { + bed_room = { entities = builtins.map toSwitch [ "pal01" "pal02"]; }; + living_room = { entities = builtins.map toSwitch [ "pal03" "pal04" ]; }; + tv = { entities = builtins.map toSwitch [ "pal05" ]; }; + kitchen = { entities = builtins.map toSwitch [ "pal06" ]; }; + unknown = { + entities = builtins.map toSwitch [ "pal07" "pal08" ]; + }; + all_lights = { + entities = builtins.map toSwitch [ "pal01" "pal02" "pal03" "pal04" "pal05" "pal06" ]; + }; + }; + + switch = let + sonoffConfigurations = builtins.map (name: { + name = name; + platform = "mqtt"; + command_topic = "cmnd/${lib.toUpper name}/POWER"; + state_topic = "stat/${lib.toUpper name}/POWER"; + payload_on = "ON"; + payload_off = "OFF"; + state_on = "ON"; + state_off = "OFF"; + }) (builtins.attrNames sonoffSwitches); + in sonoffConfigurations; + + # discover state on init + automation = [{ + alias = "Sonoff initial Power state"; + trigger = { + platform = "homeassistant"; + event = "start"; + }; + action = builtins.map (name: { + service = "mqtt.publish"; + data = { + topic = "cmnd/${lib.toUpper name}/power"; + payload = ""; + }; + }) (builtins.attrNames sonoffSwitches); + }]; + }; + +} diff --git a/configs/pepe/home-assistant/timer.nix b/configs/pepe/home-assistant/timer.nix new file mode 100644 index 0000000..663a179 --- /dev/null +++ b/configs/pepe/home-assistant/timer.nix @@ -0,0 +1,244 @@ +{ config, ... }: { + + imports = [ ./mpd.nix ]; + + services.homeAssistantConfig = { + + sensor = [{ + platform = "time_date"; + display_options = [ "time" "date" ]; + }]; + + input_datetime = { + wakeup = { + name = "Arbeitswecker"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + leave = { + name = "Turn off Time"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + return = { + name = "Return home"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + sleep = { + name = "Turn off Time"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + }; + + input_boolean = { + wakeup = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + leave = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + return = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + sleep = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + }; + + input_select = { + wakeup = { + name = "Playlist"; + icon = "mdi:library-music"; + options = [ "wakeup" "wakeup1" "wakeup2" ]; + }; + }; + + binary_sensor = [ + { + platform = "tod"; + name = "night"; + after = "sunset"; + before = "sunrise"; + } + { + platform = "tod"; + name = "daytime"; + after = "sunrise"; + before = "sunset"; + } + ]; + + group = { + + timer_wakeup = { + view = false; + name = "Arbeits Aufwachen"; + control = "hidden"; + entities = [ + "input_boolean.wakeup" + "input_datetime.wakeup" + "input_select.wakeup" + ]; + }; + + timer_leave = { + view = false; + name = "Leave Time"; + control = "hidden"; + entities = [ "input_boolean.leave" "input_datetime.leave" ]; + }; + + timer_return = { + view = false; + name = "Nach Hause kommen"; + control = "hidden"; + entities = [ "input_boolean.return" "input_datetime.return" ]; + }; + + timer_sleep = { + view = false; + name = "Einschlafen"; + control = "hidden"; + entities = [ "input_boolean.sleep" "input_datetime.sleep" ]; + }; + + timers.entities = [ + "group.timer_wakeup" + "group.timer_leave" + "group.timer_return" + "group.timer_sleep" + "binary_sensor.night" + "binary_sensor.daytime" + ]; + + today.entities = [ "sensor.date" "sensor.time" ]; + + view_overview.entities = [ + "group.timer_wakeup" + "group.timer_leave" + "group.timer_return" + "group.timer_sleep" + ]; + }; + + automation = [ + { + alias = "Wecker Arbeiten"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.wakeup.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "state"; + entity_id = "input_boolean.wakeup"; + state = "on"; + } + { + condition = "state"; + entity_id = "binary_sensor.workday"; + state = "on"; + } + ]; + }; + action = [ + { + alias = "Play wakeup list"; + service = "media_player.play_media"; + data_template = { + entity_id = "media_player.mpd"; + media_content_type = "playlist"; + media_content_id = "{{ states('input_select.wakeup') }}"; + }; + } + { + alias = "turn all on"; + service = "script.turn_on"; + entity_id = "script.turn_all_on"; + } + ]; + } + + { + alias = "Leave Turn all off Timer"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.leave.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [{ + condition = "state"; + entity_id = "input_boolean.leave"; + state = "on"; + }]; + }; + action = [{ + alias = "turn all off"; + service = "script.turn_on"; + entity_id = "script.turn_all_off"; + }]; + } + + { + alias = "Return to Home"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.return.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [{ + condition = "state"; + entity_id = "input_boolean.return"; + state = "on"; + }]; + }; + action = [{ + alias = "turn all on"; + service = "script.turn_on"; + entity_id = "script.turn_all_on"; + }]; + } + + { + alias = "Sleep Turn all off Timer"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.sleep.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [{ + condition = "state"; + entity_id = "input_boolean.sleep"; + state = "on"; + }]; + }; + action = [{ + alias = "turn all off"; + service = "script.turn_on"; + entity_id = "script.turn_all_off"; + }]; + } + + ]; + }; + +} diff --git a/configs/pepe/home-assistant/zigbee2mqtt.nix b/configs/pepe/home-assistant/zigbee2mqtt.nix new file mode 100644 index 0000000..03b100d --- /dev/null +++ b/configs/pepe/home-assistant/zigbee2mqtt.nix @@ -0,0 +1,279 @@ +{ pkgs, lib, config, ... }: +let + + # allow new devices to join + enablePairing = true; + + device = "/dev/ttyACM0"; + dataFolder = "/srv/zigbee/data"; + + sensors = { + buttons = { + "button_1".id = "0x00158d0002b04f65"; + "button_2".id = "0x00158d0002b04f09"; + "button_3".id = "0x00158d0002b00e04"; + }; + temperature = { + "temperature_sensor_1".id = "0x00158d0002d79220"; + "temperature_sensor_2".id = "0x00158d0002d7913d"; + }; + motion = { "motion_sensor_1".id = "0x00158d0002fbd451"; }; + }; + + # todo : rename with allSensors + allSensors = with sensors; buttons // temperature // motion; + + zigBee2MqttConfig = { + + # Home Assistant integration (MQTT discovery) + homeassistant = false; + # homeassistant = true; + + # allow new devices to join + permit_join = enablePairing; + + # MQTT settings + mqtt = { + # MQTT base topic for zigbee2mqtt MQTT messages + base_topic = "zigbee2mqtt"; + # MQTT server URL + server = "mqtt://127.0.0.1:1883"; + # MQTT server authentication, uncomment if required: + user = "zigbee"; + password = lib.fileContents ; + }; + + # Serial settings + serial = { + port = "/dev/ttyACM0"; + # Optional: disable LED of CC2531 USB sniffer + disable_led = true; + }; + + devices = lib.mapAttrs' (name: + { id, ... }: { + name = id; + value = { + retain = false; + friendly_name = name; + }; + }) allSensors; + }; + + configurationYaml = + pkgs.writeText "configuration.yml" (builtins.toJSON zigBee2MqttConfig); +in { + imports = [ ./mqtt.nix ]; + + services.homeAssistantConfig = { + + # group.unknown.entities = [ "sensor.button_1" ]; + + sensor = let + buttons = with lib; + mapAttrsToList (name: + { ... }: { + platform = "mqtt"; + name = name; + icon = "mdi:toggle-switch"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + value_template = "{{ value_json.click }}"; + }) sensors.buttons; + + temperature = with lib; + mapAttrsToList (name: + { ... }: [ + { + platform = "mqtt"; + name = name; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "°C"; + device_class = "temperature"; + value_template = "{{ value_json.temperature }}"; + } + { + platform = "mqtt"; + name = "humidity_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "%"; + device_class = "humidity"; + value_template = "{{ value_json.humidity }}"; + } + { + platform = "mqtt"; + name = "pressure_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "hPa"; + device_class = "pressure"; + value_template = "{{ value_json.pressure }}"; + } + ]) sensors.temperature; + + informations = lib.mapAttrsToList (name: + { ... }: [ + { + platform = "mqtt"; + name = "battery_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "%"; + device_class = "battery"; + value_template = "{{ value_json.battery }}"; + } + { + name = "link_${name}"; + platform = "mqtt"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "-"; + value_template = "{{ value_json.linkquality }}"; + } + ]) allSensors; + + in lib.flatten (buttons ++ temperature ++ informations); + + binary_sensor = let + + motion = lib.mapAttrsToList (name: + { ... }: { + name = name; + platform = "mqtt"; + device_class = "motion"; + #icon = "mdi:motion-sensor"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + payload_on = true; + payload_off = false; + value_template = "{{ value_json.occupancy }}"; + }) sensors.motion; + in lib.flatten (motion); + + group = let + + information = name: [ "sensor.battery_${name}" "sensor.link_${name}" ]; + + sensor = lib.mapAttrs' (name: + { ... }: { + name = name; + value = { + control = "hidden"; + entities = [ "sensor.${name}" ] ++ (information name); + }; + }) (sensors.buttons); + + sensorTemperature = lib.mapAttrs' (name: + { ... }: { + name = name; + value = { + control = "hidden"; + entities = [ + "sensor.${name}" + "sensor.humidity_${name}" + "sensor.pressure_${name}" + ] ++ (information name); + }; + }) (sensors.temperature); + + binarySensor = lib.mapAttrs' (name: + { ... }: { + name = name; + value = { + control = "hidden"; + entities = [ "binary_sensor.${name}" ] ++ (information name); + }; + }) (sensors.motion); + + views = { + view_sensors = { + name = "Sensoren"; + control = "hidden"; + view = true; + entities = + lib.mapAttrsToList (name: { ... }: "group.${name}") allSensors; + }; + }; + + in views // sensor // binarySensor // sensorTemperature; + + automation = let + lights = map (button: { + alias = "Toggle all lights, on click"; + trigger = { + platform = "mqtt"; + topic = "zigbee2mqtt/${button}"; + }; + condition = { + condition = "template"; + value_template = ''{{ "single" == trigger.payload_json.click }}''; + }; + action = { + service = "switch.toggle"; + entity_id = "group.all_lights"; + }; + }) [ "button_1" "button_2" "button_3" ]; + mpd = map (button: { + alias = "Toggle mpd, on double click"; + trigger = { + platform = "mqtt"; + topic = "zigbee2mqtt/${button}"; + }; + condition = { + condition = "template"; + value_template = ''{{ "double" == trigger.payload_json.click }}''; + }; + action = { + service = "media_player.toggle"; + # todo use a group here + entity_id = "media_player.mpd"; + }; + }) [ "button_1" "button_2" "button_3" ]; + in lights ++ mpd; + + # click = double => music an aus + + # click = hold => film an aus + + }; + + virtualisation.docker.enable = true; + + # todo : einen eigenen container bauen mit dockerTool : https://nixos.wiki/wiki/Docker + + systemd.services."zigbee2mqtt" = { + enable = true; + description = + "Allows you to use your Zigbee devices without the vendors bridge/gateway."; + after = [ "docker.service" ]; + requires = [ "docker.service" ]; + # todo : udev rule erstellen, die diesen service erst startet, dieses wanted by ist labil + wantedBy = [ "home-assistant.service" ]; + + preStart = '' + if [ -f ${dataFolder}/configuration.yaml ] + then + rm ${dataFolder}/configuration.yaml + fi + mkdir -p ${dataFolder} + cat ${configurationYaml} | ${pkgs.yq}/bin/yq --yaml-output '.' > ${dataFolder}/configuration.yaml + ''; + + restartTriggers = [ configurationYaml ]; + + script = '' + # delete old instance to ensure update + ${pkgs.docker}/bin/docker stop zigbee2mqtt || true && ${pkgs.docker}/bin/docker rm -f zigbee2mqtt || true + # start instance + ${pkgs.docker}/bin/docker run \ + --network="host" \ + --name zigbee2mqtt \ + -v ${dataFolder}:/app/data \ + --device=${device} \ + koenkk/zigbee2mqtt + ''; + }; + +} diff --git a/configs/pepe/wifi-access-point.nix b/configs/pepe/wifi-access-point.nix index db5f81f..0204cf6 100644 --- a/configs/pepe/wifi-access-point.nix +++ b/configs/pepe/wifi-access-point.nix @@ -1,14 +1,15 @@ { lib, pkgs, ... }: let - wifi = "wlp0s29u1u2"; - ipAddress = "10.123.145.1"; + wifi = "wlp0s26u1u2"; + ipAddress = "10.23.45.1"; prefixLength = 24; - servedAddressRange = "10.123.145.2,10.123.145.150,12h"; - ssid = "bumbumbum"; - wifiPassword = lib.fileContents ; + servedAddressRange = "10.23.45.2,10.23.45.150,12h"; + ssid = "palosiot"; + wifiPassword = lib.fileContents ; in { + # todo only open needed ports networking.firewall.trustedInterfaces = [ wifi ]; @@ -20,19 +21,10 @@ in { prefixLength = prefixLength; }]; - # forward traffic coming in trough the access point => provide internet and vpn network access - # todo : forward to own servers - boot.kernel.sysctl = { - "net.ipv4.conf.${wifi}.forwarding" = true; - "net.ipv6.conf.${wifi}.forwarding" = true; - }; - systemd.services.hostapd = { description = "hostapd wireless AP"; path = [ pkgs.hostapd ]; - - # start manual - # wantedBy = [ "network.target" ]; + wantedBy = [ "network.target" ]; after = [ "${wifi}-cfg.service" diff --git a/images/remote-install/config.nix b/images/remote-install/config.nix index af37d80..e3951da 100644 --- a/images/remote-install/config.nix +++ b/images/remote-install/config.nix @@ -1,5 +1,6 @@ { pkgs, lib, ... }: let + remote-access = import ../lib/remote-access.nix { # cat ~/.ssh/id_rsa.pub @@ -8,15 +9,24 @@ let # remote-install-get-hiddenReceiver hiddenReceiver = ""; + }; in { imports = [ remote-access ]; # network configuration - networking.networkmanager.enable = true; - networking.wireless.enable = lib.mkForce false; + # --------------------- + # no wifi + #networking.networkmanager.enable = true; + + # wifi + networking.wireless.enable = true; + networking.wireless.networks."ssid".psk = "password"; + + + # configuration environment.extraInit = '' # use vi shortcuts # ---------------- diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix index a6a51f9..991bad4 100644 --- a/modules/services/home-assistant.nix +++ b/modules/services/home-assistant.nix @@ -231,11 +231,11 @@ in { }; input_boolean = mkOption { default = null; - type = with types; (attrsOf attrs); + type = with types; nullOr (attrsOf attrs); }; input_datetime = mkOption { default = null; - type = with types; (attrsOf attrs); + type = with types; nullOr (attrsOf attrs); }; calendar = mkOption { default = [ ]; diff --git a/shell.nix b/shell.nix index 1def696..7d1115a 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,8 @@ let # host used to install stuff. (can be an onion id if you use torify) - installHost = "localhost"; + #installHost = "localhost"; + installHost = "adsf.onion"; #ops = import ../plops ; ops = import ((import { }).fetchgit {