Graceful Shutdown Sensor

Thanks @Hellis81 , I am considering doing that. But not an ideal solution.
Would also need to find a way to cater for a restart after installing a new version.

OK, tried it. Still doesn’t trigger

alias: Utility - HA Shutdown Routine 2
description: Set Boolean to show system closed down cleanly
trigger:
  - platform: event
    event_type: homeassistant_stop
condition: []
action:
  - service: input_boolean.turn_on
    data: {}
    target:
      entity_id: input_boolean.ha_clean_shutdown
mode: single

OK, tried it. Still doesn’t trigger

type or paste code here

I don’t know what to tell you other than it works for me.

I’m using two Event Triggers (to detect homeassistant_started and homeassistant_stop) in a Trigger-based Template Sensor that records the time when Home Assistant starts and stops (i.e. shutdown).

I don’t use it in any automation, but in the mqtt integration it has the “Enable will message” option that apparently works fine.

You could set the will message to “Soft restart” and check it when the HA starts.
If topic = “Soft restart” do nothing and set the topic to “Running”
If topic = “Running” HA was not turned off properly, run your automations and set the topic to “Running”.

It wasn’t well explained, but I think it’s enough for you to get the idea.

Here’s a Trigger-based Template Sensor I recently created that reports one of two states on startup:

  • start if Home Assistant was shutdown normally prior to starting.
  • interrupt if Home Assistant was not shutdown normally prior to starting.

It also maintains a history of the ten most recent stop/started events, sorted in reverse chronological order (i.e. most recent is first). This attribute is optional.

- trigger:
    - platform: event
      event_type:
        - homeassistant_started
        - homeassistant_stop
  sensor:
    - name: Start Stop
      state: >
        {% if trigger.event.event_type == 'homeassistant_started' %}
          {{ iif(this.state|default('unknown') == 'shutdown', 'start', 'interrupt') }}
        {% else %}
          shutdown
        {% endif %}
      attributes:
        history: >
          {% set current = this.attributes.get('history', []) %}
          {% set new = [{
            "event": trigger.event.event_type[14:],
            "time": now().isoformat() }] %}
          {{ (new + current)[:10] }}

After creating the Trigger-based Template Sensor, it will initially report unknown. Initialize it by restarting Home Assistant (Developer Tools> YAML > Restart). On startup, it should now report start.

Here’s what it looks like on startup after Home Assistant was interrupted (i.e. not shutdown properly). The sensor reports interrupt. The history attribute shows there was no stop event prior to the most recent started event, indicating Home Assistant had been interrupted and didn’t get a chance to shutdown normally.

You can create an automation with a State Trigger to monitor the sensor when it changes to: interrupt and have it notify you that there was a recent interruption (potentially due to a power failure).


NOTE 1

Originally I tried to have the Event Trigger detect homeassistant_start which occurs before homeassistant_started but it failed to be detected. I assume it may be because the Template integration is loaded after the homeassistant_start event occurs so the Trigger-based Template Sensor never gets the opportunity to detect it.

NOTE 2

The history attribute is optional and can be eliminated without affecting the sensor’s operation. It’s included merely as a convenience; the sensor’s recorded History (i.e. in the database) shows the same information.

9 Likes

This is very clever. Thank you for sharing it.

That is indeed clever. And it seems to work for me too. Maybe because it’s not part of an automation. Whereas what I was trying was part of an automation.
Thanks very much.

1 Like

You’re welcome!

Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title which signals to other users that this topic has been resolved. This helps users find answers to similar questions.

For more information about the Solution tag, refer to guideline 21 in the FAQ.

I have used this idea to create an event state history for timers which will allow me to differentiate between timer.started, timer.paused, timer.restarted, timer.cancelled, and timer.finished instead of the timer states of active, idle, and paused.

Thank you, again, for the seed.

Hi Taras,

