Instantly share code, notes, and snippets.
Last active
October 22, 2025 19:38
-
Star
0
(0)
You must be signed in to star a gist -
Fork
1
(1)
You must be signed in to fork a gist
-
-
Save narektutikian/6e00b3e59d9ddfd2b148174fd3efb7e8 to your computer and use it in GitHub Desktop.
Zigbee2MQTT - Tuya 4-Button Scene Switch TS004F
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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