Hey all. I’ve created a custom component called var for generic variable entities. This component is basically a slightly more flexible template sensor. Variable entity attributes can be set manually from a service or dynamically through the use of templates and/or SQL queries. All of a variable’s attributes (including dynamic template attributes) can be set using the var.set service. Variables can be displayed in Lovelace in all of the same places that sensors are displayed. Each variable entity contains one value which can be of any type (a tuple, for example).
Variables can be updated based on events, including the state changed events of other entities.
I’ve found this component to be a bit more convenient than template sensors which require separate backing data.
I should also note that there is another custom component for variables that is floating around, “hass-variables” by rogro82. Their component has different aims than this one, and there were a few things I wanted to do differently which is why I made this one.
Let me know what you think!
Features
Current Features
Create variable entities by adding them under var: in configuration.yaml
Set the value of one or more variables using the var.set service - values can be computed using data_template
Set any other variable attributes using the var.set service (e.g., icon, entity_picture) - these can be computed using data_template as well!
Specify a value_template and a variable will update dynamically using that template
Specify attribute templates (e.g., icon_template, entity_picture_template) and those attributes will update dynamically
Display variables in Lovelace UI in the same way as other sensor components
Advanced Features
Update a variable whenever the state of one or more specified entities changes (tracked_entity_id)
Update a variable whenever one or more specified events fire (tracked_event_type)
Update templates (e.g., value_template, friendly_name_template) dynamically using var.set
Update the value of a variable using an SQL query (useful for history statistics)
Use the results of an SQL query in a template
Why?
It was tedious to create a corresponding separate template sensor for each entity in the UI.
I wanted a single general-purpose component, with a generic name, that could be used to store, update, and display values using templates.
I didn’t like using named UI components to store first-class data (e.g. input_text ).
I wanted to be able to work with data directly from the home assistant database (especially custom events) without having to create and flip-flop between a bunch of different entities.
I wanted a custom component that I could extend with more features in the future.
I’m not intimately familiar with rogro82’s component, but I do know that it has an unconventional way to tack on additional attributes to the entity using a JSON structure. It doesn’t handle live updates via templates, and it doesn’t support setting multiple variables at once to my knowledge.
I think the examples on the github page should help clarify.
I like the dynamic variable. This is not available in rogro82 implementation. @finity not sure as the two custom components declare the same domain ‘variable’ @snarkysnark perhaps you can name your custom components ‘dynamic_variable’ or something like that to allow the two custom components to cohexist?8
Looking more closely at rogro82’s component, it does appear to support a value template through the “value_template” key, and other templates through the “attributes_template”. However, as you mention @oncleben31, it doesn’t update these values dynamically.
I don’t like it’s use of JSON to pass attributes, though which seems to be the other main difference between these components. I’m guessing the JSON is required in order to be able to pass ad-hoc named attributes, but I didn’t see a use for those over multiple variables.
I’m happy to change the name of this component. That seems like a good idea.
I’m open to suggestions for a new name. “dynamic_variable” is sensible, but a bit too verbose for how often the entities are referenced in the yaml and jinja.
I’d like for the variable entities to be able to assume values from a db query like the SQL sensor component. In particular, I’d like to query events from the Home Assistant db and use that query as the variable state. For example, I’d like to be able to specify something like, “This variable is the number of ‘door_open’ events in the trailing 3 days” or “this variable is the average of all ‘light_events’ whose ‘event_data.brightness’ is greater than zero”.
A few things I’m working through:
is worth incorporating the sql sensor code to achieve this (shouldn’t be difficult)?
should the config params be an SQL query or a more limited interface?
how to write an SQL query to filter events from the db based on event_data? I can do it for event_type AND time_fired, but it’s not clear to me how to write a query that filters on event_data which is a dict stored as the SQL TEXT type.
Well, I’ve incorporated the SQL sensor functionality into the var integration, but I can’t seem to get the variable to update after the recorder component writes the event to the database. I’m not sure if this strict ordering is possible without modifying home assistant. I’m looking into it…
The ugly alternative is to add an option to update the variable state based on some time period.
Update1: It looks like the recorder component is a singleton instance that I can access through the hass instance. I might be able to do a non-blocking wait on the recorder until it’s done updating the database after an event fires, but I’m entirely unsure if it will work.
Update2: I’ve tried to synchronize with the recorder by adding the following await statements to an event listener callback. The idea is that the variable should update itself after an event fired, but only once the event has been written to the database by the recorder.
# Calling this in the event listener callback doesn't seem to work...
await self.hass.async_block_till_done()
await self.hass.async_add_job(self.hass.data[recorder.DATA_INSTANCE].block_till_done)
However, this doesn’t work - the event is written to the database, but the variable doesn’t update. I’m not sure what else to do. I’m close, but something isn’t quite right.
Could you possibly convert this for HACS input? That will make updating much faster for us.
@toofewacres: Sure. Actually, from what I can tell, this integration is already compatible with HACS. Let me know if this isn’t the case, and I’ll be happy to fix it.
In the mean time, I have a couple of bug fixes to push, and this database sync problem to solve.
This is an awesome component, especially given the ability to auto-update from another entity. I finished migrating everything from input_* to var.* (and all Tasker calls!).
Now, I was hoping to use this as a way to track my last-x contact closures.
outer_front_door_log:
friendly_name: "Outer front door log"
value_template: >-
{# Only track opens #}
{% if states.binary_sensor.outer_front_door.state == 'on' %}
{# If the variable is empty, don't use a delimiter #}
{% if is_state('var.outer_front_door_log', '') %}
{% set delimiter= '' %}
{% else %}
{% set delimiter= '|' %}
{% endif %}
{{ states('var.outer_front_door_log') }}{{delimiter}}Front Door: {{ as_timestamp(states.binary_sensor.outer_front_door.attributes.timestamp) | timestamp_custom('%a, %m-%d, %I:%M %p') }}
{% else %}
{# return our current value if we did not just open #}
{{ states('var.outer_front_door_log') }}
{% endif %}
tracked_entity_id:
- binary_sensor.outer_front_door
I’m realizing that it fires just after start-up as the tracked_entity_id is restored with its previous value.
This would be easy to prevent in a automation that could be enabled in the homeassistant_start automation, but that’s not making use if this cool new stuff.
From peeking above, it appears you might be investing a logbook solution, too. Maybe I should just chill?
(I hunted around - if there’s a way to detect HA is just starting, I’m not finding it.)
I’ve noticed this issue myself, but I’m not yet sure how to handle it.
I think the behavior that we want is that a variable should restore its state on startup (if restore is not set to false), but the variable should not update itself on startup (unless it tracks the homeassistant_start event).
Like you mentioned, tracked entities seem to emit a state change event when their state is restored on startup. So, I need to find a way to identify and ignore those startup state change events. I’m not exactly sure how to do that, but I’ll do some thinking.
Sorry, I’m not sure what you’re referring to regarding the logbook. Variables do show up in the logbook if you configure it to track the var domain.