Skip to content

Instantly share code, notes, and snippets.

@narektutikian
Last active October 22, 2025 19:38
Show Gist options
  • Select an option

  • Save narektutikian/6e00b3e59d9ddfd2b148174fd3efb7e8 to your computer and use it in GitHub Desktop.

Select an option

Save narektutikian/6e00b3e59d9ddfd2b148174fd3efb7e8 to your computer and use it in GitHub Desktop.
Zigbee2MQTT - Tuya 4-Button Scene Switch TS004F
blueprint:
name: NT Zigbee2MQTT - Tuya 4-Button Scene Switch TS004F
description: Automate your Tuya 4-Button Scene Switch (TS004F) via Zigbee2MQTT.
domain: automation
input:
switch:
name: TS004F Switch
description: Tuya 4-Button Scene Switch to use
selector:
entity:
domain:
- sensor
integration: mqtt
multiple: false
button_one_short_press:
name: Single Press - Button 1
description: Action to run on button 1 (upper-left) single press
default: []
selector:
action: {}
button_one_hold:
name: Hold - Button 1
description: Action to run on button 1 (upper-left) single press
default: []
selector:
action: {}
button_one_double_press:
name: Double Press - Button 1
description: Action to run on button 1 (upper-left) single press
default: []
selector:
action: {}
button_two_hold:
name: Hold - Button 2
description: Action to run on button 2 (upper-right) single press
default: []
selector:
action: {}
button_two_double_press:
name: Double Press - Button 2
description: Action to run on button 2 (upper-right) single press
default: []
selector:
action: {}
button_two_short_press:
name: Single Press - Button 2
description: Action to run on button 2 (lower-right) single press
default: []
selector:
action: {}
button_three_short_press:
name: Single Press - Button 3
description: Action to run on button 3 (lower-left) single press
default: []
selector:
action: {}
button_three_hold:
name: Hold - Button 3
description: Action to run on button 3 (lower-left) long press
default: []
selector:
action: {}
button_three_double_press:
name: Double Press - Button 3
description: Action to run on button 3 (lower-left) long press
default: []
selector:
action: {}
button_four_short_press:
name: Single Press - Button 4
description: Action to run on button 4 (lower-right) single press
default: []
selector:
action: {}
button_four_hold:
name: Long Press - Button 4
description: Action to run on button 4 (lower-right) long press
default: []
selector:
action: {}
button_four_double_press:
name: Double Press - Button 4
description: Action to run on button 4 (lower-right) long press
default: []
selector:
action: {}
source_url: https://gist.github.com/narektutikian/6e00b3e59d9ddfd2b148174fd3efb7e8
mode: single
max_exceeded: silent
variables:
# The entity the user picks in the blueprint (e.g. sensor.nnjaran_scene_switch_action)
switch_entity: !input switch
# Robust device slug for Z2M topic: strip the last _suffix (action/battery/linkquality/voltage/etc.)
device_slug: "{{ switch_entity.split('.')[1].rsplit('_', 1)[0] }}"
topic: "{{ trigger.topic }}"
# Safe JSON handle (may be None on legacy '1_single' messages)
pj: "{{ trigger.payload_json if trigger.payload_json is defined else None }}"
# Action string from JSON or legacy raw payload
command: >-
{% if pj is not none and 'action' in pj %}
{{ pj['action'] }}
{% else %}
{{ trigger.payload }}
{% endif %}
# Button index from JSON fields or from legacy "1_single"
button_index: >-
{% if pj is not none and 'button' in pj %}
{{ pj['button']|int }}
{% elif pj is not none and 'endpoint' in pj %}
{{ pj['endpoint']|int }}
{% elif pj is not none and 'button_id' in pj %}
{{ pj['button_id']|int }}
{% elif '_' in command %}
{{ command.split('_')[0]|int }}
{% else %}
0
{% endif %}
# Normalize to single/double/hold
press_type: >-
{% if '_' in command %}
{{ command.split('_')[-1] }}
{% else %}
{{ command }}
{% endif %}
# Exact match against the action topic for THIS device
topic_ok: "{{ topic == ('zigbee2mqtt/' ~ device_slug ~ '/action') }}"
trigger:
- platform: mqtt
topic: zigbee2mqtt/+/action
action:
- choose:
- conditions:
- condition: template
value_template: "{{ topic_ok }}"
sequence:
- choose:
# Button 1
- conditions:
- condition: template
value_template: "{{ button_index == 1 and press_type == 'single' }}"
sequence: !input button_one_short_press
- conditions:
- condition: template
value_template: "{{ button_index == 1 and press_type == 'double' }}"
sequence: !input button_one_double_press
- conditions:
- condition: template
value_template: "{{ button_index == 1 and press_type in ['hold','long','long_press'] }}"
sequence: !input button_one_hold
# Button 2
- conditions:
- condition: template
value_template: "{{ button_index == 2 and press_type == 'single' }}"
sequence: !input button_two_short_press
- conditions:
- condition: template
value_template: "{{ button_index == 2 and press_type == 'double' }}"
sequence: !input button_two_double_press
- conditions:
- condition: template
value_template: "{{ button_index == 2 and press_type in ['hold','long','long_press'] }}"
sequence: !input button_two_hold
# Button 3
- conditions:
- condition: template
value_template: "{{ button_index == 3 and press_type == 'single' }}"
sequence: !input button_three_short_press
- conditions:
- condition: template
value_template: "{{ button_index == 3 and press_type == 'double' }}"
sequence: !input button_three_double_press
- conditions:
- condition: template
value_template: "{{ button_index == 3 and press_type in ['hold','long','long_press'] }}"
sequence: !input button_three_hold
# Button 4
- conditions:
- condition: template
value_template: "{{ button_index == 4 and press_type == 'single' }}"
sequence: !input button_four_short_press
- conditions:
- condition: template
value_template: "{{ button_index == 4 and press_type == 'double' }}"
sequence: !input button_four_double_press
- conditions:
- condition: template
value_template: "{{ button_index == 4 and press_type in ['hold','long','long_press'] }}"
sequence: !input button_four_hold
default:
- service: system_log.write
data:
level: warning
logger: blueprint.ts004f
message: >
TS004F UNMATCHED: command={{ command }},
btn={{ button_index }}, type={{ press_type }},
topic={{ topic }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment