#Label-based availability notification

1 messages · Page 1 of 1 (latest)

granite sentinel
#

Hi, I'm a relatively new Home Assistant user, but as a computer science student I have experience with programming various systems.

I wanted to figure out a nice, scalable method to make my HA notify me when a device turns unavailable. I'd like to share what I came up with here so that others could use it as a base or maybe share some feedback on it.

Some requirements I had:

  • I would like to receive notifications per device, not per entity. This should make sense - a device is a physical item, and it's likely that when there is a problem with the device, all or most of its entities will become unavailable, so I don't want to be spammed with messages, and I want it to be clear from the notification which device is malfunctioning.
  • It should be scalable and flexible: I would like this to work for any device, such that I don't have to create a different automation for some device which doesn't quite fit the system.
  • It should be easy to manage: I don't want to have to dig into yaml to add a device to some inclusion or exclusion list.
#

So, I came up with the following system:

First I created the following sensor. Attached to this post is an image of a flowchart I made to describe it, I recommend you check it out (scroll way down).

template:
  - sensor:
      - name: Monitored devices offline list
        unique_id: monitored_devices_offline_list
        state: >
          {% set _ = now() %}  {# forces re-eval each minute #}
          {% set monitor_label = 'availability_notify' %}
          {% set override_label = 'availability_override' %}
          {% set override_entities = label_entities(override_label) %}
          {% set offline = namespace(names=[]) %}

          {% for dev in label_devices(monitor_label) %}
            {% set ents = device_entities(dev) %}

            {# Get entities with the override label #}
            {% set overrides = ents | select('in', override_entities) | list %}


            {# If there is more than one override label #}
            {% if overrides | count > 0 %}
              {% if is_state(overrides[0], 'unavailable') %}
                {% set offline.names = offline.names + [device_name(dev)] %}
              {% endif %}
            {% else %}
              {# default: any entity unavailable counts as "offline" #}
              {% set bad = expand(ents) | selectattr('state','in',['unavailable']) | list %}
              {% if bad | count >= 1 %}
                {% set offline.names = offline.names + [device_name(dev)] %}
              {% endif %}
            {% endif %}
          {% endfor %}

          {{ offline.names | sort | tojson }}

#

An explanation of this sensor:
Firstly, it only tracks devices which have been given the label availability_notify. This way, we can decide on an include-basis which devices we would like to receive notifications for, simply by adding a label to this device. The default behavior is then to track state changes in these devices' entities, and if a single one goes unavailable, the device is considered unavailable (added to this sensor's state, which is a json-style list)."

However, I found that some integrations will have devices which have entities that are unavailable under normal circumstances, and this would then falsely classify the device as unavailable. So, I created another label availability_override, which allows you to specify which entity of a device will be considered. When you give a device's entity this label, the sensor will only consider that entity's availability and disregard other entities. Simple!

Example: Say you have a smart bulb. Most will have just one entity, and it should always be available. Here, we only have to use the availability_notify label.
However, some security cameras will have a whole load of entities, some of which may be unavailable, while the only one you truly care about is the camera sensor itself. Then, you can use the availability_override label as well to disregard those other entities.

#

Now, I have a sensor with the following state:

[device-1-name, device-2-name] where device-1 and device-2 are unavailable. Based on this we can quite easily make an automation which considers changes in this sensor's state. I'll add my current implementation for completeness:

alias: Device availability notifications
triggers:
  - entity_id: sensor.monitored_devices_offline_list
    trigger: state
conditions:
  - condition: template
    value_template: |
      {{ trigger.from_state is not none
         and trigger.to_state is not none
         and trigger.from_state.state not in ['unknown','unavailable','none','']
         and trigger.to_state.state not in ['unknown','unavailable','none',''] }}
variables:
  now: >
    {% set s = trigger.to_state.state %} {{ [] if s in
    ['unknown','unavailable','none',''] else (s | from_json) }}
  before: >
    {% set s = trigger.from_state.state if trigger.from_state else '' %} {{ []
    if s in ['unknown','unavailable','none',''] else (s | from_json) }}
  went_offline: "{{ now | reject('in', before) | list }}"
actions:
  - condition: template
    value_template: "{{ went_offline | count > 0 }}"
  - delay: "00:00:20"
  - variables:
      current: >
        {% set s = states('sensor.monitored_devices_offline_list') %} {{ [] if s
        in ['unknown','unavailable','none',''] else (s | from_json) }}
      still_offline: "{{ went_offline | select('in', current) | list }}"
  - condition: template
    value_template: "{{ still_offline | count > 0 }}"
  - # now here you can do some kind of notification, but it depends how you want to notify
mode: parallel
#

It seems to fit my own requirements:

  • The availability is tracked per device, and notifications show the name of the device.
  • It's flexible - we can decide which entity is considered by simply giving that entity a label
  • It's easy to manage. All we have to do is give devices and entities labels, which is easy and intuitive to do through the UI.

Let me know what you think!

#

Label-based availability notification

cursive willow
#

Following 🙂

iron cedar
#

I have something similar set up with a slightly different approach. The template sensor's state is the number of monitored (labeled) entities that are unavailable/unknown. (Monitored entities are generally a light, sensor, or binary_sensor of a device.) A list of unavailable/unknown entities is stored in an attribute. A regex_replace removes some extraneous text from the friendly_name and leaves just the device name. Storing the list as an attribute allows me to not only use that list in a notification via automation but can also be shown on a dashboard. Notifications are handled via three triggers: state change not_to 0, state change to 0, and at 06:00.

template:
  - trigger:
      - platform: time_pattern
        minutes: "/15"
        variables:
          unavailable_entities: |
            {{ label_entities('Monitored') | expand() | selectattr('state' , 'in' , ['unavailable','unknown']) | sort(attribute='name') | map(attribute='name') | list | regex_replace(find=' Battery Level| Battery', replace='', ignorecase=true) }}
          unavailable_entity_count: |
            {{ unavailable_entities  | count }}
          unavailable_entity_list: |
            {{ unavailable_entities | join(', ') }}
    sensor:
      - name: Unavailable Monitored Entities
        unique_id: 6fa6ca0b-0c4e-49e5-b95b-c4f3a28719fb
        state: "{{ unavailable_entity_count }}"
        attributes:
          monitored_entities_count: |
            {{ label_entities('Monitored') | expand() | map(attribute='name') | list | count }}
          unavailable: |
            {% if unavailable_entity_count | int > 0 %} {{ unavailable_entity_list }} {% else %} No unavailable entities {% endif %}
```(I was working on getting the sensor to compare the current list to the previous list in order to say what entity has returned but I couldn't get it working so it is not shown here.)
wooden abyss
#

I just keep a list of sensors I care about going unavailable in automations, in this case Doors. It sends me a notification to signal and adds it to a todo list inside HA. I suppose you could add a wait for trigger to automatically remove it too if it comes back online.

`alias: Door Sensor unavailable
description: Sends a notification when any door becomes unavailable.
triggers:

  • entity_id:
    • binary_sensor.bedroom_door
    • binary_sensor.front_door_contact
    • binary_sensor.slider_contact
    • binary_sensor.office_door_contact
    • binary_sensor.gun_closet_contact
    • binary_sensor.basement_door_contact
      to: unavailable
      trigger: state
      actions:
  • data:
    message: >
    {% set unavailable_sensor = trigger.entity_id %} The sensor "{{
    unavailable_sensor }}" is unavailable. Check its connection or power.
    action: notify.signal
  • action: todo.add_item
    metadata: {}
    data:
    item: >-
    {% set unavailable_sensor = trigger.entity_id %} The sensor "{{
    unavailable_sensor }}" is unavailable.
    target:
    entity_id: todo.sensor_is_unavailable
    mode: single`
wooden abyss
#

Well I made it the second automation too.

`alias: notification when any door becomes available.
description: Sends a notification when any door becomes available.
triggers:

  • entity_id:
    • binary_sensor.bedroom_door
    • binary_sensor.front_door_contact
    • binary_sensor.slider_contact
    • binary_sensor.office_door_contact
    • binary_sensor.gun_closet_contact
    • binary_sensor.basement_door_contact
      to:
    • "off"
    • "on"
      trigger: state
      conditions: []
      actions:
  • action: todo.remove_item
    metadata: {}
    data:
    item: >-
    {% set unavailable_sensor = trigger.entity_id %} The sensor "{{
    unavailable_sensor }}" is unavailable.
    target:
    entity_id: todo.sensor_is_unavailable
  • action: notify.signal
    metadata: {}
    data:
    message: >-
    {% set unavailable_sensor = trigger.entity_id %} The sensor "{{
    unavailable_sensor }}" is available.
    mode: single`
iron cedar
#

I just keep a list of sensors I care about going unavailable in automations
@wooden abyss Here's the beauty of what Krulknul and I have demonstrated: You don't have to update the automation when a new device is to be monitored (or removed from monitoring). Simply tag it and you're done.
In your case, you have multiple automations that would need maintaining. This is more of a "set it and forget it" automation.
Also, with the two automations you've shown, you can actually combine those into a single automation and get the same results. By using two triggers (with trigger_ids defined) and either Choose or IFs, you can perform the actions desired without needing separate automations. (Again, less maintenance, but also less clutter and better organization IMO.)
I actually just changed my automation from a trigger_id/Choose configuration to something that is even more template-based instead of handling multiple notification messages. It was a bit of a hassle to set up (because I don't completely know what I'm doing and it was also a learning experience), but I got it working. Also, if all entities are good and the daily_check runs, the notification won't be sent. This is what it looks like now:

wooden abyss
#

I choose two automations over trigger IDs. I don't actually like using trigger IDs as I find them harder to maintain when you start stacking different automations that affect the same stuff. I have multiple automations that call my lights off automation for instance. I do have many that do trigger IDs though.

I also have different urgency of notifications per devices Dead batteries are just less important than saying the alarm failed to arm. Given it's a bad example as a door sensor would cause the alarm to fail to arm here. Most of my not urgent notifications go to signal and silent. Alarm uses ha app notifications

kindred seal
#

See, I'm the complete opposite - I prefer keeping everything that controls a particular device (or device type - e.g. heating) to be in a single automation, so I know exactly where to look if it does something unexpected.