How to use variables in HA

No, what I told you is that variables have a scope. You thought you could change the value of a global variable by redefining it with a local variable but you can’t. The scope of a variable defined within a choose statement is not global so it can’t change the value of a variable that was defined outside of of the choose statement.

None of that reasoning applies to the use of now() in an automation’s action. The templates in action are evaluated only when action is processed.

That reasoning applies to the Template integration.

Reference: Template integration - Rate Limiting Updates

I examined your automation and discovered it sends a notification only when tipo_mese is Freddo, not when it’s Caldo. I don’t know if that’s what you intended but here’s a streamlined version that does the same thing. It sends a notification at 08:00 on Monday, Friday, and Sunday but only in the months of January to April and October to December.

- id: "006"
  alias: "GIARDINAGGIO - Routine di irrigazione perimetrale sul lastrico solare"
  description: "Routine di irrigazione perimetrale sul lastrico solare"
  mode: single
  trigger:
    - platform: time
      at: '08:00'
  condition:
    - "{{ now().month in [1, 2, 3, 4, 10, 11, 12] }}"
    - "{{ now().isoweekday() in [1, 5, 7] }}"
  action:
    - service: notify.mobile_app_cellulare_claudio
      data:
        title: "PROVA"
        message: >
          Siamo nel mese di {{state_attr('sensor.oggi_e_adesso', 'mese_lettere')}} che viene da me considerato Freddo.

Of course, automation is still in its infancy …
As I get it to work it will evolve …
Let’s see’

action:
    - variables:
        devo_annaffiare: "{{ true }}"
        tipo_mese: >
          {% set mese =
            [
              {'mese': 'Gennaio', 'considera_come': 'Freddo'},
              {'mese': 'Febbraio', 'considera_come': 'Freddo'},
              {'mese': 'Marzo', 'considera_come': 'Freddo'},
              {'mese': 'Aprile', 'considera_come': 'Freddo'},
              {'mese': 'Maggio', 'considera_come': 'Caldo'},
              {'mese': 'Giugno', 'considera_come': 'Caldo'},
              {'mese': 'Luglio', 'considera_come': 'Caldo'},
              {'mese': 'Agosto', 'considera_come': 'Caldo'},
              {'mese': 'Settembre', 'considera_come': 'Caldo'},
              {'mese': 'Ottobre', 'considera_come': 'Freddo'},
              {'mese': 'Novembre', 'considera_come': 'Freddo'},
              {'mese': 'Dicembre', 'considera_come': 'Freddo'}
            ]
          %}
          {{mese | selectattr('mese', 'eq', states['sensor.oggi_e_adesso'].attributes.mese_lettere) | map(attribute='considera_come') | first}}
    - choose:
        - conditions:
            and:
              # DA OTT AD APR
              - condition: template
                value_template: "{{tipo_mese == 'Freddo'}}"
              # 3 irrigazioni alla settimana
              - condition: template
                value_template: "{{ states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Mercoledì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Venerdì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Domenica'}}"
          sequence:
            - service: notify.mobile_app_cellulare_claudio
              data:
                title: "PROVA"
                message: "{{ devo_annaffiare}} Siamo nel mese di {{states['sensor.oggi_e_adesso'].attributes.mese_lettere}} che viene da me considerato {{tipo_mese}}."
  

