Setting "global" variables in automation

I’m not sure what logic I’m missing for my automation triggers, conditions, and actions to all properly see the value of a variable set at the top level of the automation…

I’m working on my HVAC automation, and I’m trying to set the target temps once as variables at the beginning of the automation, then reference them later on. Here’s the full YAML in a Gist.

Based on my reading of Passing Variables to Scripts and Variable Scopes, setting variables at the “top” level should make it visible throughout the automation. I’m only setting the value once, then referencing it throughout, not trying to alter the values or anything.

I thought I had it all squared away, but when I try to run it, I get Error: Template rendered invalid entity IDs: in a few spots, for example:

action: script.upstairs_heat_schedule
data:
  variables:
    upstairs_am_heat_target: '{{ upstairs_am_heat_target }}'
    upstairs_night_target: '{{ upstairs_night_target }}'

I try this logic in Developer Tools > Template Editor, and get an undefined error.

I tried with data:variables:

variables:
  upstairs_night_target: 65
  upstairs_am_heat_target: 72
action: script.upstairs_heat_schedule
data:
  variables:
    upstairs_am_heat_target: '{{ upstairs_am_heat_target }}'
    upstairs_night_target: '{{ upstairs_night_target }}'

'upstairs_night_target' is undefined

And I tried with just data:

variables:
  upstairs_night_target: 65
  upstairs_am_heat_target: 72
action: script.upstairs_heat_schedule
data:
  upstairs_am_heat_target: '{{ upstairs_am_heat_target }}'
  upstairs_night_target: '{{ upstairs_night_target }}'

'upstairs_night_target' is undefined

I just confirmed that all my Scripts have Fields defined, and got this error in the Trace:

Executed: September 28, 2024 at 01:15:55
Error: Template rendered invalid entity IDs:
Result:

params:
  domain: script
  service: upstairs_heat_schedule
  service_data:
    variables:
      upstairs_am_heat_target: 72
      upstairs_night_target: 65
  target: {}
running_script: true

child_id:
  domain: script
  item_id: upstairs_heat_schedule
  run_id: 1e5c2e8bf75b9fd03b4321a2a352e3c0

So some part of the action knows the values I’m trying to pass in, but it’s still throwing that error.

Here’s the trace JSON.
The trace also shows the same error in the choose logic, even though it does appear to be evaluating the relative temp correctly, as well as getting the variable values to send on the script.

if you want to run a script and pass variables to it, you need to use this syntax:

      - action: script.turn_on
        target:
          entity_id: script.your_script
        data:
          variables:
            variable_1: >
              {{template_1}}
            variable_2: >
              {{template_2}}

somehow that seems to have been deleted for the earlier documentation, or at least, I cant find it any longer under that link.

Yeah that’s how the UI builds it, which I’ve been using to get the right structure, then switch to YAML to apply the templates. That’s in my first example.

I’ve now gotten to a new error, which is a type of progress :smiley:
Based on the second example in Input Numbers, I tried using states(var) | int:

action: script.upstairs_heat_schedule
data:
  variables:
    upstairs_am_heat_target: '{{ states(upstairs_am_heat_target) | int }}'
    upstairs_night_target: '{{ states(upstairs_night_target) | int }}'

Which then returned the error: Error: Error rendering data template: AttributeError: 'int' object has no attribute 'lower'. I have no idea where the lower is coming from, I know I don’t call it anywhere. I tried with float too, with the same result.

you’re still using the direct way to call the script there, and don’t use action: script.turn_on

as for the template error, at least give the |int a default value to see if that helps: |int(10)

Um… Isn’t this overkill? :grin:

The Generic Thermostat integration allows you to set targets and stuff.

Hi Jacob Lee,

Setting a variable to itself doesn’t work because the variable doesn’t exist until you create it. It would be undefined there.

There you changed scope so it works in the first instance, but a new scope means new variables, so again it is undefined.

That one looks like something an AI dreamed up.

If you want a variable you can refer to in multiple places in the acript/automation, use a helper. create it, load it with your values, and it will be available regardless of scope.
Open your Home Assistant instance and show your helper entities.
There is also this available:
Trigger based template sensor to store global variables.

But to solve your actual problem Jack has the answer you might be looking for.

I’ve looked at those, but can’t use them because I have 1 external heat pump, but 2 internal air handlers each with their own thermostat. If one of them attempts to go to heat or cool while the other is in the opposing mode, they shut down, because the heat pump can’t run both ways at the same time.

That’s why I have to build dependent logic here, where the main floor of the house takes priority, then the upper floor is set to whatever it can be.

Those examples that are variables/action/data were what I ran through the Template developer tool, where it kept saying they were not defined. I was just trying different ways, since I’ve found different ways in various community posts. Sorry that wasn’t clear; the first variables is the “global” values set in the Automation, then the later one inside the data argument is where I’m attempting to pass the values to the script.

I didn’t think I was setting it to itself, since I set it to a value first, but that’s a good point. Unfortunately, setting distinct var names &a default int value in the Template developer tool shows that it’s not getting the arguments. Tried it both with states() and without:

automation:
- variables:
      upstairs_am_heat_temp: 72
      upstairs_night_temp: 65
- action: script.upstairs_heat_schedule
  data:
    upstairs_am_heat_target: "{{ 'upstairs_am_heat_temp' | int(10) }}"
    upstairs_night_target: "{{ states('upstairs_night_temp') | int(15) }}"
Result type: string

automation:
- variables:
      upstairs_am_heat_temp: 72
      upstairs_night_temp: 65
- action: script.upstairs_heat_schedule
  data:
    upstairs_am_heat_target: "10"
    upstairs_night_target: "15"

It does look like the Helper input_number is working though:

- action: input_number.set_value
  data:
    value: 70
  target:
    entity_id: input_number.main_house_target_temp
- action: script.set_hvac_temp_mode
  data:
    target_entity: climate.main_house
    target_mode: heat
    target_temp: "{{ states('input_number.main_house_target_temp') | int}}"
Result type: string

- action: input_number.set_value
  data:
    value: 70
  target:
    entity_id: input_number.main_house_target_temp
- action: script.set_hvac_temp_mode
  data:
    target_entity: climate.main_house
    target_mode: heat
    target_temp: "70"

So I’ll keep working from there. thanks!

Thanks, that default value is a good tip!

I’m not sure why the script.turn_on matters? Per the documentation, using script.turn_on makes it async, and I specifically want it to be synchronous because i need to make sure the hvac_mode changes before changing the next mode.

The syntax for passing variables is different when the script is called synchronously vs asynchronously.

Sync

    action: script.notify
    data:
      title: State change
      message: The light is on

Async

    action: script.turn_on
    target:
      entity_id: script.notify
    data:
      variables:
        title: State change
        message: The light is on!

Your example called the script synchronously but used async syntax for passing the variables.

2 Likes

Ah thanks! I hadn’t noticed that distinction in the script variables doc.