Ive been using this for the last week, and it works just fine (though I had an interrupt upon first restart ;-0

I just can not be sure I fully understand the state template, more specifically the iif section. Could you please explain what that does and why? Why is the ‘shutdown’ also listed in thehomeassistant_started if?

thx,

Here’s its theory of operation:

  • When Home Assistant is shutdown gracefully, the sensor sets its state to shutdown.

  • On startup, the sensor checks its previous state.

    • If it was shutdown, it changes its state to start.
    • If it was not shutdown, it changes its state to interrupt.

So if Home Assistant is not shutdown gracefully, the sensor never gets a chance to set its state to shutdown. It’s state remains as start (or unknown). On startup, the sensor detects that its previous state was not shutdown and reports interrupt.

The pseudo code for this:

        {% if trigger.event.event_type == 'homeassistant_started' %}
          {{ iif(this.state|default('unknown') == 'shutdown', 'start', 'interrupt') }}
        {% else %}
          shutdown
        {% endif %}

would be something like this:

IF Home Assistant just started
THEN
  IF my previous state was 'shutdown' (if I had no previous state then use 'unknown')
  THEN
    Set my state to 'start'
  ELSE 
    Set my state to 'interrupt'
ELSE 
  Set my state to 'shutdown'
1 Like

thanks for that last bit, because that (and the use of the ‘==’ operator) was what I am struggling with, especially given what is said in the warning box under:Templating - Home Assistant

I take it you’ve guarded that?

What it’s warning against is that it doesn’t care if the result of the test is true or false, it will always compute the values of if_true, if_false, and if_none.

This will work:

{{ x + 3 if x is defined else 3 }}

This will fail because it will attempt to evaluate x + 3 even when x is undefined.

{{ iif(x is defined, x + 3, 3) }}

The template I posted above isn’t affected by this behaviour because the values of its if_true and if_false are just strings.

2 Likes

thanks again Taras, that explains it very well.
I must admit I was thrown off by the ‘==’ and was looking for a closing ), but now see that the full

this.state|default('unknown') == 'shutdown'

compares to the

is_state('light.kitchen', 'on')

from the docs in the first iif example jut above that warning boxs…

btw, adding a unique_id to that trigger template makes it UI configurable, and I tried to create an extra on/off attribute, so we could easily use that in an automation trigger. Never sure if it updates to the latest state though, so I made this separate binary and that seems to operate correctly:

    sensor:
      - unique_id: graceful_shutdown_sensor
#         name: Graceful shutdown sensor
        state: >
          {% if trigger.event.event_type == 'homeassistant_started' %}
            {{ iif(this.state|default('unknown') == 'shutdown', 'start', 'interrupt') }}
          {% else %}
            shutdown
          {% endif %}
        icon: >
          mdi:restart{{'-alert' if this.state == 'interrupt'}}
        attributes:
          history: >
            {% set current = this.attributes.get('history', []) %}
            {% set new = [{
              "event": trigger.event.event_type[14:],
              "time": now().isoformat() }] %}
            {{ (new + current)[:10] }}

    binary_sensor:
       - unique_id: graceful_shutdown_sensor_binary
 #       name: Graceful shutdown
        state: >
          {{states('sensor.graceful_shutdown_sensor') != 'interrupt'}}

using a first time name during creation, and next commenting that, so the UI can take over.

note ‘interrupt’ at first launch/creation, and binary on, even though state is interrupt…? I have taken out the device_class afterwards though, as it is a positive binary, meaning ‘on’ is good…:

second restart:

I didn’t find a need for it given that a State Trigger with to: interrupt does the job.

yes, you are right.
I tend to create these binary ‘alerts’ so I can easily make frontend conditionals on those too, not only trigger automations. Even use those binary alerts in a container UI binary consisting of only binary_sensors…

but again, maybe I am overdoing things, and I could take several of these out. will scrutinize to see if deletion will bring me (back) some extra efficiency gain.
thanks anyways, its a very fine example of trigger based template and iif usage.
Should be in the docs!

@123 Even after multiples tries and reading of explanations, a plain copy/paste of the above code snippet doesn’t work : in the history attribute, I only see homeassistant_started events, no single homeassistant_stop events.
What could be missing to have it running like expected ?

I’m runing HA 2023.11.2 on Raspberry PI.

Big thanks if you can help !

Thanks for bringing this to my attention.

I have performed a test and was able to replicate your results. There’s no record of the sensor being able to detect Home Assistant’s homeassistant_stop event.

I modified the sensor’s code to use Homeassistant Trigger to detect the shutdown event but it still failed to detect it

  - platform: homeassistant
    event: shutdown

It appears that since I posted my example in March, something changed in Home Assistant that now prevents a Trigger-based Template Sensor from detecting any events involving the shutdown process.

1 Like

I’ve also tried the homeassistant trigger with same result.

The positive of this is that we are now at least 2 sharing this issue.
What action do you recommend ? Bug reporting ?

Thanks,