[question] build a script for several entity dynamically

Hi all,
i have some qubino zwave roller modules and I managed to automate them in HA.

Unfortunately from time to time( don’t know why, maybe a zwave or module bug) the roller received the “open roller” command and stayed closed (i know this because i hear the "clac noise from the module)
so the zwave device received it command but somehow did not open it.

manual solution : send the opposite command (the roller is closed but i need to say close roller), and right after send again the open roller.

my idea : instead of just using the defaut switch => write a script for open and a script for close

I wrotte following script

open_salon:
  sequence:
  - data:
      payload_template: "{{(state_attr('cover.qubino_salon_level', 'current_position')|int)}}"
      retain: 'true'
      topic: /volet/salon/position
    service: mqtt.publish
  - data:
      entity_id: cover.qubino_salon_level
    service: cover.open_cover
  - delay: '1'
  - condition: template
    value_template: "{{ (states.cover.qubino_salon_level.attributes.current_position|int) == (states.sensor.position_volet_salon.state|int) }}"
  - data:
      entity_id: cover.qubino_salon_level
    service: cover.close_cover
  - delay: '1'
  - data:
      entity_id: cover.qubino_salon_level
    service: cover.open_cover

as I have 4 cover, with different names, is it possible to change this script to work with the different covers ?

indeed this is the open for “salon”
i want to have the open for “cuisine” for ex, as my sensor and cover are all the same form and include the name of the roller, would it be possible parameterize this ?
indeed i could copy/paste the script 3 times, but for maintenance reason i would prefer preventing code repetition :slight_smile:

basically I want to do something like this

VAR = a list of values(for ex salon, cuisine, chambre)

some kind of loop with

open_VAR:
  sequence:
  - data:
      payload_template: "{{(state_attr('cover.qubino_VAR_level', 'current_position')|int)}}"
      retain: 'true'
      topic: /volet/VAR/position
    service: mqtt.publish
  - data:
      entity_id: cover.qubino_VAR_level
    service: cover.open_cover
  - delay: '1'
  - condition: template
    value_template: "{{ (states.cover.qubino_VAR_level.attributes.current_position|int) == (states.sensor.position_volet_VAR.state|int) }}"
  - data:
      entity_id: cover.qubino_VAR_level
    service: cover.close_cover
  - delay: '1'
  - data:
      entity_id: cover.qubino_VAR_level
    service: cover.open_cover

I am not sure what you are asking in your title but to pass a variable to a script, see below. You can set the variable for the cover you want to use and use only one script.

PASSING VARIABLES TO SCRIPTS

As part of the service, variables can be passed along to a script so they become available within templates in that script.

There are two ways to achieve this. One way is using the generic script.turn_on service. To pass variables to the script with this service, call it with the desired variables:

# Example configuration.yaml entry
automation:
  trigger:
    platform: state
    entity_id: light.bedroom
    from: 'off'
    to: 'on'
  action:
    service: script.turn_on
    entity_id: script.notify_pushover
    data:
      variables:
        title: 'State change'
        message: 'The light is on!'

The other way is calling the script as a service directly. In this case, all service data will be made available as variables. If we apply this approach on the script above, it would look like this:

# Example configuration.yaml entry
automation:
  trigger:
    platform: state
    entity_id: light.bedroom
    from: 'off'
    to: 'on'
  action:
    service: script.notify_pushover
    data:
      title: 'State change'
      message: 'The light is on!'

sorry for the bad title, i modified it and gave an example of what I tried to archive to make it more clear

Looping isn’t easy in native automations. You can do loops with appdaemon or some other automation engine. The best way to handle this in native HA would be 2 scripts. 1 master script that does the ‘looping’ and one that does the work.

master sequence:

master_sequence:
  sequence:
    - service: script.open_cover
      data:
        var: 'salon'
    - wait_template: "{{ is_state('script.open_cover', 'off') }}"
    - service: script.open_cover
      data:
        var: 'cuisine'
    - wait_template: "{{ is_state('script.open_cover', 'off') }}"
    - service: script.open_cover
      data:
        var: 'chambre'
    - wait_template: "{{ is_state('script.open_cover', 'off') }}"

opens a cover:

open_cover:
  sequence:
    - service: mqtt.publish
      data_template:
        payload: >
          {% set entity_id = 'cover.qubino_{}_level'.format(var) %}
          {{ state_attr(entity_id, 'current_position') | int }}
        retain: 'true'
        topic: >
          {{ '/volet/{}/position'.format(var) }}
    - service: cover.open_cover
      data_template:
        entity_id: >
          {{ 'cover.qubino_{}_level'.format(var) }}
    - delay: '00:00:01'
    - condition: template
      value_template: >
        {% set cover_id = 'cover.qubino_{}_level'.format(var) %}
        {% set position_id = 'sensor.position_volet_{}'.format(var) %}
        {{ state_attr(cover_id, 'current_position') | int == states(position_id) | int }}
    - service: cover.close_cover
      data_template:
        entity_id: >
          {{ 'cover.qubino_{}_level'.format(var) }}
    - delay: '00:00:01'
    - service: cover.open_cover
      data_template:
        entity_id: >
          {{ 'cover.qubino_{}_level'.format(var) }}

The first script opens a cover, then waits for the script to finish opening the cover and moves to the next cover. The cover name is passed to the second script via the variable var. The second script uses var in each template section to make the topic name and entity_ids. Scripts can only be run one at a time like this. This is because you only have 1 script it will not create a new thread. It creates 1 thread per script. Meaning you can’t run this method in parallel. It can only be ran in series. That’s why the wait template exists. If you attempt to run in parallel, the script will just cancel itself each run and all the delays will be ignored and most services will be skipped.

1 Like

thanks a lot i’ll use and adapt this. It will make my scripts less big :wink:

is it possible to name part of the sequence ?
building the scripts dynamic was to have less code
but i still need script that open just one cover .
I guess this code can be used to open them all

or maybe is it possible to define some kind of aliases ?
for ex alias open_cover salon = script.open_cover with data ‘salon’

Indeed I use also the scripts in alexa,