1 automation to rule them all

Hi all!

I´ve ordered several zigbee buttons (Sonoff SNZB-01)
and would like to fix my current automation that handles 1 button to be dynamic
and call scripts based on device_ieee but I want my scripts to have better naming convention than **device_ieee + “_click/dblclick/hold”

So I thought a template service calling different scripts depending on device_ieee would be the solution but I can’t get it working.
Am I doing it wrong or is this not possible?

- alias: SNZB-01_XX clicks
  variables:
    device: "-"
  trigger:
    event_type: zha_event
    platform: event
    # Populate with valid device_ieee for SNZB-01 buttons
    event_data:
      device_ieee: 00:12:4b:00:1b:7c:d9:2f
  action:
    - service: <
        "{% if trigger.event.data.device_ieee == '00:12:4b:00:1b:7c:d9:2f' %} {% set device = 'snzb01_01' %} {% endif %}"
        #button2 device_ieee => set device =  SNZB_01_02
        #button3 device_ieee => set device =  SNZB_01_03
        #button4 device_ieee => set device =  SNZB_01_04
        #button5 device_ieee => set device =  SNZB_01_05
        #button6 device_ieee => set device =  SNZB_01_06
    - choose:
        # SINGLE CLICK ACTION
        - conditions:
            - condition: template
              value_template: "{{ trigger.event.data.command == 'toggle' }}"
          sequence:
            - service: "{{ 'script.' + device  + '_clk' }}"              
          # DOUBLE CLICK ACTION
        - conditions:
            - condition: template
              value_template: "{{ trigger.event.data.command == 'on' }}"
          sequence:
            - service: "{{ 'script.' +  device  + '_dblclk' }}"  
          # HOLD CLICK ACTION
        - conditions:
            - condition: template
              value_template: "{{ trigger.event.data.command == 'off' }}"
          sequence:
            - service: "{{ 'script.' +  device  + '_hold' }}"     
      default: []
  mode: single

Follow-up, Can I skip the Choose and do my conditionals inside a service template?
Like this

- service: >
    {% if trigger.event.data.command == 'toggle'  %}  'script.' + device  + '_clk'     {% endif %} 
    {% if trigger.event.data.command == 'on'      %}  'script.' + device  + '_dblclk'  {% endif %} 
    {% if trigger.event.data.command == 'off'     %}  'script.' + device  + '_hold'    {% endif %} 

I think I understand what you’re trying to do and it cannot be done with this thing you’ve invented called a “template service” (it doesn’t exist; there’s no service call to set a variable).

The variable you named device should be defined within action. Its template should compute the value by using trigger.event.data.device_ieee as a key for a map containing each device_ieee and its associated device.

  action:
    - variables:
        device: >
          {% set devices = {'00:12:4b:00:1b:7c:d9:2f': '01', '00:14:23:0a:3e:c5:d8:1c': '02', 
                            '00:1d:23:10:2c:12:d8:1f': '03', '00:11:a3:22:e6:9f:d3:b5': '04', 
                            '00:3f:5b:11:c5:10:e3:1a': '05', '00:a1:5d:21:e1:4b:d3:e6': '06'} %}
          snzb_01_{{ devices[trigger.event.data.device_ieee] }}
    - choose:
        # SINGLE CLICK ACTION
        - conditions:
            - condition: template
              value_template: "{{ trigger.event.data.command == 'toggle' }}"
          sequence:
            - service: "script.{{ device }}_clk"
        ... etc ...

That’s permitted.

- service: >
    {% set commands = {'toggle': 'clk', 'on': 'dblclk', 'off': 'hold' } %}
    script.{{device}}_{{commands[trigger.event.data.command]}}
1 Like

Thanks a bunch, I understand my error!
Will implement this asap.

But if I may, how does one properly set variables inside an action/sequence in order to use them later on?

Is this the one and only and proper way?

- variables:
  var1: ... 
  var2: ... 

With some additional indenting:

- variables:
    var1: ... 
    var2: ... 

If you define a variable the way you originally did, outside of action, the variable is global to the entire automation (visible in condition and action). However, as far as I can recall, it doesn’t have access to the Trigger State Object (in your case trigger.event.data.etc) because that’s generated after the trigger occurs.

If you define a variable inside action it is local to action (i.e. doesn’t exist elsewhere like the condition). In addition, it has access to the Trigger State Object.

Ah but of course… Makes sense…
Thanks, feels like I’m getting a better understanding of yaml with your explanations

Might be late to the party here - but have you considered using Node-Red to accomplish this?

Never tried it, I’ve invested what time I have in learning Home Assistant and Tasmota :+1:

Having some issues here, action dies att the service template… The script to call does exist.
I added an input_text just to capture the generated text

If I add my input_text service before the templated service
I can see what the command looks like, IF I add my input text service after the templated service
it does not get updated so I guess its because the action “dies”

Any clue as to why this is so?

I fiddled some more on my own.

Tried your approach on the device variable with the command, Not sure this is the reason it works but it does work now !

  action:
    - variables:
        device: >
          {% set devices = {'00:12:4b:00:1b:7c:d9:2f': '01', 
                            '00:14:23:0a:3e:c5:d8:1c': '02', 
                            '00:1d:23:10:2c:12:d8:1f': '03'
                            %}
          snzb_01_{{ devices[trigger.event.data.device_ieee] }}
        command: >
          {% set commands = {'toggle': 'click', 'on': 'dblclick', 'off': 'hold' } %}
          {{commands[trigger.event.data.command]}}
    
    - service: script.{{device}}_{{command}}