Why the heck don't we have global variables?

Which input_* can you use to store more than 255 characters and the value survives a restart?

I agree that input_* can substitute for global variables but a true global variable:

  • Can have a type other than a string.
  • Isn’t constrained to 255 characters.
  • Survives a restart.
  • Its value can be easily assigned and retrieved (without resorting to the use of python_script).
  • Preferably has no associated Lovelace UI card (i.e. cannot be manually tweaked by a user, only via services).

Nothing I can think of satisfies all these requirements. Either something ought to be invented or an existing input_* enhanced to satisfy most of the requirements. Personally, an input_text supporting custom attributes (and services to set them) would go a long way to meeting all requirements.

As for an example, I mentioned one earlier: to store a list of all active timers. The list is needed on startup to restore all active timers. Currently, I’m using an input_text but 255 characters is a bit too small to handle many timers.

Another use case for me is tracking devices which have no integration. For instance I use tasker to report the location of my car and headphones every time it connects or disconnects from one of those devices via bluetooth. There’s no integration for these so I have to stash the state of these devices in a variable since there are multiple fields to track for devices (location name, latitude, longitude, gps accuracy, other useful data, etc.). Or i can use device_tracker.see but device trackers created that way don’t survive a restart either so its not any better.

Another one I’ve encountered is when trying to write automation to notify me any time there’s a new add-on. Supervisor has an API that returns the list of all currently available add-ons I can poll against but that meant I also had to keep track of my own list of all the add-ons I’d already seen. This way I can diff the two and determine what is new. I resorted to stashing that list in a text file due to the issue described here - HA provides no place to store more then 255 chars of data that survives a restart.

Also tbh, I don’t think @123 has to explain all that much here. Just take a scan through the search results on this forum for rogro82. Rogro82’s hass-variables plugin is the go-to plugin people use to fill this gap and there are tons of posts about people using it or recommending its use. I guess you could make an argument that many of these are workarounds where people are closing gaps in HA’s featureset (like making timers and device trackers survive restarts for instance). That may be true but

a) Not all are
b) HA team has limited time so it would be great to give us this capability in the meantime. If/when they close that gap then we can delete our variable and automation and use OOTB functionality.

1 Like

I have numerous examples in my config, follow the link and CTRL-F “variable”. Generally I use them to store the state of an entity after it has changed. Things that are too irregular or long to store in input booleans or input selects.

There’s also this variable custom component that I maintain (and would be happy to put to rest :sweat:). It has the same inefficiency in that it uses the entity system to store state.

For anyone asking, here’s another use case for storing state: I have an rgb light set to a current rgb value and brightness. I want to flash the light a different color to indicate a notification and then set the light back to its prior setting after the notification has passed. How else to do this but saving the state of the light into some sort of variable?

In my opinion, input entities shouldn’t be used to store state at all. The view should be separated from the model.

1 Like

Actually we have scene services for that. It allows for snapshotting / saving the current state of an entity on the fly, and restore it again later.

2 Likes

I use the rogro82 custom variable component to store lists of previous entity states in the variables attributes.

here are three examples:

then they are easily displayed in a card or used in automations.

For people who don’t know, it’s a useful feature but be aware that ‘snapshot’ scenes don’t survive a restart. So if you plan to restore a scene, created with snapshot_entities, keep in mind it no longer exists after a restart.

Creating scenes on the fly

Yes Please. Like @123 I use item Select rather input text to hold persistant data

This sounds like another WTH… Snapshots should be able to survive a restart.

Terry

Edit: and now it is another WTH. :wink:

It may not be considered part of Home Assistant, but the integration of node-red is so smooth that it might as well be!

Node-red has the concept of node context, as explained in this tutorial

I’ve moved all my automations over to node-red, and it’s been a game-changer.

1 Like

I want to use the value of an entity (maybe a long one like the body of an email from the IMAP content sensor) after the state of that entity has changed. I believe scenes won’t cover this use case, correct?

Correct. The email body must reside in some entity, either in its state or attributes. If it exceeds 255 characters it must reside in attributes (state is limited to 255).

A scene represents the desired states for a collection of entities. A scene has no “space” to store other information beyond the entity names and the desired states (just the states and not attributes).

A scene is sort of like a recipe. It contains ingredients (light.kitchen) and quantities (brightness: 100).

1 Like

Thinking about this: what if a new domain existed (variables) and we gave two services:

  • variables.set(key, value): creates a new variables entity (e.g., variables.my_var) whose state is the value.
  • variables.remove(key): deletes a variables entity with the provided key

These services would interact with a JSON storage to hold onto the values. The set service “creates” the variable and reading the entity’s state “gets” the variable.

This would be an MVP; more complex functionality (templates, etc.) could come after.

EDIT: I’ve drafted a PR for this here: https://github.com/home-assistant/core/pull/39070 – no clue if this is the ultimate direction or a detour, but it was a good exercise to play with the concepts.

2 Likes

I read the PR and I understand, in this very early stage, it is limited to creating a string value. My only comment is that, as it evolves, that string must be capable of holding more than the current cap of 255 characters. If it is unable to breach that ceiling, shelve this thing now because we can already use input_text to store a string of up to 255 characters.

If it will indeed be possible to hold a string value of several kilobytes, wonderful, please continue!

A tremendous bonus would be the ability to store other types like integer and, of course, list and dict. Then I imagine it will be possible to retrieve and consume the value with its type retained. For example:

  - service: variables.set(foo0, 'Thus spoke Zarathustra')
  - service: variables.set(foo1, ['Dave', 'Frank', 'Heywood'])
  - service: variables.set(foo2, {'name': 'HAL', 'model': 9000})

elsewhere:

{{ states('variables.foo0') }}
{{ states('variables.foo1')[1] }}
{%- set x = states('variables.foo2') -%}
{{x.name}} {{x.model}}

produces:

Thus spoke Zarathustra
Frank
HAL 9000
1 Like

These variable values have no inherent limit.

Once I get approval on the overall direction, additional types shouldn’t be challenging.

2 Likes

Looking back at my own examples, will the service conform to how existing ones are defined? In other words like this:

  - service: variables.set
    data:
      key: foo0
      value: 'Thus spoke Zarathustra'

Not sure what you mean by “existing ones,” but yes, your call there will work fine.

I meant that your example used this function-like way of specifying arguments:

variables.set(key, value)

whereas all services normally use the YAML form where the arguments are on separate lines and indented appropriately.

The PR’s description shouldn’t be taken for documentation – a service is basically a function, so I used shorthand to communicate the idea. Nevertheless, yes, your existing service call structure in YAML is the way to go. :+1:t2: