{ pkgs, lib, config, ... }: let # allow new devices to join enablePairing = false; 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"; "motion_sensor_2".id = "0x00158d0002f9a6b8"; "motion_sensor_3".id = "0x00158d0002f04522"; "motion_sensor_4".id = "0x00158d0002f9a558"; "motion_sensor_5".id = "0x00158d0002f9a56f"; "motion_sensor_6".id = "0x00158d0002f9a5cb"; "motion_sensor_7".id = "0x00158d0002f9a6aa"; "motion_sensor_8".id = "0x00158d0002f04637"; }; door = { "door_sensor_1".id = "0x00158d000312dc52"; "door_sensor_2".id = "0x00158d000316d5bf"; "door_sensor_3".id = "0x00158d0002f9516f"; "door_sensor_4".id = "0x00158d00031383b9"; "door_sensor_5".id = "0x00158d0003120d3e"; }; }; # todo : generate automatically allSensors = with sensors; buttons // temperature // motion // door; 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 = { # define sensors # -------------- sensor = let # define button sensors 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; # define temperature sensors 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; # define meta information sensors informations = lib.mapAttrsToList (name: { ... }: [ { name = "battery_${name}"; platform = "mqtt"; state_topic = "zigbee2mqtt/${name}"; availability_topic = "zigbee2mqtt/bridge/state"; unit_of_measurement = "%"; icon = "mdi:battery-10"; value_template = "{{ value_json.battery }}"; } { name = "link_${name}"; platform = "mqtt"; state_topic = "zigbee2mqtt/${name}"; availability_topic = "zigbee2mqtt/bridge/state"; icon = "mdi:signal"; unit_of_measurement = "lqi"; value_template = "{{ value_json.linkquality }}"; } ]) allSensors; in lib.flatten (buttons ++ temperature ++ informations); # define binary sensors # --------------------- binary_sensor = let # define motion sensors # --------------------- motion = lib.mapAttrsToList (name: { ... }: { name = name; platform = "mqtt"; device_class = "motion"; state_topic = "zigbee2mqtt/${name}"; availability_topic = "zigbee2mqtt/bridge/state"; payload_on = true; payload_off = false; value_template = "{{ value_json.occupancy }}"; }) sensors.motion; # define door sensors # ------------------- door = lib.mapAttrsToList (name: { ... }: { name = name; platform = "mqtt"; device_class = "door"; state_topic = "zigbee2mqtt/${name}"; availability_topic = "zigbee2mqtt/bridge/state"; payload_on = false; payload_off = true; value_template = "{{ value_json.contact}}"; }) sensors.door; in lib.flatten (motion ++ door); # create groups # ------------- # to have nice panels for every device group = let information = name: [ "sensor.battery_${name}" "sensor.link_${name}" ]; sensorButtons = 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); sensorMotions = lib.mapAttrs' (name: { ... }: { name = name; value = { control = "hidden"; entities = [ "binary_sensor.${name}" ] ++ (information name); }; }) (sensors.motion); sensorDoors = lib.mapAttrs' (name: { ... }: { name = name; value = { control = "hidden"; entities = [ "binary_sensor.${name}" ] ++ (information name); }; }) (sensors.door); views = { view_sensors = { name = "Sensoren"; control = "hidden"; view = true; entities = lib.mapAttrsToList (name: { ... }: "group.${name}") allSensors; }; }; in views // sensorButtons // sensorMotions // sensorTemperature // sensorDoors // { all_sensors.entities = (lib.mapAttrsToList (name: { ... }: "sensor.${name}") (sensors.buttons // sensors.temperature)) ++ (lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") (sensors.motion // sensors.door)); }; # create automation # ----------------- # todo : this belongs in the home-assistant.nix automation = let # hold, turn off the lights everywhere all_lights_off = map (button: { alias = "turn all lights off on holding a button"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${button}"; }; condition = { condition = "template"; value_template = ''{{ "hold" == trigger.payload_json.action }}''; }; action = { service = "script.turn_all_off"; }; }) [ "button_1" "button_2" "button_3" ]; # one click, turn on the light in the room room_lights_on = map ({ button, room }: { alias = "turn on lights in ${room}, on ${button} click"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${button}"; }; condition = { condition = "template"; value_template = ''{{ "single" == trigger.payload_json.click }}''; }; action = { service = "switch.turn_on"; entity_id = "group.${room}"; }; }) [ { button = "button_1"; room = "living_room"; } { button = "button_2"; room = "bed_room"; } { button = "button_3"; room = "bed_room"; } ]; # double click, turn off the light in the room room_lights_off = map ({ button, room }: { alias = "turn on lights in ${room}, on ${button} click"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${button}"; }; condition = { condition = "template"; value_template = ''{{ "double" == trigger.payload_json.click }}''; }; action = { service = "switch.turn_off"; entity_id = "group.${room}"; }; }) [ { button = "button_1"; room = "living_room"; } { button = "button_2"; room = "bed_room"; } { button = "button_3"; room = "bed_room"; } ]; # kitchen light automation # ------------------------ # https://www.home-assistant.io/integrations/binary_sensor.template/ kitchen_lights = map (motion: [ { alias = "turn on kitchen lights, on motion detected"; trigger = { platform = "state"; entity_id = "binary_sensor.${motion}"; from = "off"; to = "on"; }; action = { service = "switch.turn_on"; entity_id = "group.kitchen_room"; }; } { alias = "turn off kitchen lights, on motion clear"; trigger = { platform = "state"; entity_id = "binary_sensor.${motion}"; from = "on"; to = "off"; }; action = { service = "switch.turn_off"; entity_id = "group.kitchen_room"; }; } ]) [ "motion_sensor_1" ]; in lib.flatten (kitchen_lights ++ all_lights_off ++ room_lights_on ++ room_lights_off); # click = double => music an aus # click = hold => film an aus }; # manage zigbee2mqtt # ------------------ # todo : einen eigenen container bauen mit dockerTool : https://nixos.wiki/wiki/Docker virtualisation.docker.enable = true; 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 ''; }; }