{ pkgs, lib, ... }: let # we create 3 input_boolean which get toggled by the 3 types of buttons pressed. # input_boolean.single_${name} : single click # input_boolean.double_${name} : double click # input_boolean.hold_${name} : hold # if you override these input (via states) you have to create the input yourself # https://www.zigbee2mqtt.io/devices/WXKG12LM.html allDevices = { "button_1" = { id = "0x00158d0002b04f65"; # states = { click = "input_boolean.living_room_button"; } # input state to hold (optional) (default "input_boolean.single_${name}") groups = [ "living_room" "living_room_present" ]; }; "button_2" = { id = "0x00158d0002b04f09"; groups = [ "bed_room" "bed_room_present" ]; states.single = "input_boolean.bed_room_buttons"; }; "button_3" = { id = "0x00158d0002b00e04"; groups = [ "bed_room" "bed_room_present" ]; states.single = "input_boolean.bed_room_buttons"; }; }; in { services.zigbee2mqtt.devices = lib.mapAttrs' (name: { id, ... }: { name = id; value = { retain = false; friendly_name = name; }; }) allDevices; services.homeAssistantConfig = { # define input_boolean # -------------------- # which get toggled by the buttons input_boolean = let stripEmpty = lib.filter (a: a != { }); in builtins.listToAttrs (stripEmpty (lib.flatten (lib.mapAttrsToList (name: { states ? { }, ... }: [ (lib.optionalAttrs (!lib.hasAttr "single" states) { name = "single_${name}"; value = { icon = "mdi:toggle-switch"; }; }) (lib.optionalAttrs (!lib.hasAttr "double" states) { name = "double_${name}"; value = { icon = "mdi:toggle-switch"; }; }) (lib.optionalAttrs (!lib.hasAttr "hold" states) { name = "hold_${name}"; value = { icon = "mdi:toggle-switch"; }; }) ]) allDevices))); # define meta information sensors sensor = lib.flatten (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 }}"; } { 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 }}"; } ]) allDevices); binary_sensor = 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 }}"; }) allDevices; # create groups # ------------- group = let # to have nice panels for every device sensorGroups = lib.mapAttrs (name: { states ? { }, ... }: let entityIds = { single ? "input_boolean.single_${name}" , double ? "input_boolean.double_${name}" , hold ? "input_boolean.hold_${name}", ... }: [ single double hold ]; in { control = "hidden"; entities = [ "sensor.${name}" ] ++ (entityIds states) ++ [ "sensor.battery_${name}" "sensor.link_${name}" ]; }) allDevices; # sort lights into given groups. sortedInGroups = let groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name: { groups ? [ ], states ? { }, ... }: map (groupName: { "${groupName}" = if (lib.hasAttr "single" states) then states.single else "input_boolean.single_${name}"; }) groups) allDevices)); in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries; in sortedInGroups // sensorGroups // { all_sensors.entities = lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") allDevices; }; # create automation # ----------------- automation = let # single click toggle_single_button_input = lib.mapAttrsToList (name: { states ? { }, ... }: let entityId = if (lib.hasAttr "single" states) then states.single else "input_boolean.single_${name}"; in { alias = "toggle single click ${name}"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${name}"; }; condition = { condition = "template"; value_template = ''{{ "single" == trigger.payload_json.click}}''; }; action = { service = "input_boolean.toggle"; data.entity_id = entityId; }; }) allDevices; # double click toggle_double_button_input = lib.mapAttrsToList (name: { states ? { }, ... }: let entityId = if (lib.hasAttr "double" states) then states.double else "input_boolean.double_${name}"; in { alias = "toggle double click ${name}"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${name}"; }; condition = { condition = "template"; value_template = ''{{ "double" == trigger.payload_json.click}}''; }; action = { service = "input_boolean.toggle"; data.entity_id = entityId; }; }) allDevices; # hold toggle_hold_button_input = lib.mapAttrsToList (name: { states ? { }, ... }: let entityId = if (lib.hasAttr "hold" states) then states.hold else "input_boolean.hold_${name}"; in { alias = "toggle hold ${name}"; trigger = { platform = "mqtt"; topic = "zigbee2mqtt/${name}"; }; condition = { condition = "template"; value_template = ''{{ "hold" == trigger.payload_json.action}}''; }; action = { service = "input_boolean.toggle"; data.entity_id = entityId; }; }) allDevices; in lib.flatten (toggle_single_button_input ++ toggle_double_button_input ++ toggle_hold_button_input); }; }