How to generalize a verbose automation with a template group iteration

Hi guys,

I’ve got a ZoneMinder camera array and I’ve built a bunch of automations that control the recording state for the cameras (to disable recording when fog, snow or shadows in the wrong spot, etc.) and it works very well but I’ve noticed that when I restart Home Assistant the states can get out of sync. The global and local controls for each camera say that the camera is enabled but the actual ZoneMinder state is disabled.

Because of this I wrote an automation to force an update of ZoneMinder on a restart of Home Assistant to sync everything up. It works, but I’d like to make it more generic (not specifying all the independent cameras within the automation). Right now it looks like this:

  - id: cameras_update_states_on_restart
    alias: Cameras Update States on Restart
    initial_state: true
    trigger:
      - platform: homeassistant
        event: start
    action:
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_back_yard_global_control', 'on') and is_state('input_boolean.cameras_back_yard_control', 'on') ) else 'off' }}
        entity_id: switch.back_yard_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_west_yard_global_control', 'on') and is_state('input_boolean.cameras_west_yard_control', 'on') ) else 'off' }}
        entity_id: switch.west_yard_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_east_yard_global_control', 'on') and is_state('input_boolean.cameras_east_yard_control', 'on') ) else 'off' }}
        entity_id: switch.east_yard_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_front_door_global_control', 'on') and is_state('input_boolean.cameras_front_door_control', 'on') ) else 'off' }}
        entity_id: switch.front_door_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_garage_global_control', 'on') and is_state('input_boolean.cameras_garage_control', 'on') ) else 'off' }}
        entity_id: switch.garage_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_out_the_back_global_control', 'on') and is_state('input_boolean.cameras_out_the_back_control', 'on') ) else 'off' }}
        entity_id: switch.out_the_back_state
      - service: switch.turn_{{ 'on' if ( is_state('binary_sensor.cameras_storage_room_global_control', 'on') and is_state('input_boolean.cameras_storage_room_control', 'on') ) else 'off' }}
        entity_id: switch.storage_room_state

Lots of copy/pasta and it makes me feel dirty. Also, if I happen to add more cameras I have to keep this automation sync’d up with the camera list which sucks. I’d much rather have a generic automation that applies to all cameras in the group (rolling through each one and setting the state) but I can’t wrap my head around how to do that or if it’s even possible since the entity_id and service are two separate things…

Anyone have any ideas?

//edit
added conditions to each action so it only triggers the switch update on a mismatch between the HA state and the ZM state.
//edit2
removed conditions because it doesn’t work how I thought it would.

What do you envision putting in this one group? All the switches?

The challenge is that each switch’s state depends on the state of two other entities (a binary_sensor and an input_boolean) whose name is different from each other and the switch. Example:

switch.back_yard_state
binary_sensor.cameras_back_yard_global_control
input_boolean.cameras_back_yard_control

There’s just enough similarity in the object_id that, with some effort, we can use ‘back_yard’ (2nd and 3rd words) to tie them together.

So far we have a repeat that iterates through the members of a group (after applying expand to it) gets the member’s object_id, extracts the 2nd and 3rd words, uses them to construct the entity_ids of the associated binary_sensor and input_boolean, gets their states, and uses it to determine the service call, either turn_on or turn_off. Whew!

Obviously there would be a bit less work involved if all three entities had the same object_id. Anyway, there it is.

@123, thanks for the response here. I got this working after about a day of playing around. I ended up using a combination of an automation and a script. The automation is kicked off by home assistant startup, has the list of cameras and it calls the script for each. The script takes the camera name as a field and then builds the necessary entities you outlined, performs the test and flips the switch if necessary.

I’ve been futzing so much with my automations over the last few days that I now have a much stronger sense of what automations can and can’t do. :slight_smile: I hit 100 automations on Christmas day and by the 27th I had shrunk that number to 55. Lots of simplification and streamlining with the choose: option.

After you mentioned the thing about simplifying the names, I’m thinking I might do that at some point so they’re at least consistent. Like:

binary_sensor.cameras_global_control_back_yard
input_boolean.cameras_control_back_yard

The thing that sucks is that the switch definition isn’t something I built, it actually comes from the zoneminder integration so maybe it’s more work than it’s worth since I have to deprocess and rebuild the names on the fly…