devo_annaffiare is a global variable and, as it is textual, is displayed in the sent message.

  action:
    - variables:
        tipo_mese: >
          {% set mese =
            [
              {'mese': 'Gennaio', 'considera_come': 'Freddo'},
              {'mese': 'Febbraio', 'considera_come': 'Freddo'},
              {'mese': 'Marzo', 'considera_come': 'Freddo'},
              {'mese': 'Aprile', 'considera_come': 'Freddo'},
              {'mese': 'Maggio', 'considera_come': 'Caldo'},
              {'mese': 'Giugno', 'considera_come': 'Caldo'},
              {'mese': 'Luglio', 'considera_come': 'Caldo'},
              {'mese': 'Agosto', 'considera_come': 'Caldo'},
              {'mese': 'Settembre', 'considera_come': 'Caldo'},
              {'mese': 'Ottobre', 'considera_come': 'Freddo'},
              {'mese': 'Novembre', 'considera_come': 'Freddo'},
              {'mese': 'Dicembre', 'considera_come': 'Freddo'}
            ]
          %}
          {{mese | selectattr('mese', 'eq', states['sensor.oggi_e_adesso'].attributes.mese_lettere) | map(attribute='considera_come') | first}}
    - choose:
        - conditions:
            and:
              # DA OTT AD APR
              - condition: template
                value_template: "{{tipo_mese == 'Freddo'}}"
              # 3 irrigazioni alla settimana
              - condition: template
                value_template: "{{ states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Mercoledì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Venerdì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Domenica'}}"
          sequence:
            - variables:
                devo_annaffiare: "{{ true }}"
            - service: notify.mobile_app_cellulare_claudio
              data:
                title: "PROVA"
                message: "{{ devo_annaffiare}} Siamo nel mese di {{states['sensor.oggi_e_adesso'].attributes.mese_lettere}} che viene da me considerato {{tipo_mese}}."

devo_annaffiare is a local variable and, as it is textual, is displayed in the sent message.

  action:
    - variables:
        tipo_mese: >
          {% set mese =
            [
              {'mese': 'Gennaio', 'considera_come': 'Freddo'},
              {'mese': 'Febbraio', 'considera_come': 'Freddo'},
              {'mese': 'Marzo', 'considera_come': 'Freddo'},
              {'mese': 'Aprile', 'considera_come': 'Freddo'},
              {'mese': 'Maggio', 'considera_come': 'Caldo'},
              {'mese': 'Giugno', 'considera_come': 'Caldo'},
              {'mese': 'Luglio', 'considera_come': 'Caldo'},
              {'mese': 'Agosto', 'considera_come': 'Caldo'},
              {'mese': 'Settembre', 'considera_come': 'Caldo'},
              {'mese': 'Ottobre', 'considera_come': 'Freddo'},
              {'mese': 'Novembre', 'considera_come': 'Freddo'},
              {'mese': 'Dicembre', 'considera_come': 'Freddo'}
            ]
          %}
          {{mese | selectattr('mese', 'eq', states['sensor.oggi_e_adesso'].attributes.mese_lettere) | map(attribute='considera_come') | first}}
    - choose:
        - conditions:
            and:
              # DA OTT AD APR
              - condition: template
                value_template: "{{tipo_mese == 'Freddo'}}"
              # 3 irrigazioni alla settimana
              - condition: template
                value_template: "{{ states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Mercoledì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Venerdì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Domenica'}}"
          sequence:
            - variables:
                devo_annaffiare: "{{ true }}"
            - if:
                - condition: template
                  value_template: "{{ devo_annaffiare == true }}"
              then:
                - service: notify.mobile_app_cellulare_claudio
                  data:
                    title: "PROVA"
                    message: "{{ devo_annaffiare}} Siamo nel mese di {{states['sensor.oggi_e_adesso'].attributes.mese_lettere}} che viene da me considerato {{tipo_mese}}."

