Getting attribute information in automation

I have a custom sensor (from rest) with several attributes. I am trying to set up an notify automation that will fire when any of the attribute values change. The notification could say something like “Attribute [attribute_name] changed from [previous_value] to [new_value].

This is pretty easy to do with multiple triggers with Trigger IDs and multiple Notify entries, but I would like to use a single trigger and a single notify with variable substitution for the attribute name and values. This means that I must be able to retrieve the name of the attribute that triggered the automation, as well as the prior / current values of that attribute. Is that possible? Thanks.

Here’s what is contained in a State Object (click link and review the properties).

attributes is one of the properties of a State object. It’s a dictionary whose individual keys represent what is commonly referred to as an “attribute” (i.e. what you called “attribute_name”).

The result of triggering a State Trigger is a trigger object containing the following properties.

from_state and to_state contain the entity’s State Objects before and after triggering. However, nothing in the trigger object, or the from/to State objects, explicitly indicates what changed in attributes.

You can compare trigger.to_state.attributes and trigger.from_state.attributes but that will only tell you if they’re different or the same. It won’t which dictionary key’s value changed. To get that you will have to iterate through the dictionary’s keys and compare individual values.


All this to say that if you want to define a single State Trigger like this and then attempt to determine what was responsible for triggering it (a change in its state or the value of one of the keys in its attributes dictionary), you will have a fair bit of templating to do.

trigger:
  - platform: state
    entity_id: sensor.foo

OK, I was afraid of that. So I’m using a separate trigger for each attribute and one notify for each attribute, but I was able to get the prior and current attribute values by using {{ (trigger.from_state.state | from_json).[attribute_name] }} (and again using to_state) in the notifications. I just needed to adjust the rest call to convert the state information in the value_template key by piping it to to_json so that I could get to the individual attribute values. Thanks for the help.

If that template works for you, what you are doing has nothing to do with an entity’s attributes. That template would only work if the state of your sensor is a dictionary encoded in JSON.

It would be best if you could go to developer tools > states, find and click on your REST sensor entity, and copy/paste what appears in the “state” field, and then also copy/paste what appears in the “state attributes” field.

It’s now clear to me that you were using the word “attributes” differently from how that word is commonly used in Home Assistant. Your version of “attributes” has nothing to do with an entity’s attributes .

.

Here is the REST sensor I created. Note the Attributes column. These were created via the json_attributes param in the rest configuration.

And here is the REST config:
rest

I see the column but, prior to posting that screenshot,
you posted a template that references the value of "attributes " in state not attributes. Both mekaneck and I were led to conclude you were using the word “attributes” in a different manner. No one could guess you have duplicated the data in state and attributes.

Create three State Triggers, each one monitoring a different attribute, and it will simplify determining which one triggered the automation (and what was the attribute’s previous value).

Otherwise, as mentioned previously for a single State Trigger, you’ll need a template to perform the heavy-lifting.


EDIT

I assume you know that state can’t store more than 255 characters.

I apologize for the confusion. I set up the automation as you described and it’s working. Thank you for pointing me in the right direction. I’m new to HA (and Python and Jinja), but alway try to find ways to keep my code clean by not repeating patterns or hard-coding values.

I do now! :grinning: Thanks again.

No worries; it happens.

Glad to hear you found my suggestion useful.

1 Like

I understand the topic has gone in a different direction, but assuming there are no added or deleted attributes, this should build up a message list:

{% set t = trigger.to_state.attributes %}
{% set f = trigger.from_state.attributes %}
{% for i in t -%}
{% if t[i] != f.get(i,'') -%}
Attribute {{ i }} changed from {{ f.get(i,'n/a') }} to {{ t[i] }}.
{% endif -%}
{% endfor %}

This looks very promising! I will definitely give it a try. Thanks.

As mentioned, iterating through the values and comparing them is one way to compare dictionaries.

1 Like