Help with passing position to script

Hi All,

I have made an automation to close blinds half way when the sun is too intensive and UV index is above 1 in two sunny rooms (each has its own cover). I would like to close the blinds half way from where they are, each time the automation starts. Ultimately, either the temperature in the sunny rooms stabilizes, or the automation would completely close the blinds.

Here is the automation entry (automation.yaml).

I have spent hours searching for the error and cannot find it. If I put a number in the first action service, such as 50, it works very well. But as soon as I set the expression, it fails with the following error:

Error executing script script.1583004153017. Invalid data for call_service at pos 1: expected int for dictionary value @ data['position']

In the template editor screen, the expressiion : {{ ((0 + states.cover.kitchen_blinds_controller.attributes.current_position )/2)| int}} gives the value 23.

- id: '1570981684762'
  alias: BLINDS DOWN - All, Partial - On_Strong_Light_or_Too_Hot
  description: Both covers (SOMFY and Kitchen) down partially when light too high
  trigger:
  - above: '1200'
    entity_id: sensor.terrasse_nord_illuminance
    for: 00:03:00
    platform: numeric_state
  condition:
  - condition: and
    conditions:
    - condition: or
      conditions:
      - condition: template
        value_template: '{{  states.cover.kitchen_blinds_controller.attributes.current_position  |
          int > 40 }}'
      - condition: template
        value_template: '{{ states.cover.time_based_cover_2.attributes.current_position
          | int > 40 }}'
    - above: '1'
      condition: numeric_state
      entity_id: sensor.dark_sky_uv_index
    - above: '25.0'
      condition: numeric_state
      entity_id: sensor.terrasse_nord_temperature
  action:
  - data:
      mycover: cover.kitchen_blinds_controller
      set_position: '"{{ ((0 +  states.cover.kitchen_blinds_controller.attributes.current_position
        )/2)| int}}"'
    service: script.1583004153017
  - data:
      mycover: cover.time_based_cover_2
      set_position: '"{{ ((0 +  states.cover.time_based_cover_2.attributes.current_position
        ) /2)|int}}"'
    service: script.1583004153017
  - data:
      message_title: BLINDS DOWN - All, Partial - On_Strong_Light_or_Too_Hot
    service_template: script.{% if states.input_select.notify_fh_on_events.state ==
      'info'%}1582713804730{%else%}1582707732926{%endif%}
  - data:
      option: weather_dependant
    entity_id: input_select.blinds_auto_close
    service: input_select.select_option

Any help to figure where the error is would be greatā€¦

Thanks in advance,
Felix

Itā€™s in your script.1583004153017, not the automation. HA stores values as strings. You need to |int filter the position in the script as well.

Edit: also see the yellow warning here and adjust your templates accordingly: https://www.home-assistant.io/docs/configuration/templating/#states not a show stopper, just best practice.

try:

- id: '1570981684762'
  alias: BLINDS DOWN - All, Partial - On_Strong_Light_or_Too_Hot
  description: Both covers (SOMFY and Kitchen) down partially when light too high
  trigger:
  - above: '1200'
    entity_id: sensor.terrasse_nord_illuminance
    for: 00:03:00
    platform: numeric_state
  condition:
  - condition: and
    conditions:
    - condition: or
      conditions:
      - condition: template
        value_template: '{{ states.cover.kitchen_blinds_controller.attributes.current_position  |
          int > 40 }}'
      - condition: template
        value_template: '{{ states.cover.time_based_cover_2.attributes.current_position
          | int > 40 }}'
    - above: '1'
      condition: numeric_state
      entity_id: sensor.dark_sky_uv_index
    - above: '25.0'
      condition: numeric_state
      entity_id: sensor.terrasse_nord_temperature
  action:
  - data_template:
      mycover: cover.kitchen_blinds_controller
      set_position: "{{(state_attr('cover.kitchen_blinds_controller','current_position')|int)/2)|int}}"
    service: script.1583004153017
  - data_template:
      mycover: cover.time_based_cover_2
      set_position: "{{(state_attr('cover.time_based_cover_2','current_position')|int/2)|int}}"
    service: script.1583004153017
  - data:
      message_title: BLINDS DOWN - All, Partial - On_Strong_Light_or_Too_Hot
    service_template: script.{% if states.input_select.notify_fh_on_events.state ==
      'info'%}1582713804730{%else%}1582707732926{%endif%}
  - data:
      option: weather_dependant
    entity_id: input_select.blinds_auto_close
    service: input_select.select_option