devo_annaffiare is a local variable and the message is sent.

  action:
    - variables:
        devo_annaffiare: "{{ true }}"
        tipo_mese: >
          {% set mese =
            [
              {'mese': 'Gennaio', 'considera_come': 'Freddo'},
              {'mese': 'Febbraio', 'considera_come': 'Freddo'},
              {'mese': 'Marzo', 'considera_come': 'Freddo'},
              {'mese': 'Aprile', 'considera_come': 'Freddo'},
              {'mese': 'Maggio', 'considera_come': 'Caldo'},
              {'mese': 'Giugno', 'considera_come': 'Caldo'},
              {'mese': 'Luglio', 'considera_come': 'Caldo'},
              {'mese': 'Agosto', 'considera_come': 'Caldo'},
              {'mese': 'Settembre', 'considera_come': 'Caldo'},
              {'mese': 'Ottobre', 'considera_come': 'Freddo'},
              {'mese': 'Novembre', 'considera_come': 'Freddo'},
              {'mese': 'Dicembre', 'considera_come': 'Freddo'}
            ]
          %}
          {{mese | selectattr('mese', 'eq', states['sensor.oggi_e_adesso'].attributes.mese_lettere) | map(attribute='considera_come') | first}}
    - choose:
        - conditions:
            and:
              # DA OTT AD APR
              - condition: template
                value_template: "{{tipo_mese == 'Freddo'}}"
              # 3 irrigazioni alla settimana
              - condition: template
                value_template: "{{ states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Mercoledì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Venerdì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Domenica'}}"
          sequence: []
    # MANDA NOTIFICA
    - if:
        - condition: template
          value_template: "{{ devo_annaffiare == true }}"
      then:
        - service: notify.mobile_app_cellulare_claudio
          data:
            title: "PROVA"
            message: "{{devo_annaffiare}} Siamo nel mese di {{states['sensor.oggi_e_adesso'].attributes.mese_lettere}} che viene da me considerato {{tipo_mese}}."

devo_annaffiare is a global variable and the message is sent.

  action:
    - variables:
        tipo_mese: >
          {% set mese =
            [
              {'mese': 'Gennaio', 'considera_come': 'Freddo'},
              {'mese': 'Febbraio', 'considera_come': 'Freddo'},
              {'mese': 'Marzo', 'considera_come': 'Freddo'},
              {'mese': 'Aprile', 'considera_come': 'Freddo'},
              {'mese': 'Maggio', 'considera_come': 'Caldo'},
              {'mese': 'Giugno', 'considera_come': 'Caldo'},
              {'mese': 'Luglio', 'considera_come': 'Caldo'},
              {'mese': 'Agosto', 'considera_come': 'Caldo'},
              {'mese': 'Settembre', 'considera_come': 'Caldo'},
              {'mese': 'Ottobre', 'considera_come': 'Freddo'},
              {'mese': 'Novembre', 'considera_come': 'Freddo'},
              {'mese': 'Dicembre', 'considera_come': 'Freddo'}
            ]
          %}
          {{mese | selectattr('mese', 'eq', states['sensor.oggi_e_adesso'].attributes.mese_lettere) | map(attribute='considera_come') | first}}
    - choose:
        - conditions:
            and:
              # DA OTT AD APR
              - condition: template
                value_template: "{{tipo_mese == 'Freddo'}}"
              # 3 irrigazioni alla settimana
              - condition: template
                value_template: "{{ states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Mercoledì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Venerdì' or states['sensor.oggi_e_adesso'].attributes.giorno_della_settimana == 'Domenica'}}"
          sequence:
            - variables:
                devo_annaffiare: "{{ true }}"
    # MANDA NOTIFICA
    - if:
        - condition: template
          value_template: "{{ devo_annaffiare == true }}"
      then:
        - service: notify.mobile_app_cellulare_claudio
          data:
            title: "PROVA"
            message: "{{devo_annaffiare}} Siamo nel mese di {{states['sensor.oggi_e_adesso'].attributes.mese_lettere}} che viene da me considerato {{tipo_mese}}."

devo_annaffiare is a local variable and the message isn’t sent.

I’m afraid I’ll end up using helpers.
I wanted to avoid it because they are entities that are added to those that must necessarily be in HA.
To ultimately do such a trivial task.
I don’t see other solutions … at least within my reach

1 Like

It is a trivial task but, respectfully, you have chosen a needlessly complicated way of achieving it.

Respectfully, the automation is already awkwardly structured (and reliant on an incorrect use of variables) so further enhancements are likely to make it even more of a mess. For example, you’ve already mentioned adding helpers to what is already far more code than is needed.

The example I presented does the same thing without errors, far less fuss, and it can easily be enhanced to do more. However, if you enjoy creating overly complicated automations, then I can understand why you don’t want to use it.

Good luck.

Helpers aren’t needed unless the data produced by this automation is needed by another automation (or script). The example Pico1965 presented creates data that is referenced exclusively within the automation so a helper isn’t needed. In fact, as I demonstrated in the example I posted above, it doesn’t even need a variable to achieve the desired result.

I’m sorry I gave you the impression of the pedantic.
Your automation does exactly the same thing as mine, certainly more efficiently.
That is, it lights up in the cold months in the established period.
However, there are the warm months and, in them, those in which the temperature exceeds 30 ° C.
There are rains and winds to manage …
All events that I believe should be managed in the action section of the automation.
For this reason I used choose and I started from the simplest case.
I realized, however, that at the end of the choose … checks you have to turn on the pump with the appropriate commands.
And so on to the next choose and the following ones.
I’m sure HA won’t go to the unions for this repetitive job.
I therefore wondered if it was possible to manage the routine in such a way as to use only one pump control at the end of the automation. The “elegance of the code” I was talking about with the friend above.
I remember that in cases like these 40 years ago, support variables were used.
Thanks to your advice I learned that the use of variables in this application is very … residual.
Think … if I had copied some automation here and there on the web I would have had working code that I would not understand anything about.
I also understand that for people like you who handle the code on a daily basis, the word I have represented for you is made of goat’s wool.
You must also understand that for me (or someone like me, if you prefer) the last (trivial) automation I did dates back to about 6 months ago.
This is why every time I decide to develop automation, it’s like starting over. At my age, memory is not at its all-time high.
I share what you wrote in the previous post. I will put a pump command for each choose.
I thank you again for the time you gave me and I hope this post will be of help to other patrons of this community.

We offer examples that are based on the requirements you present, not on the ones you haven’t shared with us.

If you have more requirements, describe them in detail and we can suggest the best solution. What you have described regarding temperature, rain, wind, etc is too vague and requires elaboration.

Maybe, it all depends on the requirements.

Yes, I think so. I recently wrote an automation to schedule radiator thermostats that is a kind of state machine requiring several persistent variables. For example it turns off the heating if you open a window; when you close the window it reverts to the previous manual or scheduled setting, depending what preceded the suspension of heating. I use helpers input_text, input_number and input_datetime. Within an automation, they are set using the appropriate service: input_text:set, input_number:set and input_datetime:datetime. Timers are also a type of global variable.

Helpers have the advantages that they are persistent over a reboot and you can easily add them to dashboards. Disadvantages are that there is no way to stop a user overwriting them in a dashboard, and no way to generate them in a blueprint (you have to create them all by hand for every instance of the blueprint, then identify them to the blueprint when it is invoked).

My suggestion is to make feature requests for
a) global variables that can only be read and written by automations or scripts: global_text, global_number, global_datetime etc.
b) a way of declaring instances of them within the setup of a blueprint, perhaps so that they appear as attributes to the automation entity?

2 Likes

6 posts were split to a new topic: Having issues trying to use a variables, coming from OpenHab

Hi Andy. Just noticed your topic here. Hope it’s not too late for some useful response. You may well already have discovered these things… in which case, my apologies.
You say:

My understanding is that the Helpers now have a Visible option. Select the helper, then its Setting cogwheel and set Visible at the bottom to yes/no. It says “Hidden entities will not be shown on your dashboard or included when indirectly referenced (ie via an area or device). Their history is still tracked and you can still interact with them with services.”
Also, I believe the Helpers can be created in YAML, though the preferred way is via the UI.

Re your feature requests for Variables - yes, several others before and I also have expressed the same arguements. The lack of Variables (except in specific places) and that can be updated within scripts is a pain. See also
https://community.home-assistant.io/t/global-variables-long-lived-variables-in-automations/513746
and
https://community.home-assistant.io/t/how-declare-a-proxy-variable-in-ha/604432/7 where @kameo4242 gives some useful ideas. Thus far I’ve stuck with input_xxx helpers for ‘global’ variables.
You can also pass “Fields” (aka parameters) to scripts and load (your own) Events with your data for Automations to consume, which both have some uses.

1 Like

Don’t forget about trigger-based template sensors as a way to store variables. Here s a particularly slick way of using one sensor for all your variables:

