I’ve read a number of people’s solutions for monitoring when a sensor stops updating to alert me and I wasn’t quite satisfied with any of them. Many used an automation template to compare the ‘time’ or ‘date_time’ to the desired sensor ‘last_updated’, however this seems like it would require a large number of automation to keep track of so I can be notified WHICH sensor to check.
I think I’ve come up with an elegant way to do this which gives me lots of flexibility. If I set MQTT to force_update I could even graph it on Lovelace and have an overview of any outlier sensors that may have signal issues since the interval should be regular.
Mine are temp-humidity, I want to catch a change to either (clearly if ANY update arrives it’s still updating) so I used an IF condition to grab whichever updated most recently.
The solution I came up with was using template sensors (since I’m already making sensors for each MQTT item) that track the seconds since the last update as so:
sensor:
- platform: template
sensors:
outside_front_sensor_age:
friendly_name: "Outside Front Sensor Age"
entity_id: sensor.time
value_template: >-
{% if states.sensor.outside_front_temperature.last_changed > states.sensor.outside_front_humidity.last_changed %}
{{ (states.sensor.time.last_changed - states.sensor.outside_front_temperature.last_changed).total_seconds() | round(0) }}
{% else %}
{{ (states.sensor.time.last_changed - states.sensor.outside_front_humidity.last_changed).total_seconds() | round(0) }}
{% endif %}
unit_of_measurement: "Seconds"
- platform: template
sensors:
outside_rear_sensor_age:
friendly_name: "Outside Rear Sensor Age"
entity_id: sensor.time
value_template: >-
{% if states.sensor.outside_rear_temperature.last_changed > states.sensor.outside_rear_humidity.last_changed %}
{{ (states.sensor.time.last_changed - states.sensor.outside_rear_temperature.last_changed).total_seconds() | round(0) }}
{% else %}
{{ (states.sensor.time.last_changed - states.sensor.outside_rear_humidity.last_changed).total_seconds() | round(0) }}
{% endif %}
unit_of_measurement: "Seconds"
- platform: template
sensors:
shed_driveway_sensor_age:
friendly_name: "Shed Driveway Sensor Age"
entity_id: sensor.time
value_template: >-
{% if states.sensor.shed_driveway_temperature.last_changed > states.sensor.shed_driveway_humidity.last_changed %}
{{ (states.sensor.time.last_changed - states.sensor.shed_driveway_temperature.last_changed).total_seconds() | round(0) }}
{% else %}
{{ (states.sensor.time.last_changed - states.sensor.shed_driveway_humidity.last_changed).total_seconds() | round(0) }}
{% endif %}
unit_of_measurement: "Seconds"
Now, I can use a single automation to easily message me for all the problems of interest to me, and based on the friendly_name I can be alerted if it’s the battery low, sensor age, or something else:
#System Status Alerts
- alias: 'Telegram Check Sensor Alert'
trigger:
# Low Battery Alerts
# Binary Sensor Alerts (on = alarm)
- entity_id:
# Acurite Temp & Humidity Sensors
- binary_sensor.outside_front_sensor_battery_low
- binary_sensor.outside_rear_sensor_battery_low
- binary_sensor.shed_driveway_sensor_battery_low
- binary_sensor.shed_backyard_sensor_battery_low
- binary_sensor.attic_sensor_battery_low
platform: state
from: 'off'
to: 'on'
# Reduce flapping
for:
minutes: 15
# Low Battery Alerts
- platform: numeric_state
entity_id:
# Zigbee
- sensor.washer_vibration_battery_level
- sensor.dryer_vibration_battery_level
# Z-Wave
- sensor.dining_room_gate_sensor_battery_level
below: 33
# Reduce flapping
for:
minutes: 15
# Monitor sensor age - not reporting in
- platform: numeric_state
entity_id:
# Acurite Temp & Humidity Sensors Age Expired
- sensor.outside_front_sensor_age
- sensor.outside_rear_sensor_age
- sensor.shed_driveway_sensor_age
- sensor.shed_backyard_sensor_age
- sensor.attic_sensor_age
# Seconds for timeout
above: 1800
action:
service: notify.telegram_my_user
data_template:
message: |
Warning - Check Sensor:
{{ trigger.to_state.attributes.friendly_name }}
The messages from this single automation then end up looking like this - clean and concise easily letting me know what to check:
To me, as a software engineer, this seems much easier and more modular for maintenance than having to keep track of a mess of automation…I can just make the sensors as I make the MQTT sensors and then add 1 line to my notification alerts. If I decide I need to be alerted via another method, I only have to change 1 automation and I can have it (for example) blink a light or send an email instead of Telegram messages. If I decide to change the interval, I can change it in 1 place on the alert automation. If I add a sensor, I don’t have to worry about copying the correct alert logic, I can just add the new sensor to the existing list. If I want to add more actions, I can simply reference the known working age calculations.
I also plan to make a watchdog automation to detect if ALL the sensors drop out and automatically try restarting RTL433, sometimes if the USB cable is bumped it seems to get stuck. This should be a lot easier now that I have sensors with numeric to compare instead of having to do a bunch of complex templates with conditions duplicating the same code as my alert…now I can simply reference the age-sensor values.
For my particular scenario (Accurite sensors) I have made a bash-script to generate my MQTT temp/humidity/battery sensors and filter/last_updated sensors given a numeric sensor-ID and location-name string. I’ve posted it on GitHub if someone wants to use it as a basis for making other bulk sensors.
I wish this was an easily referenced attribute I could use built into hassio, but in the meantime I guess this is nearly as convenient.