Using the new action events in Zigbee2MQTT 2.0

The new Zigbee2MQTT 2.0 introduces the new event based actions for things with buttons. And at the same time deprecates the old way of using action sensors.

However, it seems the Zigbee2MQTT devs have pulled back on the plan to remove the legacy sensor based method, so for now users can start to play with the events but it may be best to keep things as they are and re-enable things as they are by turning on Home Assistant legacy actions sensors from the Zigbee2MQTT UI (Settings)

You can still use device triggers which most of us hate with a passion because it uses some ugly long devive IDs that no human can associate with anything and will change is you replace a device. Ugly ugly.

The new way is pretty cool. It was introduced as beta in the December release but with Zigbee2MQTT 2.0 it was supposed to be official, but the developers admit that it is still work in progress.

The new actions that are created start with event entities. Prefix event. These change state when buttons are pressed and attributes of the event sensor defines what changed. Each type of remote or switch does it differently but the principle is the same.

Let us take an example with a Philips Hue 4 button dimmer switch. The example implements both short and long press and up/down dimming the Zigbee2MQTT optimal way. In this example the light.bedroom is a group defined in Zigbee2MQTT and the background lights are some additional lights that can be turned on and off by long press.

alias: Bedroom Dimmer
triggers:
  - trigger: state
    entity_id: event.bedroom_switch_action
    not_from: unavailable
    #Do not put any To or From or Attribute lines in trigger.
    #If you do, you cannot push same button twice. Very important
actions:
  - choose:
      - conditions:
          - "{{trigger.to_state.attributes.button == 'on'}}"
          - "{{trigger.to_state.attributes.event_type == 'press'}}"
        sequence:
          - data:
              entity_id:
                - light.bedroom
              brightness_pct: 50
            action: light.turn_on
      - conditions:
          - "{{trigger.to_state.attributes.button == 'on'}}"
          - "{{trigger.to_state.attributes.event_type == 'hold'}}"
        sequence:
          - data:
              entity_id:
                - light.bedroom
                - light.bedroom_desk
                - light.background
              brightness_pct: 100
            action: light.turn_on
      - conditions:
          - "{{trigger.to_state.attributes.button == 'up'}}"
          - "{{trigger.to_state.attributes.event_type == 'hold'}}"
        sequence:
          - action: mqtt.publish
            metadata: {}
            data:
              topic: zigbee2mqtt/Bedroom/set
              payload: "{\"brightness_move\": 50 }"
      - conditions:
          - "{{trigger.to_state.attributes.button == 'down'}}"
          - "{{trigger.to_state.attributes.event_type == 'hold'}}"
        sequence:
          - action: mqtt.publish
            metadata: {}
            data:
              topic: zigbee2mqtt/Bedroom/set
              payload: "{\"brightness_move\": -50 }"
      - conditions:
          - "{{trigger.to_state.attributes.button in ('up', 'down')}}"
          - "{{trigger.to_state.attributes.event_type == 'hold_release'}}"
        sequence:
          - action: mqtt.publish
            metadata: {}
            data:
              topic: zigbee2mqtt/Bedroom/set
              payload: "{\"brightness_move\": 0 }"
      - conditions:
          - "{{trigger.to_state.attributes.button == 'off'}}"
          - "{{trigger.to_state.attributes.event_type == 'press'}}"
        sequence:
          - data:
              entity_id:
                - light.bedroom
            action: light.turn_off
      - conditions:
          - condition: template
            value_template: "{{trigger.to_state.attributes.button == 'off'}}"
          - condition: template
            value_template: "{{trigger.to_state.attributes.event_type == 'hold'}}"
        sequence:
          - data:
              entity_id:
                - light.bedroom
                - light.bedroom_desk
                - light.background
            action: light.turn_off
initial_state: "on"
mode: queued
max_exceeded: silent

Here is an example using an IKEA 2 button switch

alias: Office Blinds Switch
triggers:
  - trigger: state
    entity_id: event.office_blinds_switch_action
    not_from: unavailable
    #Do not put any To or From or Attribute lines in trigger.
    #If you do, you cannot push same button twice. Very important
actions:
  - choose:
      - conditions:
          - "{{trigger.to_state.attributes.event_type == 'brightness_move_up'}}"
        sequence:
          - data:
              topic: office-blinds/set
              payload: "50"
            action: mqtt.publish
      - conditions:
          - "{{trigger.to_state.attributes.event_type == 'brightness_move_down'}}"
        sequence:
          - data:
              topic: office-blinds/set
              payload: "0"
            action: mqtt.publish
      - conditions:
          - "{{trigger.to_state.attributes.event_type == 'on'}}"
        sequence:
          - data:
              topic: office-blinds/step
              payload: "10"
            action: mqtt.publish
      - conditions:
          - condition: template
            value_template: "{{trigger.to_state.attributes.event_type == 'off'}}"
        sequence:
          - data:
              topic: office-blinds/step
              payload: "-10"
            action: mqtt.publish