I believe the issue is how it handles the attribute. basically need to define the attribute youā€™re pulling as a integer rather then a string.

Edit: itā€™s probably just the way you defined the service data. Needs to be ā€œdata_template:ā€ instead of ā€œdata:ā€

1 Like

It will still be passed as a string to the script. Thatā€™s what HA does.

oh. do you think maybe he needs to define data_template: instead of data: as well? Iā€™m still learning too, thanks!

1 Like

Yeah he needs to do that too.

What an amazing Community! As soon as I have set the ā€œ|intā€ in the script, it worked. So many hours searching for the error, and that was it! many thanks to both of you.

The reason why I used data (instead of data_template) in the actions is that I was following the UI automation editor, which is great, but still has some mysteries.

I converted also all ā€œstates.XXXā€ to functions, it makes sense because it happens that some sensors are unavailable due to WIFI rssi.

May I ask you why it shall be data and not data_template? Whatā€™s the rule to tie-break between these two? Do you mean that data_template conserves the data type passed to the service, and that ā€œdataā€ systematically converts the arguments to strings?

Best regards,Felix

If you specify data_template the automation will pass the evaluation result of the template to your script (as a string, always as a string). e.g. "24"

If you use data in the automation it will pass the whole template unevaluated to your script ( again, as a string). e.g.

 '{{ states.cover.kitchen_blinds_controller.attributes.current_position | int > 40 }}'

You must then ensure your script is set up to evaluate that template by using data_templates in your script.

Personally, Iā€™d use data_template in both.

  • In the automation so it only has to pass the result not the whole template (it uses minutely less memory and is fractionally faster).

  • In the script to convert the result string into a number required for your service.

because itā€™s well documented (rule no.1 - surprise!), reading docs may save you a lot of time!

I never thought about it that wayā€¦ just followed the simple rule ā€œhave templateā€ ā†’ ā€œuse data_templateā€ (and it makes sense, doesnā€™t it?) so thanks for the explanation, even if I wonā€™t be using that knowledge :wink:

Itā€™s a great rule. I suppose there might be a reason to pass the whole template but I canā€™t think of one.

You often see questions like - why is my notification saying, ā€œsomething {{ literal template }} somethingā€.

Itā€™s because they used data instead of data_template and the template was not evaluated before sending the message.

Itā€™s a common trap and I will undoubtedly fall for it again myself.

me too. perhaps because it doesnā€™t make sense to create a template and then not to evaluate it.

I do it sometimes but I immediately know how to fix it when I see my template instead of it value :wink:

Thank you Tom, I learnt something. In other words data_template is passing-by-value, while ā€œdataā€ is passing the entire formula of the template. It could be useful if the target script modifies the data upon which the template is calculated. Is it not?

Many thanks again.
Felix

afaik when HA sees data_template, it evaluates (i.e substitutes templates with their calculated value) every value below it and then assigns the results of that evaluations (always strings) to appropriate keys. That way this (simplified example)

data_template:
   number: "{{ 2*2 }} steps"

will result in numberā€™ value being set to ā€œ4 stepsā€ and that value will be used in script/service/whatever.

and itā€™s the same as saying

data:
   number: "4 steps"

On the other hand, if we forget to use data_template and use data instead

data:
   number: "{{ 2*2 }} steps"

HA wonā€™t evaluate anything and numberā€™ value will be set to ā€œ{{ 2*2 }} stepsā€. Sometimes we need it - for example, to pass a string that contains double curly brackets.

However, if we need to dynamically change data that we assign to number, we have to use templates as they give us runtime evaluation. And for that evaluation to work we need to instruct HA accordingly by using data_template instead of data.

Therefore this

data_template:
   number: "{{ states('input_number.staps') }} steps"

will get a number entered in UI by user and the numberā€™s value will be set to something like ā€œ48 stepsā€
whereas this

data:
  number: "{{ states('input_number.staps') }} steps"

will lead to number always being ā€œ{{ states(ā€˜input_number.stapsā€™) }} stepsā€ as HA will always literally assign it to the key.

Thatā€™s why simple rule ā€œhave templateā€ ā†’ ā€œuse data_templateā€ is usually all you need to remember to use.

Hope it helps

Thank you Ahmad, for this very detailed explanation. Both your response and Tom and Coryā€™s responses helped a lot to solve my issue. My deepest thanks to all for sharing your knowledge!
Best regards, Felix

3 Likes