Trigger based template sensor to store global variables

This was posted earlier here. I’ve added some improvements, mostly to avoid errors, and also added some additional stuff suggested by @erkr in this post

It can happen you want to store some data to use it in another automation, or make sure it’s still available after a restart of HA. You can use helpers for that (eg and input_text entity) but these are limited in which types you can store, and they can be easily edited in the GUI.

The configuration below creates a trigger based templates sensor which can be used to store data. As trigger based template sensors restore their state and attributes after a restart, the data will survive restarts.

You can also store any type of data in this sensor, it can be a string, decimal number, integer but also a list or dictionary.

Note: there is a limitation how much data you can store in an attribute. If it becomes too big, it will not be stored in the database, and can therefor not be retrieved. If you really want to store a lot of data, you can maybe create a separate sensor for that.

Sensor configuration

# this configuration can be placed in configuration.yaml
template:
  - trigger:
      - platform: event
        event_type: set_variable
      - platform: event
        event_type: remove_variable
      - platform: event
        event_type: clear_variables
    action:
      - if: "{{ this.attributes.get('log_events', true) }}"
        then:
          - service: logbook.log
            data:
              name: "{{ trigger.event.event_type }}:"
              message: >
                {{ trigger.event.data.key | default('-') }}
                {%- if trigger.event.event_type == 'set_variable' -%}
                  : {{ trigger.event.data.value | default('not defined!')}}.
                {%- endif -%}
    sensor:
      - unique_id: 4a4c8e53-9e68-4198-9cc5-b336e228ea4d
        name: Variables
        state: Variables
        attributes:
          default_timestamp: true
          log_events: false
          variables: >
            {% set current = this.attributes.get('variables', {}) %}
            {% if trigger.event.event_type == 'set_variable' 
              and trigger.event.data.value is defined
              and trigger.event.data.key is defined
            %}
              {% if trigger.event.data.get('set_timestamp', this.attributes.get('default_timestamp', false)) %}
                {% set value  = trigger.event.data.value %}
                {% set value = value.isoformat() if value is datetime else value %}
                {% set new = {trigger.event.data.key: {'value': value, 'timestamp': now().isoformat()}} %}
              {% else %}
                {% set new = {trigger.event.data.key: trigger.event.data.value} %}
              {% endif %}
              {{ dict(current, **new) }}
            {% elif trigger.event.event_type == 'remove_variable' 
              and trigger.event.data.key is defined
            %}
              {{ dict(current.items() | rejectattr('0', 'eq', trigger.event.data.key)) }}
            {% elif trigger.event.event_type == 'clear_variables' %}
              {{ {} }}
            {% else %}
              {{ current }}
            {% endif %}

You can set the value for the set_timestamp attribute to true if you want to add a timestamp for the event by default, this can be overridden when you actually store a variable.

If you set log_events to true the events on which the sensor was triggered will be logged in the logbook.

How to add a variable

The sensor uses event triggers to store the data, you can send a custom event as an automation or script action, or you can use developer tools > events to send it.

# example for an action in an automation
action:
  - event: set_variable
    event_data: 
      key: some_test
      value: Some Value
      set_timestamp: false

Event data parameters

parameter type required explanation
key string yes the name of the variable
value string yes the value which you want to store this kan be any kind of value. datetime objects will be stored as isoformat string
set_timestamp boolean no Use this paramter to set the default timestamp setting used in the sensor

Exemple of the attributes of the sensor after adding some variables

default_timestamp: true
log_events: false
variables:
  test_without_timestamp: What time is it?
  test_with_timestamp:
    value: I know the time!
    timestamp: '2022-10-02T20:19:41.713241+02:00'
  some_list:
    - item 1
    - item 2
  a_mapping:
    fruit: banana
    veggies: broccoli
friendly_name: Variables

How to retreive a variable.

To retreive a variable, you’ll need to use a template. The template differs for variables stored with or without a timestamp.

With timestamp

replace variable_key with the actual key used when adding the variable

{{ state_attr('sensor.variables', 'variables')['variable_key'].value }}

Without timestamp

replace variable_key with the actual key used when adding the variable

{{ state_attr('sensor.variables', 'variables')['variable_key'] }}

How to remove variables

You can send an event similar as when you added a variable.

action: # example for an action in an automation
  - event: remove_variable
    event_data: 
      key: some_test

You can remove all stored variables in one go by sending the clear_variables event without further event data.


15 Likes

Glad you posted this, I’ve been using this successfully for some time now.

FYI there’s some funky indentation going on around line 50ish, around the if/then and logbook service that prevents an easy copy/paste into the config yaml.

1 Like

Thanks, should be fixed now

Have been using this the past couple of weeks, and it was spamming an error. Just figured out what it was complaining about.
You have this:

stating not required, so I didn’t put the set_timestamp key in at all. If I put the key in and say false, the error goes away. No key, it spams. Still works for what I needed either way, though.

I can probably resolve that :slight_smile: let me check that when I’m back from holiday

1 Like

If I add it to the configuration I get to see this:

What does the config checker in developer tools > YAML say about this? If should be fine unless you’re on a very old version of HA

This is almost exactly what I am looking for. I say almost because I want to be able to include many items in the event data.

Has anyone managed to convert it so this possible? I have been trying for a couple of hours and I think I have come close but it seems that the python data types are tripping me up .

Hi!

Really love this template and have big plans for it. So I’ve gotten myself into a mess and began wondering “how can I safeguard myself against (yet) non-existing variables”?

I wanted to fire an event that works on a variable retroactively, so it could not exist yet. This worked:

event: set_variable
event_data:
  key: heater_start
  value: "{{ state_attr('sensor.variables', 'variables')['heater_start'] | default(0) + 1}}"
  set_timestamp: true

However, I also needed a timestamp, so .value was required. This wouldn’t work:

event: set_variable
event_data:
  key: heater_start
  value: "{{ state_attr('sensor.variables', 'variables')['heater_start'].value | default(0) + 1}}"
  set_timestamp: true

So I’m leaving my solution in case any other unfortunate soul gets stuck:

event: set_variable
event_data:
  key: heater_start
  value: "{{ (state_attr('sensor.variables', 'variables') | default({})).get('heater_start', {}).get('value', 0) + 1 }}"
  set_timestamp: true

This is just a bunch of safeguards for every step of getting the value I need. I use it then to send a notification (will probably pack it into a variable, the event might be slower than the notification):

action: notify.mobile_app_rmx2155
metadata: {}
data:
  title: "[INFO] Heater on"
  message: >-
    The heater was turned on {{ (state_attr('sensor.variables', 'variables') | default({})).get('heater_start', {}).get('value', 0) }} times today.
1 Like

This looks very helpful!

Where do you add it in the UI though? I don’t see anything relevant in the “Automations & Scenes” dash, nor the “Devices & Services” dash.

@jacobmovingfwd Trigger based template sensors can only be created using YAML

I have noticed that if a variable’s value is false, trying to change it to 0 doesn’t work. Vice versa is also true. If I change it to true first, then it updates correctly to the integer.

Is that intended? Granted, I have not yet encountered any issue with treating false as 0.

I’ll have a look at that soon

1 Like