How do I check if an entity that went offline is online again?

I created an automation for entities that are offline (not available) for at least 5 minutes. The automation sends a notification to my phone and a persistant notification.

How can I achieve to check for the specific entity that triggered the automation to be online again (“on” or “off” state)? I don’t want to create an automation that simply states which entity went from offline to online because it would apply to even <1 min. offline states. Here is my automation so far. It distinguishes between devices directly connected and those who have a smart switch inbetween (because it would only be relevant to see them offline when the switch on the higher level is on):

alias: "Device goes offline"
description: ""
trigger:
  - platform: state
    entity_id:
      - light.example_light
      - switch.example_switch
      - cover.example_cover
    to: unavailable
    for:
      hours: 0
      minutes: 5
      seconds: 0
    alias: Devices without adapter offline
    id: Devices without adapter offline
  - platform: state
    entity_id:
      - switch.example_switch_with_adapter
      - light.example_light_with_adapter
    alias: "Media Center: devices offline"
    to: unavailable
    id: "Media Center: devices offline"
    for:
      hours: 0
      minutes: 5
      seconds: 0
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - Device without adapter offline
            alias: Device without adapter offline
        sequence:
          - service: notify.notify
            data:
              title: Device offline!
              message: >-
                {{ state_attr(trigger.to_state.entity_id, 'friendly_name') }}
                is offline for more than 5 minutes.
            alias: Push notification
          - service: notify.persistent_notification
            data:
              title: Device offline!
              message: >-
                {{ state_attr(trigger.to_state.entity_id, 'friendly_name') }}
                is offline for more than 5 minutes.
            alias: Notification
      - conditions:
          - condition: trigger
            id:
              - "Media Center: Device offline"
            alias: "A device connected to Media Center is offline"
          - condition: or
            conditions:
              - condition: state
                entity_id: switch.media_center
                state: "on"
                alias: " Media Center on"
              - condition: state
                entity_id: switch.media_center
                state: "off"
                alias: "Media Center aus"
            alias: "Media Center must be available"
        sequence:
          - service: notify.notify
            data:
              title: Device offline!
              message: >-
                {{ state_attr(trigger.to_state.entity_id, 'friendly_name') }}
                is offline for more than 5 minutes.
            alias: Push notification
          - service: notify.persistent_notification
            data:
              title: Device offline!
              message: >-
                {{ state_attr(trigger.to_state.entity_id, 'friendly_name') }}
               is offline for more than 5 minutes.
            alias: Notification
    alias: Notifications for offline devices
mode: parallel

Idea: trigger a new automation and make it check for the trigger of either “on” or “off” state for the entity that triggered automation #1. But how can I send

{{ trigger.to_state.entity_id) }}

to a new automation?

Use a State Trigger with from: unavailable

But where? As a “If/then” action? I guess the automation checks the device instantly and doesn’t wait for the state to change again…?

And in a new automation the problem is that it would apply to all devices that went offline for even 3 seconds.

That’s your choice; in the existing automation or a separate one.

Okay… situation: Switch goes offline for 5 minutes. Triggers the automation. Automation comes down to the “if/then” action. My question is: Does this automation apply instantly to check if the state is changing in that exact moment or does it wait until the device goes online again in any given time?

Your automation will trigger the moment either of its two State Triggers detects a monitored entity’s state changes to unavailable and remains that way for at least 5 minutes. The automation has no condition so it immediately proceeds to execute its action section.

My suggestion is to add a State Trigger that monitors the same entities when their state changes from unavailable (you can optionally add for). However, you’ll probably have to modify the logic in action because now the automation detects when an entity changes to and from unavailable.

But how does the automation distinguish then between devices that just went offline for a few seconds and those who went offline for at least 5 minutes? With another state trigger that just checks for devices going to a new state from “unavaibale” the automation doesn’t have that info and just fires.

I tried it now with

 {{ trigger.to_state.entity_id }}

in an If/then action but it turns out that you cannot use templates for state triggers. :confused:

Currently, you have configured your automation’s State Triggers to trigger only when the entity’s state is unavailable for at least 5 minutes. It ignores any entity that changed to unavailable for less than 5 minutes.

I suggest you use the same strategy for a State Trigger that monitors from unavailable.

  - id: "Media Center: devices online"
    platform: state
    entity_id:
      - switch.example_switch_with_adapter
      - light.example_light_with_adapter
    from: unavailable
    for:
      minutes: 5

Your trigger fires when a device changes its state from unavailable and stays in that new state (e.g. “on”) for 5 minutes right? So how it does it solve my problem? :confused: It would also fire when a device was unavailable for 1 minute before. Or am I not getting the logic here?

You had asked for this:

How can I achieve to check for the specific entity that triggered the automation to be online again (“on” or “off” state)?

The State Trigger I suggested is designed to detect an entity that has changed from unavailable to another state. Given that the State Trigger is monitoring multiple entities, you can determine which one changed using trigger.entity_id

But trigger.entity_id would apply either to an entity that went unavailable for at least 5 minutes or it would apply to an entity that went online again (on, off, unknown etc.). It doesn’t do both.

So when the automation is triggered for the second option (being available again), there is no way of knowing that the device it triggers on was offline before for at least 5 minutes. That was and still is my problem.

Is there a reason why you cannot fix the root cause of your entities becoming unavailable? It would spare you the need to create an automation that has to deal with so many outages that it has to triage which ones to report.

