How could I use logs of an entity's state in an automation condition / implementing a state override

Hi,

I am trying to create an automation (or rather a set of automations most probably) that would handle the following scenario.

SETUP

I have a heater, which can have the following states:

  • Confort
  • Eco
  • Frost protection
  • Off

The heater’s state can be updated through any of the three following actions:

  1. A schedule pilots this heater and changes the states following a timetable.
  2. We change the heater’s state manually.
  3. When we open the window, a contact sensor triggers an automation that switches the heater off. We want the heater to be switched back to the correct state, which is not necessarily the one on which it was when the window got opened.

SCENARIO

And the last bit is where it becomes complicated : when either the scheduler changes the heater state or this state is changed manually, how can the automation know this new state to which it has to update the heater when we close the window.

Here is a concrete example:

  1. The heater is on “Confort”.
  2. It is 7:55 am, and I open the window to air the room. My automation switches the heater to “Off”.
  3. It is 8 am, and the scheduler switches the heater to “Eco” => I don’t what this to happen! I want this target state to be kept somewhere, and the heater to stay on “Off” because the window is still opened.
  4. It is 8:02 am, and close the window, and I want the heater to be set on “Eco” as scheduled, not on “Confort” as it was before I opened the window.

CONSTRAINTS

  • The scheduler and the manual state change must manipulate the entity state directly => I don’t want (/it is not workable) to have a complicated setup that would require to use an intermediate state holder instead of the actual entity state. It is not feasible on the scheduler, and would require to do tricks and adjustments that would be easy to get lost into and forget about how it all works out in the future.

THEORETICAL SOLUTION

The following solution would work:

  • A first automation triggers when the window is opened, and:
    • Takes the current state of the heater and puts its value in a helper (Text? Dropdown?).
    • Changes the state of the heater to “Off”.
  • A second automation triggers when the window is closed, and:
    • Sets the heater’s state to the value that was kept in the helper.
  • A third automation triggers when the state of the heater changes, and if the change has neither been made by first automations, nor by the second, nor by this automation itself, it:
    • Takes the changed state of the heater and updates the helper with this value.
    • Changes the state of the heater to “Off”.

CHALLENGE

The challenge lies in the “if the change has neither been made by first automations, nor by the second, nor by this automation itself”.

I know this information is available in the log book as shown in the screenshot below, but I could not find a way to access the logs from an automation in an “if” condition to get this information.

Assuming that I would then be able to identify exactly the correct log entry using the data from trigger.entity_id and trigger.to_state.last_updated.

Unless someone here can suggest another solution, the question then is: How do I access home assistant’s logs from an automation in an “if” condition?

Looking forward to your tips and tricks.

Em

Use input_boolean (toggle) helpers in the three automations to record whether they made the change.

Trying to access history beyond the most-recent change (in a trigger variable) is not the way to go.

The values you see in the logs are derived from the trigger’s context variable.

You can retrieve the context information about you heater’s state change from the trigger variable.

yaml</s> <s>trigger:</s> <s> - platform: state</s> <s> entity_id: climate.example</s> <s>variables:</s> <s> id: "{{ trigger.to_state.context.id }}"</s> <s> parent: "{{ trigger.to_state.context.parent_id }}"</s> <s> user: "{{ trigger.to_state.context.user_id }}"</s> <s>

You will need to do a little testing to find the id and parent.id generated by your 3 automations, then use those in your condition:

yaml</s> <s>condition:</s> <s> - alias: Test if triggered by any of the 3 automations</s> <s> condition: template</s> <s> value_template: |</s> <s> {% set auto1 = ( EXAMPLE_id1, EXAMPLE_parent_id1 ) %}</s> <s> {% set auto2 = ( EXAMPLE_id2, EXAMPLE_parent_id2 ) %}</s> <s> {% set auto3 = ( EXAMPLE_id3, EXAMPLE_parent_id3 ) %}</s> <s>

EDIT: See below

Aha! Great stuff! I could not find correspondence of the parent_id’s value in any of the automation data (even in the id in the automation.yaml file is different) so I could not say for sure it was indeed related to an automation.

Thanks for the tip ! I will implement a solution and post the results.

I looked at the automation traces : the parent_id changes at each execution even though the same automation is the trigger. So in your proposition, the EXAMPLE_parent_id1 will be different every time. Hence it cannot be added to the code for comparaison.

I would need a way to identify the automation the parent_id represents, and I have not found a way yet.

For the time being, as a degraded solution, I can check parent_id to know if an automation (any automation) has triggered the change in state. Luckily I have no other automations than the three I mentionned that do that for the time being, but when this ceases to be the case, it will not work anymore.

Anyone has a clue on how to link the parent_id to the specific automation?

Based on your tests, this post, and some tests of my own, I think the following should work for the other two automations:

condition:
  - alias: Continue if not triggered by self or other automations
    condition: template
    value_template: |
      {% set automations = ['automation.EXAMPLE_1', 'automation.EXAMPLE_2'] %}
      {% set others =  expand(automations) | map(attribute='context.id') | list %}
      {{ trigger.to_state.context.id not in others }}

As mentioned in the last post of the linked thread, a 100% reliable way to avoid self-triggering other than setting the mode to single is proving more elusive.

1 Like

Will check that as soon as I can. Thanks !

I read the last post you mentioned and I am thinking : one could possibly use the last_changed or last_updated state attributes to sort out the mode issue. Will look into it.

You could definitely use last_triggered to throttle your automation…

condition: 
  - condition: template
    value_template: "{{ now() - this.attributes.last_triggered | default(as_datetime(0)) >= timedelta(minutes = 5) }}"

But, depending on the rest of the automation, that’s not exactly the same a making it unable to trigger itself and it would throttle all trigger sources/contexts.

Interesting… I was talking about the last_changed or last_updated attributes on the trigger.to_state state object and did not even think to the this state object… This one opens some new possibilities. Will dig.