Variable number of actions (using Jinja)

I’m trying to create an automation that’s easy to maintain. Specifically, one where I can create a mapping of “key device” to a list of “value” devices, and I want to say if any of the associated “value” devices are in a different state to their “key” device, the “key” device should re-enforce it’s status.

I do this because sometimes Zigbee signals don’t necessarily get through (in groups). So if I have a group containing, say, 18 devices, it may be that 3 or 4 didn’t change their status with the rest. It happens. I want to run this automation periodically to ‘rectify’ the status of the switch with the devices it controls.

Here is my sample script:

variables:
  switches:
    "light.driveway_lights": [
      "light.post_1_light_small",
      "light.post_1_light_medium",
      "light.post_1_light_tall",
      "light.post_2_light_small",
      "light.post_2_light_medium",
      "light.post_2_light_tall",
      "light.post_3_light_small",
      "light.post_3_light_medium",
      "light.post_3_light_tall",
      "light.post_4_light_small",
      "light.post_4_light_medium",
      "light.post_4_light_tall",
      "light.post_5_light_small",
      "light.post_5_light_medium",
      "light.post_5_light_tall",
      "light.post_6_light_small",
      "light.post_6_light_medium",
      "light.post_6_light_tall",
      "light.driveway_lights_slave",
    ]
    "light.porch_lights": [
      "light.porch_left_lights_small",
      "light.porch_left_lights_medium",
      "light.porch_left_lights_tall",
      "light.porch_right_lights_small",
      "light.porch_right_lights_medium",
      "light.porch_right_lights_tall",
    ]
    "light.rear_door_lights": [
      "light.rear_door_left_light_left",
      "light.rear_door_left_light_right",
      "light.rear_door_right_light_left",
      "light.rear_door_right_light_right",
    ]
    "light.deck_post_lights": [
      "light.deck_post_left_light_small",
      "light.deck_post_left_light_medium",
      "light.deck_post_left_light_tall",
      "light.deck_post_right_light_small",
      "light.deck_post_right_light_medium",
      "light.deck_post_right_light_tall",
    ]

action:
  {%- for switch in switches -%}
  {%- set switch_state = states(switch) -%}
  - if:
    - condition: or
      conditions:
        {%- for entity in switches[switch] -%}
        - condition: device
          {%- if switch_state -%}
          type: is_off
          {%- else -%}
          type: is_on
          {%- endif -%}
          device_id: "{{ device(entity) }}"
          entity_id: "{{ entity }}"
          domain: "{{ entity.split('.')[0] }}"
        {%- endfor -%}
    then:
      {%- if switch_state -%}
      - type: turn_on
      {%- else -%}
      - type: turn_off
      {%- endif -%}
        device_id: "{{ device(switch) }}"
        entity_id: "{{ switch }}"
        domain: "{{ switch.split('.')[0] }}"
  {%- endfor -%}

However, it won’t let me put the jinja code (the for in this case) after the action: - which I need it to be able to expand into multiple if statements.

Sure, I could easily create a separate if statement for each switch mentioned in the variables, but the idea of this is to be easily maintainable. I should be able to add a new entry to ‘switches’ and reload automations and have it ‘Just Work’ ™ to update the actions part.

How would I go about achieving this?

Jinja templates can only be used to define the values in the YAML configuration. It cannot be used to define the keys, or to “build” yaml configuration in situ.

Are your “switches” (example light.driveway_lights) actual switches, light groups defined in HA, or are they ad hoc groups that are only defined in your variables in this automation?

The switches in each case above are actual light switches. Physical devices.

So the values in the above case are all individual (smart) light bulbs. And the switches are physical switches (that are in smart switch mode, so pushing on or off actually sends a group zigbee signal of on or off, which is what turns the light bulbs off).

So turning the switch on or off is exactly the same as me pushing the physical switch on or off. But that’s not electrically connected to the bulbs. Consider the switches more like scene controllers.

Like Didgeridrew explained, you can’t use a Jinja2 template to generate YAML in an automation’s action. Even if it was permissible, it still wouldn’t work because you’re using a Device Action and its options don’t support templating.

What’s your intended goal?

@123 As mentioned - my goal is to check the state of all the bulbs controlled by the switch in question (smart bulbs, smart switch - think of the switch more like a scene controller with an on/off state), and if one of the bulbs is not in the same state as the switch (ie. it’s on but the switch is off or vice versa), then trigger the switch again (in it’s current state, so trigger ‘turn off’ if it’s off, again or ‘turn on’ again if it’s on).

These are all Zigbee devices in a zigbee group. So hitting turn off on the switch actually signals the zigbee group to turn off. Sometimes some bulbs don’t get the message, so this is specifically designed to bring devices in line with what the state SHOULD be by re-triggering that turn off (but turning “off” the switch again, which is actually just sending a zigbee group command).

But, I want to do that in a way that I don’t have to define a separate action per switch manually, but I can use the variable map as I indicated to generate the appropriate actions.
This would be brain dead easy if I just created individual actions, and filled in the bulbs manually in each condition. But that’s hellish to maintain or add to, as opposed to the variable map.

So, a bandaid to cover a Zigbee communication problem?

1 Like

Loops in automations are done using Repeat Actions. To iterate over a list of item you can use the Repeat for Each action. Here’s a basic approach… you can fill in all the other lists:

trigger:
  - platform: ?
condition: []    
action:
- repeat:
    for_each:
      - switch: light.rear_door_lights    
        light_list:
          - light.rear_door_left_light_left
          - light.rear_door_left_light_right
          - light.rear_door_right_light_left
          - light.rear_door_right_light_right
      - switch:     
        light_list:
      - switch:     
        light_list:
    sequence:
      - variables: 
          switch_state: "{{ states(repeat.item.switch) }}"
          problem_lights: >
            {{ repeat.item.light_list 
            | reject('is_state', [switch_state, 'unknown', 'unavailable']) 
            | list }}
      - condition: template
        value_template: "{{ problem_lights | count > 0 }}"
      - service: light.turn_{{ switch_state }}
        data: {}
        target:
          entity_id: "{{ problem_lights }}"

Thanks for that @Didgeridrew - a slightly modified version of that is exactly what I was looking for!

And it’s just as easy to maintain!