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.


13 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

Great, thanks! What would be the best (and the most efficient way) to pre-define 10-15 variables (in configuration.yaml or elsewhere)? In my case those will be “Slot” → “Person_Name” entries, so besides of the reported in the event slot, I can also get person’s name next to it, who unlocked the door lock. They won’t change frequently.