1 Like

Never too late!

My solution uses helpers that are generated in yaml because I need a lot – 12 for each for each automation (defined by a blueprint), and there are 23 of those in my latest implementation. Doing this by hand would be very tedious! I generate the yaml using Microsoft Mall Merge.

Thanks for pointing out the visible option. That could be useful. but I did not yet find any documentation on how to make a variable invisible in yaml. They are visible by default. See for example https://www.home-assistant.io/integrations/input_text/

These are (as I think you are saying) the only variables that are truly variable! ‘Local variables’ defined in scripts or automations, and fields used to pass parameters to scripts are actually constants (!) – you can only set them once.

There are two types of variable available in HACS, but as far as I can see they have no advantage over the built-in helpers.
https://github.com/snarky-snark/home-assistant-variables
https://github.com/rogro82/hass-variables

I also see no advantage in using template trigger sensors as variables, unless they have to be hidden from the UI.

All the above workarounds are essentially the same: you use YAML to define the variables, a service to set the value and a template to read it.

My objections are that I have to both generate all these (12 x 23) variables separately, then tell the blueprint each time I use it which ones they are – that’s 12 extra blueprint parameters I should not need.

What I would like to do is define the 12 global variables that I need within the blueprint, then have the automation generate the 12 global variable entities each time the blueprint is used (by concatenating the name of the automation with the internal name of the variable). I want to choose whether or not they are made visible outside the automation. This method would be less work, less error-prone (linking the wrong variable to the automation) and easier to maintain (if you change the variables now, you have to edit all the automations).

This idea is not new – it is a.k.a. “object-oriented programming” – it just has not yet arrived in HA yet…

Use MQTT discovery to generate the entities…
This one I wrote generates 9 entities.
HA_Blueprints/Automations/Octoprint_Additional_Buttons_Helper.yaml at 695ce9906cbab1101a38dac91f7af5c32499f536 · SirGoodenough/HA_Blueprints · GitHub.
The customer (user of the BP) doesn’t have to create anything.

Plus there is this, vote it up.

for what it’s worth (and on an old thread to boot…) I use if/then logic in template sensors for stuff like this then refer to the sensor in whatever automation or script I want - in a sense it’s a way to make HA a bit modular. I think OPs original complex use case could be more easily managed and tested as a sensor, then automation would simply either run on a schedule, or be triggered by any change to the sensor itself to perform an action.

That certainly works, but if you are trying to package up a blueprint and have everything self-contained for the user to turn on, my way works better.

I dont know why no one is telling you this, but you can actually use global variables in jinja by explicitly defining the scope:

{%- set g = namespace(test_var = 1) %}
{{ g.test_var }}
{% some for loop %}
{% set g.test_var = g.test_var + 1 %}
{% endfor %}
{{ g.test_var }}

And that’s not the scope issues that OP was running into. namespace only solves scoping issues inside a single template. OP was attempting to use variables defined in action sections that were not in scope of the action section they were in.

Lost in the noise of this discussion is a simple question being asked and the apparent answer:

Are there variables in the Home Assistant Scripting Syntax (scripting language) that have script scope, where such a scope is defined as enabling all sequences no matter how deeply nested to update these variables in a manner such that all of these sequences see the updated value?

The answer to this appears to be no!

I suspect the developers of Home Assistant have sound reasons for why this is the case. They are a group of software engineers and developers that clearly know what they doing. However, in absolute terms it simply can’t be denied that this is a lack of functionality which is a glaring hole for any scripting language. In other words this is a glaring hole in the Scripting Syntax.

For you computer science geeks out there I suspect that this means that the Scripting Syntax is not Turing complete for if it were one of the provided solutions would have provided a solution solely within the context of the Scripting Syntax. Further I suspect that the fundamental reason for this is that it is based on YAML which is a declarative language. Declarative languages, in general, aren’t Turing complete.

