How do I trigger an automation based on the change of an attribute?

I would like to trigger an automation created from a blueprint on the change of an attribute of any one of a list of entities provided.

The use case is the control of thermostats. I want to trigger when the set temperature of any thermostat in a list (in domain climate), provided as an input to the blueprint, changes (by someone turning the knob on the thermostat).

Solution 1 is to write template sensors like

- sensor: 
### Master bedroom west trv set temperature
- sensor: 
  - name: Master bedroom west trv set temperature
    unique_id: 2933bd4a-49c2-f565-bd67-fc3127fa0345
    unit_of_measurement: 'C'
    icon: mdi:thermometer
    state: "{{ state_attr('climate.master_bedroom_west_trv', 'temperature') }}"
 
### Master bedroom east trv set temperature
- sensor: 
  - name: Master bedroom east trv set temperature
    unique_id: 518c074d-c4e2-0bf9-a359-fc12ea6eeee0
    unit_of_measurement: 'C'
    icon: mdi:thermometer
    state: "{{ state_attr('climate.master_bedroom_east_trv', 'temperature') }}"

And that works fine but it is a little annoying that I have to provide the blueprint with a list of template sensors in addition to the list of the thermostats that it already has.

blueprint:
  name: "Heating X"
  description: bla bla
  domain: automation

  input:
    thermostat_controls:
      name: DEVICE ENTITY - Thermostat control
      description: One or more thermostat entities that are to be controlled by this automation
      selector:
        entity:
          filter:
            domain: climate
          multiple: true

    thermostat_set_temperature_sensors:
      name: DEVICE ENTITY - Thermostat set temperature
      description: The (template) sensors that read the set temperature from the specified thermostats
      selector:
        entity:
          filter:
            domain: sensor
          multiple: true

[...]

trigger:

  # Change in any one of the thermostat set temperatures
  - platform: state
    entity_id: !input thermostat_set_temperature_sensors
    for:
      seconds: 10  # do not trigger while value is changing 
    id: set_temperature_change

Solution 2 (attempted) was to write a template trigger that tests all the attributes. I was hoping that there is an implied trigger if any are changed, but it does not work. Is there an error in the code or in my assumption that a change in an attribute will give a True result (as it apparently does for entities)

blueprint:
  name: "Heating X2" # temporary name for testing
  description: bla bla bla
  domain: automation

[...]

  input:
    thermostat_controls:
      name: DEVICE ENTITY - Thermostat control (mandatory)
      description: One or more thermostat entities that are to be controlled by this automation
      selector:
        entity:
          filter:
            domain: climate
          multiple: true

variables:
  local_thermostat_controls: !input thermostat_controls

[...]

trigger:
  # Change in any one of the thermostat set temperatures
  - platform: template
    value_template: >
      {% for thermostat in local_thermostat_controls %}
        {% not state_attr(thermostat,'temperature') | float == states(local_required_temperature) | float %}
      {% endfor %}
    for:
      seconds: 10  # do not trigger while value is changing 
    id: set_temperature_change

[...]


Solution 3 (attempted) was to write a template trigger that tests all the attributes against the last value it was set to, the ‘required temperature’, which is held in an input_number helper whose entity is an input to the blueprint. The following code yields True or False correctly when tested in the developer tools template editor, but when pasted into the blueprint does not cause a trigger. Is the theory wrong or the code?

blueprint:
  name: "Heating X2" # temporary name for testing
  description: bla bla bla
  domain: automation

[...]

  input:
    thermostat_controls:
      name: DEVICE ENTITY - Thermostat control (mandatory)
      description: One or more thermostat entities that are to be controlled by this automation
      selector:
        entity:
          filter:
            domain: climate
          multiple: true

    required_temperature:
      name: HELPER - Required temperature (mandatory)
      description: The global variable (helper) to hold the required temperature
      selector:
        entity:
          filter:
            domain: input_number


variables:
  local_thermostat_controls: !input thermostat_controls
  local_required_temperature: !input required_temperature

[...]

trigger:
  # Change in any one of the thermostat set temperatures
  - platform: template
    value_template: >
      {% set changed_temperatures = namespace(total=0) %} 
      {% for thermostat in local_thermostat_controls %}
        {% if not state_attr(thermostat,'temperature') | float == states(local_required_temperature) | float %}
          {% set changed_temperatures.total = changed_temperatures.total + 1 %}
        {% endif %}
      {% endfor %}
      {{ (changed_temperatures.total > 0) }}
    for:
      seconds: 10  # do not trigger while value is changing 
    id: set_temperature_change