initial_state: "on"
mode: queued
max_exceeded: silent

To find the attributes, go to HA Developer Tools ā†’ States
Find the event entity for the switch/remote. You can see in the attributes in the right column

This is my Philips 4 button dimmer

event_types: press, press_release, hold, hold_release
event_type: press_release
button: off
icon: mdi:gesture-double-tap
friendly_name: Bedroom Switch Action

The event_types lists the possible event_types. The event_type shows the last received event. And the button shows which button was pressed.

Not all devices have a button attribute. They only use the event_type. I even have a remote where all buttons make an event_type uniqie to each button. Except for long press where the event_type becomes hold and you have to use the button attribute to see which button is held. That is one bad example I have seen this confusing way. Normally it is either event_type of a combination of event_type and button.

I think it is pretty well made. Much better than the deconz_event with mysterious 4 digit numbers I came from.

I hope this is a help.

Important updates from discussion below

It seems the new event feature is not enabled in 2.0 by default. At least not for upgraders. Make sure that in the Zigbee2MQTT configuration.yaml (not HA and not addon config) you set Zigbee2MQTT setting
Home Assistant experimental event entitiesā€™ to on

If you want the old behavior you also enable ā€˜Home Assistant legacy triggersā€™

Do not try to put any from or to or attribute for the trigger. This is important! The events will not trigger unless the value changes from something else to the value given in ā€œtoā€ or ā€œattributeā€. The result is that same button on a remote only works once until another button is pressed or you long press. Only trigger on the event entity itself.

Edit 2. Simplified the examples using the not_from: unavailable instead of the condition. Thanks for that elegant solution @seblu

14 Likes

This seems like a massive headache to me. I use Node Red, and could previously just select a button action and create a flow with it. No longer it seems.

2 Likes

The Zigbee2MQTT devs seems to know that the new feature needs more work and extended the deprecation period of the old way. Just enable the legacy way again and wait for a better way for Node Red etc.

Iā€™d hope this topic to be a help topic with solutions so if others have more examples of other switches, paste them in follow up messages to this topic. The more working verified examples we have the easier it will be to migrate. And if there are Node Red examples please go ahead. I do not use Node Red so I cannot give any examples.

1 Like

Hi
I have a Philipps 4 button dimmer
Can you explain how to find the event entity for the switch/remote from HA Developer Tools ā†’ States
I donā€™t see any event in this page for my Philipps device

Did you upgrade to Zigbee2MQTT 2.0?

Also restart HA and refresh browser cache may be needed sometimes

yes i did it and still nothing

First lets see if it is supposed to be there

If you go to Integrations ā†’ MQTT and find your device. Click on it.

You should see something like this for a 4-button Hue switch

Note that there is an Events window in center column at the top.

You should see an Action device there.

Unfortunately there is no UI in this view that can show attributes. You have to go to developer tools ā†’ States (NOT Actions!)

In the top of Filter Entities you can type event. and you should see your remotes

Here are a sniplet of mine

2 Likes

Strange it is not really the same thing

1 Like

Something is wrong. Your screen looks like before Zigbee2MQTT 2.0. It is not picking up the changes.

Look at your setttings in zigbee2mqtt.

If you want events to show up, select ā€œHome Assistant experimental even entitiesā€.
You can also select ā€œHome Assistant legacy action sensorsā€ and all is working as before the upgrade tot zigbee2mqtt 2.0

6 Likes

perfect thank you

I set that already in the December release and assumed it was on by default on a 2.0. It is not experimental any longer.

Hi everyone, since i struggled for an hour or so to find a solution for my Hue Switch and bridge my existing flows in node-red with the new event types, i am sharing the below for reference and hopefully helping someone in the process.

In the past i was getting on my hue dimmer a payload like
ā€œon_press_releaseā€ or ā€œoff_press_releaseā€ etc for each button i was using. This msg was then passed to a switch node and depending on the payload different actions were activated.

On my exploration of the message received from the new events, i realized that i wanted to refer to the msg.data.new_state.attributes.button and msg.data.new_state.attributes.event type which they hold the information i needed for the switch node to work. So, i wrote a small function that gets the msg data from the message and jointed the values to create the old behaviour, while keeping the new changes as is.

// Example: Node-RED Function node
// Assume the incoming msg contains data in msg.data.new_state

const newState = msg.data.new_state;

if (newState && newState.attributes) {
    const buttonValue = newState.attributes.button;
    const eventType = newState.attributes.event_type;

    // If both properties exist, create a combined string.
    if (buttonValue && eventType) {
        msg.payload = `${buttonValue}_${eventType}`;
    } else {
        // If either property is missing, handle it gracefully.
        msg.payload = null;
    }
} else {
    // If msg.data.new_state or .attributes is missing, handle it.
    msg.payload = null;
}