It seems, however, that Scripting Syntax taken on its face is just a hair step away from being Turing complete and that this issue with variables of script or automation scope is that hair. (I mean there are conditional statements, loops, etc.-- all the things necessary for Turing completeness-- but variables choke). I can’t, for the life of me, think of why, in principle, it couldn’t be resolved but almost certainly that is because I haven’t thought about it to the degree that the Home Assistant engineers have. My suspicion is it has to do with how YAML is parsed.

All of this said it should be pointed out that Pico1965’s original state of confusion was perfectly reasonable and there was nothing green or uninformed about his/her expectations. The short-coming was never his/her code but rather it truly was a short-coming of Scripting Syntax. Most of the many presented solutions were reasonable, if not necessarily convoluted, under these circumstances. However, having to go through such gyrations simply because a language, which ideally really should be, is not Turing complete is inarguably less than ideal.

As home automation becomes more and more sophisticated and Home Assistant continues to spread its wings to keep up with the challenges of this growing level of sophistication, it sure would be nice, to help reduce the proliferation of Helpers and the like of other otherwise unnecessary external structures, that Scripting Syntax could be made Turing complete.

Just to be clear I am not the one down in the weeds of the code on this issue so perhaps it is just much easier said than done. After all, to reiterate, Home Assistant has some fabulous software engineers and developers. I am sure it has been considered.

Hello Christopher C. Mills,

You may make too many assumptions…

Helpers can be used anywhere and any scope.

Also this:

Also the MQTT trick I use above.

You misunderstood my post, probably because I was not being clear enough. I know Helpers can address the problem of no global variables within the Scripting Syntax. I know that there are other “work-arounds” posted in this thread. My point is that functional as these may be they are all less than optimal options as they are all external to the Scripting Syntax.

I am a seasoned professional software developer. I have been knocking out code since the 1970s in a plethora of languages. When I am working within the Scripting Syntax I want to stay within it and not build a bunch of structure external to it just to get the script to work. Heck, I avoid Jinja and YAML as much as possible when setting up my Home Assistant even though I am perfectly comfortable using both. I want my setup to be as straight-forward and UI based as possible so that when I come back to it in the future it is understandable quickly.

Keep it simple!

Let me be clear: the thought of creating a Helper just to provide a global variable for a script is just an awful kludge from a programming standpoint. First of all it leads to a proliferation of Helpers that serve no purpose other than supporting a script of which they will not obviously be a part. So a year later when one is trying to understand why they have some arbitrary Helper that they can’t figure out what it is for, they now have to partake on a research project to decide whether to delete it or keep it.

This kind of programming mishegoss just becomes an incredible headache the more one expands their home automation system. Yes, I know the relationship to the script of a Helper will likely show up in a Related listing but this requires spending time digging around to investigate how it is being used, etc…

I could go on about the other solutions presented above too, but hopefully I am getting my point across.

A global variable capability for Scripting Syntax is really what one would expect for any scripting language and Scripting Syntax doesn’t have it! (More accurately, it lacks reasonable variable scoping rules for a scripting language.)

Btw, my expectations here had been low for a long time. I had always thought of the Scripting Syntax as being more declarative-like. However, with the introduction of Actions returning values suddenly making use of such values requires some useful variable capability.

Two final notes:

  1. I wanted to point out clearly that Pico1965, as humble as he/she was in their inquiry, had a correct intuition about their expectation of having a global variable capability. It by all rights should be there. His/her coding expectation was perfectly reasonable. Scripting Syntax is the problem here not Pico1965’s “greenness.” Home Assistant is aimed at developers who are at the level of Pico1965 and the better it gets at meeting their expectations the better Home Assistant becomes.

  2. I am not, by any means, tearing down the remarkable development effort that has gone into Home Assistant when I point out this shortcoming. This Open Source project is simply remarkable! I am sure there is a good reason for this lack of global variables. Even if it is some sort of an oversight they have gotten so much so right on this project, continuing to expand it each and every month. There is just nothing any one could fairly complain about.

This project is a gift.

I have to say, though, it sure would be nice to have a global variable in Scripting Syntax! (I probably should turn this in as a feature request, huh?) :slightly_smiling_face:

2 Likes