[...]


Otherwise, is there another solution whereby I can trigger the automation by the change of value of a temperature of any of the list of thermostats?

The - in front of platform seem to suggest you can add multiple of them, so you can add more triggers by just adding - platform: …

trigger:

  # Change in any one of the thermostat set temperatures
  - platform: state
    entity_id: !input thermostat_set_temperature_sensors
    attribute: temperature
    for:
      seconds: 10  # do not trigger while value is changing 
    id: set_temperature_change

Reference

State Trigger - Triggering on attribute changes

1 Like

Yes, I know. There are a lot already; this is just an extract of what is relevant for this problem.

What are you saying?
You have reproduced the code that already works.

I do not think HA does pattern for triggers.
Node Red can do it, but you might even be able to simplify it a bit in HA.with multiple entity IDs for the same trigger. Automation Trigger - Home Assistant

I was basing my code on the documentation for template triggers, but it is not clear whether it covers my case. I need an expert who can explain in more detail when the template is evaluated and how it causes a trigger.

Home Assistant Template Triggers

Topic’s title is:

How do I trigger an automation based on the change of an attribute?

Question is:

Answer: By using a State Trigger configured with the attribute option.


You won’t have to do that if you make the following input variable a list of climate entities instead of Template Sensors. Therefore the blueprint no longer relies on additional Template Sensors.

entity_id: !input thermostat_set_temperature_sensors
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I believe your blueprint acquires a list climate entities in its thermostat_controls input variable. So the State Trigger can be configured like this:

trigger:

  # Change in any one of the thermostat set temperatures
  - platform: state
    entity_id: !input thermostat_controls
    attribute: temperature
    for:
      seconds: 10  # do not trigger while value is changing 
    id: set_temperature_change

It’s the addition of the attribute option to the State Trigger that will make it monitor the value of each climate entity’s temperature attribute.

attribute: temperature

With an important difference; it uses the State Trigger’s attribute option to monitor the temperature attribute of each climate entity (not Template Sensor).

1 Like

Are you trying to get the automation working on your system, or are you trying to write a blueprint for sharing with others?

Both. It is a new release of my blueprint “Heating X” which was first published a year ago. I will publish release 2 when it is working on my system. Why do you Ask?

Because writing a working automation to do what you want is easy. Configuring a blueprint to cope with the inputs is outside of my experience but looks a lot harder.

2 Likes

Sorry,I did not spot that. It does look like a simple solution for my case. I tried it and it does trigger, but for some strange reason it does not now set the trigger id, so the action that should run next doesn’t. Any idea why that should be the case??

Paste the code that is behaving as you describe.

The only way that’s possible is if the automation is tested without actually triggering any of its triggers.

How did you test it?

  • If you tested it by changing the value of the temperature attribute of one of the climate entities monitored by the State Trigger, check the trace that was produced. It will indicate the value of the trigger id.

  • If you tested it by using the automation’s Run command, that only executes the automation’s actions (therefore the trigger id is undefined).

By the first method that you mention. The trace shows that the trigger fired but the action that executes based on the trigger id is skipped.

I plan to make a test automation today to reproduce the fault in isolation. If it does that I wlll log a bug report.

It was part of a large blueprint that is too large to post here, and I reverted the code anyway (to the template sensor method) so I could continue testing. I plan to make a test automation today to reproduce the fault in isolation. If it does that, I will post it and log a bug report.

Do post the automation if that happens. I’d suggest it’s much more likely your error than such an obvious bug in the very well-tested automation back end — but that’s not impossible, of course.

Post the blueprint/automation and/or the trace file (not a screenshot of the trace but the actual trace file).

The State Trigger I posted above works as described. The automation’s alleged failure to match the State Trigger’s trigger.id would be anomalous; need to see the trace to understand why it’s happening.

Apparently this was a false test. My stand-alone demo automation worked correctly and then when I migrated it back to the blueprint it worked correctly there as well. I am grateful to all contributors for pointing out this solution. :slightly_smiling_face: :clap:

However, for future reference, how do I get the “actual trace file”?

1 Like

Spot on! And I got it in the end!