Scripting with repeat.index - UndefinedError: 'dict object' has no attribute 'item'

Using developer tools services:

service: script.turn_on
target:
  entity_id: script.ensure_device_changes
data:
  variables:
    device: switch.trees_outside_north_zb
    state: "on"

to call ensure_device_changes script:

sequence:
  - variables:
      device_list: "{{ expand(device) | map(attribute='entity_id') | list }}"
  - repeat:
      sequence:
        - repeat:
            sequence:
              - service_template: "{{ repeat.item.split('.').0 }}.turn_{{ state }}"
                data_template:
                  entity_id: "{{ repeat.item }}"
                alias: "ServiceTemplate: repeat.item(0).turn_STATE"
              - delay:
                  hours: 0
                  minutes: 0
                  seconds: 3
                  milliseconds: 0
            while:
              - condition: template
                value_template: "{{ states(repeat.item) != state }}"
      for_each: "{{ device_list }}"
mode: parallel
max: 20

When passing ‘switch.trees_outside_north_zb’ I’m getting the error:

Goal is to be able to pass either an individual device or a group. if the former it should repeat the loop just once, if the latter, should repeat for all members of the group. Appears like it’s not fetching the state of the device being passed.

I’m sure it’s something small I’m overlooking. Thx in advance!
n

It’s probably a scope issue… i.e. the repeat variable is local to it’s own loop. Try assigning the value of repeat item to a new variable before starting the second loop.

...
  - repeat:
      for_each: "{{ device_list }}"
      sequence:
        - variables:
            this_item: "{{ repeat.item }}"
        - repeat:
            sequence:
              - service: "{{ this_item.split('.').0 }}.turn_{{ state }}"
                data:
                  entity_id: "{{ this_item }}"
               - delay: 3
            while:
              - condition: template
                value_template: "{{ not is_state(this_item, state) }}"
mode: parallel
max: 20
....

Tried something similar:

...
  - repeat:
      sequence:
        - repeat:
            sequence:
              - variables:
                  repeat_item: "{{ repeat.item }}"
              - service_template: "{{ repeat_item.split('.').0 }}.turn_{{ state }}"
                data_template:
                  entity_id: "{{ repeat_item }}"
...

Hmm…

You’re still doing it in the while loop… repeat.item is only defined in the for_each loop.

Updated to include another variable, looking promising:

sequence:
  - variables:
      device_list: "{{ expand(device) | map(attribute='entity_id') | list }}"
  - repeat:
      for_each: "{{ device_list }}"
      sequence:
        - variables:
            device_1: "{{ repeat.item }}"
        - repeat:
            while:
              - condition: template
                value_template: "{{ states(device_1) != state }}"
            sequence:
              - service_template: "{{ device_1.split('.').0 }}.turn_{{ state }}"
                data_template:
                  entity_id: "{{ device_1}}"
                alias: "ServiceTemplate: DEVICE_1.turn_STATE"
              - delay:
                  hours: 0
                  minutes: 0
                  seconds: 3
                  milliseconds: 0
mode: parallel
max: 20

As I understand it, this script turns on (or off) a list of entities. It repeatedly tries to turn the entity on (or off), waiting 3 seconds between each attempt, until the entity is in the desired state.

Can you provide some examples of what is passed to your script’s device variable?

The while loop is overwriting the foreach’s repeat object. So you need to extract the item into a variable to use it in the while loop.

change to

sequence:
  - variables:
      device_list: "{{ expand(device) | map(attribute='entity_id') | list }}"
  - repeat:
      sequence:
        - variables:
            entity: "{{ repeat.item }}"
            domain: "{{ item.split('.')[0] }}"
        - repeat:
            sequence:
              - service_template: "{{ domain }}.turn_{{ state }}"
                data_template:
                  entity_id: "{{ entity }}"
                alias: "ServiceTemplate: repeat.item(0).turn_STATE"
              - delay:
                  hours: 0
                  minutes: 0
                  seconds: 3
                  milliseconds: 0
            while:
              - condition: template
                value_template: "{{ states(entity) != state }}"
      for_each: "{{ device_list }}"
mode: parallel
max: 20

Updated a little bit further and calling this final (for now, ha!):

sequence:
  - variables:
      device_list: "{{ expand(device) | map(attribute='entity_id') | list }}"
  - repeat:
      for_each: "{{ device_list }}"
      sequence:
        - variables:
            device_1: "{{ repeat.item }}"
        - repeat:
            while:
              - condition: template
                value_template: "{{ states(device_1) != state }}"
                alias: "WHILE: Device State != Desired State"
              - condition: template
                value_template: "{{ repeat.index <= 3 }}"
                alias: "WHILE: # Attempts <= 3"
            sequence:
              - service_template: "{{ device_1.split('.').0 }}.turn_{{ state }}"
                data_template:
                  entity_id: "{{ device_1 }}"
                alias: "ServiceTemplate: DEVICE_1.turn_STATE"
              - wait_template: "{{ states(device_1) == state }}"
                continue_on_timeout: true
                timeout: "00:00:03"
                alias: "WAIT FOR: Device State = Desired State (3s timeout)"
mode: parallel
max: 20

Using this script b/c ZWave via USB stick went bonkers in HA and has the controller ‘jamming’ constantly. This script will attempt a few times and (hopefully) one of the times won’t be jammed and the device will actually do what I ask it to do.

Going to pull the ZWave via USB altogether and switch to a Hubitat C8 to run the radios (both for ZWave and Zigbee). Hate introducing add’l failure points / integrations - but the need to even figure out a script like this and the woes I’ve had w/ USB dongles hooked up to HA sadly deems it necessary…

Thx for the help all.