It is simply an automation for maintenance. For example my Logitech Harmony hub is constantly losing connection. Sometimes for more than 5 minutes, sometimes less. What I didn’t mention here is that my automation adds an entry into a Google sheet and also has the date and time for me to compare. So if I see a device like my Harmony hub a lot in there, I know I might have to fix that myself if possible. I had problems with certain switches from Osram in the past or with a light switch that was maybe too far away from the rest. An “unavailable” state that just persists for 3 seconds is maybe not so important if it doesn’t occur very often, with the 5 minutes mark I have a filter to show only devices that definitely need attention.

Now my sheet looks like this:

2023-10-01 22:08:49.256904 | Harmony Hub | 01.10.2023 | 22:08 | offline
2023-10-01 22:25:57.793862 | Harmony Hub | 01.10.2023 | 22:25 | offline
2023-10-01 22:37:51.802928| Harmony Hub | 01.10.2023 | 22:37 | online
2023-10-01 23:02:19.011462 | Harmony Hub | 01.10.2023 | 23:02 | online
2023-10-01 23:25:02.630409 | Harmony Hub | 01.10.2023 | 23:25 | online

As you can see, the online state will be there much more often because there is no way of knowing that a device went online again that was offline for at least 5 minutes before.

Regardless of the duration, it identifies the device has a communications problem.

Any device that frequently becomes unavailable needs attention. The big question is whether or not you can fix the root cause. Otherwise, the spreadsheet only serves to confirm what you already know: devices regularly disconnect from Home Assistant.


EDIT

Another way to do this would be to use just the State Trigger I had suggested but without the for option. When it triggers, you can compute how long the entity was unavailable by subtracting its trigger.from_state.last_changed from now(). Save the result (in seconds) to your spreadsheet and then you’ll see, on a single line, the entity’s name and how long it was offline.

1 Like

This is a great suggestion! :+1: Thank you for all the advice, I will do that. Saves me some time time to calculate. I will probably not use the notification for a device being online again since it would fire too often. Or I’ll see how annoyed I will be. :wink:

Now I have created two additional triggers for the “unavailable” state (trigger #1 is “to”, trigger #2 is “from”) without a given time and the action is only for my Google sheet. I will add an additional column for the time a device was offline.

I do this for every device. The pattern that works for me is this:

a) create a input boolean to enable / disable the alerting (this was you can mute things if it gets to annoying)
b) create a binary_sensor template that is on when the device is unavailable otherwise off. Use the delay_on and delay_off to control how long the condition must be in effect for the state to switch
c) create an alert that triggers off the binary_sensor template, set your repeat intervals, notification message and notifiers

Here’s an example for a ping sensor to determine if my deck camera is online. Since I has these for every device I use shell scripts to generate these packages.

####
#### Template
#### nw_cam_deck
#### 192.168.20.73 unreachable for 60 minutes
#### 60
#### 240
#### true
#### sms_notifiers_all

input_boolean:
  al_nw_cam_deck_alert_enable:
    name: nw_cam_deck alert enable
binary_sensor:
  - platform: template
    sensors:
      al_nw_cam_deck_alert:
        value_template: '{{ (states("binary_sensor.nw_cam_deck") != "on" ) and is_state("input_boolean.al_nw_cam_deck_alert_enable", "on") }}'
  - platform: ping
    host: 192.168.20.73
    name: nw_cam_deck
    scan_interval: 600
alert:
  al_nw_cam_deck:
    name: nw_cam_deck
    message: 'ALERT {{state_attr("zone.home","friendly_name")}} nw_cam_deck 192.168.20.73 unreachable for 60 minutes'
    done_message: 'Cleared {{state_attr("zone.home","friendly_name")}} nw_cam_deck 192.168.20.73 unreachable for 60 minutes'
    entity_id: binary_sensor.al_nw_cam_deck_alert
    state: "on"
    repeat:
      - 60
      - 240
    can_acknowledge: true
    skip_first: true
    notifiers:
      - sms_notifiers_all
      - sms_telegram_admin
recorder:
  include:
    entities:
      - binary_sensor.al_nw_cam_deck_alert
      - alert.al_nw_cam_deck
      - input_boolean.al_nw_cam_deck_alert_enable
      - binary_sensor.nw_cam_deck
      - sensor.nw_cam_deck_last_disconnect
      - sensor.nw_cam_deck_ping_average
template:
  - trigger:
      - platform: state
        entity_id: binary_sensor.nw_cam_deck
        from: "on"
        to: "off"
    sensor:
      - name: "nw_cam_deck_last_disconnect"
        state: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }} "
sensor:
  - platform: template
    sensors:
      nw_cam_deck_ping_average:
        value_template: >-
          {{ state_attr("binary_sensor.nw_cam_deck","round_trip_time_avg") }}
        unit_of_measurement: ms
2 Likes

Did it now like this:

{% set dauer = (as_timestamp(trigger.to_state.last_changed) - as_timestamp(trigger.from_state.last_changed)) %}
{{ dauer | timestamp_custom("%H:%M:%S", false) }}

… since I didn’t know how to format the seconds output it gave me with your suggestion.

{{ (trigger.to_state.last_changed - trigger.from_state.last_changed).total_seconds() }}

Or

{{ (now() - trigger.from_state.last_changed).total_seconds() }}

Look nice but for a newbee…
Where do I place this script?