EnOcean PTM 215Z (Friends of Hue) – Z2M 2.X [MQTT Device Trigger + Hold]

Inspired by my “Schneider Electric 550D6001” blueprint.

Link to Z2M device

Link to Github

Import Blueprint to My

!!! IMPORTANT !!!
Z2M version min. 2.0

blueprint:
  name: EnOcean PTM 215Z (Friends of Hue) – Z2M 2.X [MQTT Device Trigger + Hold]
  description: >
    Uses MQTT device triggers (Z2M 2.X) for 4 buttons on EnOcean PTM 215Z.
    "Held" is derived by waiting for release within hold_delay.
  domain: automation
  author: Keviin Cosmos (modded for EnOcean by Jarvis)

  input:
    #
    # 1) ZIGBEE DEVICE SELECTOR
    #
    zigbee_device:
      name: Zigbee2MQTT device
      description: Select your EnOcean PTM 215Z device (via MQTT integration)
      selector:
        device:
          integration: mqtt

    #
    # 2) OPTIONAL HOLD DELAY
    #
    hold_delay:
      name: Hold delay
      description: If no release arrives within this delay, treat press as "held".
      default: 500
      selector:
        number:
          min: 100
          max: 5000
          unit_of_measurement: milliseconds
          mode: box
          step: 10

    #
    # 3) ACTIONS FOR EACH BUTTON EVENT
    #
    top_left_pressed:
      name: 1. Top Left Pressed (press_1)
      default: []
      selector:
        action: {}

    top_left_held:
      name: 1. Top Left Held (derived)
      default: []
      selector:
        action: {}

    top_left_released:
      name: 1. Top Left Released (release_1)
      default: []
      selector:
        action: {}

    top_right_pressed:
      name: 2. Top Right Pressed (press_2)
      default: []
      selector:
        action: {}

    top_right_held:
      name: 2. Top Right Held (derived)
      default: []
      selector:
        action: {}

    top_right_released:
      name: 2. Top Right Released (release_2)
      default: []
      selector:
        action: {}

    bottom_left_pressed:
      name: 3. Bottom Left Pressed (press_3)
      default: []
      selector:
        action: {}

    bottom_left_held:
      name: 3. Bottom Left Held (derived)
      default: []
      selector:
        action: {}

    bottom_left_released:
      name: 3. Bottom Left Released (release_3)
      default: []
      selector:
        action: {}

    bottom_right_pressed:
      name: 4. Bottom Right Pressed (press_4)
      default: []
      selector:
        action: {}

    bottom_right_held:
      name: 4. Bottom Right Held (derived)
      default: []
      selector:
        action: {}

    bottom_right_released:
      name: 4. Bottom Right Released (release_4)
      default: []
      selector:
        action: {}

mode: single
max_exceeded: silent

#
# TRIGGERS (MQTT DEVICE TRIGGERS)
# EnOcean PTM 215Z action strings: press_1..4, release_1..4
#
trigger:
  # TOP LEFT
  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: press_1
    id: top_left_press

  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: release_1
    id: top_left_release

  # TOP RIGHT
  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: press_2
    id: top_right_press

  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: release_2
    id: top_right_release

  # BOTTOM LEFT
  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: press_3
    id: bottom_left_press

  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: release_3
    id: bottom_left_release

  # BOTTOM RIGHT
  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: press_4
    id: bottom_right_press

  - platform: device
    device_id: !input zigbee_device
    domain: mqtt
    type: action
    subtype: release_4
    id: bottom_right_release

#
# ACTIONS
# For each press: wait for the matching release with timeout = hold_delay.
# If release arrives in time -> run "...pressed"; if not -> run "...held".
# Release events still fire their own "...released" actions.
#
action:
  - choose:
      # -------- TOP LEFT --------
      - conditions: [{ condition: trigger, id: top_left_press }]
        sequence:
          - wait_for_trigger:
              - platform: device
                device_id: !input zigbee_device
                domain: mqtt
                type: action
                subtype: release_1
            timeout:
              milliseconds: !input hold_delay
          - choose:
              - conditions: "{{ wait.trigger is not none }}"
                sequence: !input top_left_pressed
              - conditions: "{{ wait.trigger is none }}"
                sequence: !input top_left_held

      - conditions: [{ condition: trigger, id: top_left_release }]
        sequence: !input top_left_released

      # -------- TOP RIGHT --------
      - conditions: [{ condition: trigger, id: top_right_press }]
        sequence:
          - wait_for_trigger:
              - platform: device
                device_id: !input zigbee_device
                domain: mqtt
                type: action
                subtype: release_2
            timeout:
              milliseconds: !input hold_delay
          - choose:
              - conditions: "{{ wait.trigger is not none }}"
                sequence: !input top_right_pressed
              - conditions: "{{ wait.trigger is none }}"
                sequence: !input top_right_held

      - conditions: [{ condition: trigger, id: top_right_release }]
        sequence: !input top_right_released

      # -------- BOTTOM LEFT --------
      - conditions: [{ condition: trigger, id: bottom_left_press }]
        sequence:
          - wait_for_trigger:
              - platform: device
                device_id: !input zigbee_device
                domain: mqtt
                type: action
                subtype: release_3
            timeout:
              milliseconds: !input hold_delay
          - choose:
              - conditions: "{{ wait.trigger is not none }}"
                sequence: !input bottom_left_pressed
              - conditions: "{{ wait.trigger is none }}"
                sequence: !input bottom_left_held

      - conditions: [{ condition: trigger, id: bottom_left_release }]
        sequence: !input bottom_left_released

      # -------- BOTTOM RIGHT --------
      - conditions: [{ condition: trigger, id: bottom_right_press }]
        sequence:
          - wait_for_trigger:
              - platform: device
                device_id: !input zigbee_device
                domain: mqtt
                type: action
                subtype: release_4
            timeout:
              milliseconds: !input hold_delay
          - choose:
              - conditions: "{{ wait.trigger is not none }}"
                sequence: !input bottom_right_pressed
              - conditions: "{{ wait.trigger is none }}"
                sequence: !input bottom_right_held

      - conditions: [{ condition: trigger, id: bottom_right_release }]
        sequence: !input bottom_right_released

    default: []

Import is not possible, at last for me via import

Also are you using the current version of Home Assistant?

In what way

?

Yes Z2M is 2.6.0, HA is 2025.8.1

I think Link is wrong

Aah, yes you are right…

@KeviinCosmos
The link name in the GIST has spaces and parenthesis & brackets & plus sign. If you want the My Link to work then clean that up a bit.

@KeviinCosmos This is great! I’m working on cutting over my whole setup from DeCONZ/Phoscon over to Zigbee2MQTT, and stumbled upon this blueprint!

I’d actually built a similar blueprint for this device (but for the DeCONZ integration instead of Z2M). In that version, I was able to code in some behavior that also allowed for a “held” trigger to repeat, which was reallly helpful for holding a switch to modify brightness.

I wonder if something like that could be integrated into this blueprint! (I might take a crack at it on that repo I linked.

Anyways, thanks for sharing this!