// Return the updated message.
return msg;

For this to work, i use an event node for the device action entity, i pass the event to this function node, and the output to my switch which i handled the different actions.

I hope this will help someone like me to cope with the new changes.

2 Likes

Thanks @KennethLavrsen for the write-up. I tried this out earlier today but instead using the example YAML provided at Event - Home Assistant

In the couple of hours since I set that up I had been seeing a lot of ā€œghost eventsā€ where lights were toggled on without actual button presses. According to the logbook it was due to state of the event.xyz entity changing but without any more detail than that. Is this because I didnā€™t include a condition for ā€œunavailableā€, or maybe the "to: null" part of the trigger?

Iā€™ve since reverted to using mqtt triggers, which so far seem to be working ok and donā€™t require a lot of code refactoring:

    - trigger: mqtt
      topic: "zigbee2mqtt/Kitchen Xiaomi Cube White/action"
      payload: "tap"

The topic you refer to seems written with ZHA in mind.

This start of the automation

triggers:
  - trigger: state
    entity_id: event.bedroom_switch_action
    to: null
conditions:
  - condition: template
    value_template: "{{trigger.from_state.state != 'unavailable'}}"

comes from the newly added documentation for Zigbee2MQTT so I am sure the extra bits added there are added for a good reason.

Yes, you can also use the old MQTT way. I never tried that so I cannot say if it would be easier or more difficult. There must be a reason the event way was added to Zigbee2MQTT. The old binary_sensor way was always marked as not recommended and to be deprecated so that is why I was avoiding it.

So, just a quick question for confirmation.

In order to prepare for the move to 2.0, is this considered best practice?

  1. In the Zigbee2MQTT settings, I enable ā€˜Home Assistant experimental event entitiesā€™ but keep the ā€˜Home Assistant legacy triggersā€™ box ticked still.

  2. Restart Zigbee2MQTT

  3. Change the YAML code from

alias: BTN_07 Double Click 4 Printer
description: ""
mode: single
triggers:
  - entity_id: sensor.xa_btn_07_action
    to: double
    trigger: state
conditions: []
actions:
  - data: {}
    target:
      entity_id: switch.officeplug_6
    action: switch.toggle

to

alias: BTN_07 Double Click 4 Printer
description: ""
mode: single
triggers:
  - trigger: state
    entity_id:
      - event.xa_btn_07_action
    to: double
    attribute: action
conditions: []
actions:
  - data: {}
    target:
      entity_id: switch.officeplug_6
    action: switch.toggle
  1. Test & Ready to go!

  2. Once Iā€™ve done this for all my sensor actions I upgrade to Z2M 2.0 and Iā€™m fine?

Or do I also need to make changes to MQTT topics and/or anything else?

Addition after seeing the last post:

Should I add this condition to all automations as well?

conditions:
  - condition: template
    value_template: "{{trigger.from_state.state != 'unavailable'}}"

I noted when I enabled some entities of a Zigbee2MQTT device that the entire MQTT integration goes off and on on again making 1000+ entities go unavailable for a short moment. It seems to avoid a lot of false triggers of automations to have that extra condition. I can think of many examples where we upgrade Zigbee2MQTT or MQTT server itself where we have a lot of events going to unavailable and back.

1 Like

After zigbee2MQTT 2.0 upgrade it died.

zigbee2MQTT now states it cannot find the network address of smlight.

The smlight integration in Home Assistant is finding it fine.


13)
    at start (/app/index.js:161:5)
[19:21:53] INFO: Preparing to start...
[19:21:53] INFO: Socat not enabled
[19:21:54] INFO: Starting Zigbee2MQTT...
Starting Zigbee2MQTT without watchdog.
[2025-01-04 19:21:55] error: 	z2m: Error while starting zigbee-herdsman
[2025-01-04 19:21:55] error: 	z2m: Failed to start zigbee-herdsman
[2025-01-04 19:21:55] error: 	z2m: Check https://www.zigbee2mqtt.io/guide/installation/20_zigbee2mqtt-fails-to-start_crashes-runtime.html for possible solutions
[2025-01-04 19:21:55] error: 	z2m: Exiting...
[2025-01-04 19:21:55] error: 	z2m: Error: Cannot discover TCP adapters at this time. Specify valid 'adapter' and 'port' in your configuration.
    at findTCPAdapter (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/adapter/adapterDiscovery.ts:470:15)
    at discoverAdapter (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/adapter/adapterDiscovery.ts:496:26)
    at Function.create (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/adapter/adapter.ts:68:54)
    at Controller.start (/app/node_modules/.pnpm/zigbee-herdsman@3

Trying to figure it now.

Specify your adapter in the config

SLZB-06 over Ethernet was working great prior to 2.0
:frowning: