Alert when sensors stop updating

Hello, I would like to create an automation that alerts me when any of my sensors stop updating (i.e. I do not need to be alerted if they report unchanged values, only in case they disappear completely). I am trying the following code but I still get notifications about unchanged values. N.b. all my sensors report in via MQTT.

automation:
  - trigger:
      platform: state
      entity_id:.
      - sensor.living_room_temperature_1
      - sensor.outside_temperature
      - sensor.bedroom_temperature
      - sensor.kitchen_temperature
    condition:
      condition: template
      value_template: >
        {{ (now() - trigger.from_state.last_updated | default(0)).total_seconds() > 600 }}
    action:
      service: notify.telegram
      data_template:
        message: "{{ trigger.from_state.attributes.friendly_name }} has not updated since 10 min"

If the sensor doesnā€™t update, then it can never trigger anything.

Then why am I getting notifications based on the above code? :slight_smile:

The only way your automation can trigger is if one of these changes:

      - sensor.living_room_temperature_1
      - sensor.outside_temperature
      - sensor.bedroom_temperature
      - sensor.kitchen_temperature

Therefore there is something wrong with your condition. Thatā€™s why you are getting notifications. Fix that and it will never alert you.

For example this correctly constructed template will prevent you ever receiving the message.:


value_template: "{{ ( as_timestamp(now()) - as_timestamp(state_attr('automation.your_automation_id', 'last_triggered')) |int(0) ) > 600 }}"

OK, I get it, in this case the original approach is completely wrong. Could you give me any other pointers on how I can achieve the goal above? I have seen some threads on this but nothing very straightforward and all requires a lot of copy-pasting around if I want to monitor multiple sensors. Should I go appdaemon instead?

You could use a template sensor (for each sensor you want to monitor):

 trigger:
    platform: template
    value_template: "{{ (as_timestamp(strptime(states('sensor.date_time'),'%Y-%m-%d, %H:%M')) - as_timestamp(states.sensor.living_room_temperature_1.last_changed) )  > 600 }}"

Restating home assistant will update the last_changed attribute though. So if your sensor hasnā€™t changed for 500 seconds then you restart, it will take another 600 seconds of no updates after the restart for it to trigger.

If thatā€™s important there are ways to rectify it:

OK, I have this code now:

automation:
  - trigger:
      platform: template
      value_template: >
        {{ (as_timestamp(strptime(states('sensor.date_time'),'%Y-%m-%d, %H:%M')) - as_timestamp(states.sensor.bedroom_temperature.last_changed) )  > 600 }}
    action:
      service: notify.telegram
      data_template:
        message: "Bedroom temperature has not updated since 10 min"

And I still get this error:

2019-07-12 18:18:02 ERROR (MainThread) [homeassistant.core] Error doing job: Exception in callback <function async_track_state_change.<locals>.state_change_listener at 0x7fdfac1d29d8>
Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 68, in uvloop.loop.Handle._run
  File "/usr/src/app/homeassistant/helpers/event.py", line 85, in state_change_listener
    event.data.get('new_state'))
  File "/usr/src/app/homeassistant/core.py", line 342, in async_run_job
    target(*args)
  File "/usr/src/app/homeassistant/helpers/event.py", line 106, in template_condition_listener
    template_result = condition.async_template(hass, template, variables)
  File "/usr/src/app/homeassistant/helpers/condition.py", line 331, in async_template
    value = value_template.async_render(variables)
  File "/usr/src/app/homeassistant/helpers/template.py", line 191, in async_render
    return self._compiled.render(kwargs).strip()
  File "/usr/local/lib/python3.7/site-packages/jinja2/asyncsupport.py", line 76, in render
    return original_render(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1008, in render
    return self.environment.handle_exception(exc_info, True)
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 780, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 37, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'

1 Like

Reply to myself, the above error is solved by adding a time_date sensor as follows:

sensor:
  - platform: time_date
    display_options:
    - "date_time"

Now it works fine, apart from the fact that contrary to the initial expectation, it DOES notify also in cases where the sensor publishes data but that data is unchanged from the previously published data. How to solve this?

Use the last_updated instead of last_changed attribute.

That doesnā€™t seem to achieve this (also see here)ā€¦

You need to monitor mqtt messages, not the sensor. If you get the same value your sensor will say: 19Ā°c 1 hour ago or 6 hours ago if itā€™s stable - even if it got a temperature update every minute.

Jhh

This topic has special interest to me, as I have a couple sensors which are locking-up every now and then and stop sending updates, and so Iā€™m setting up an automation to send me a message when that happens - a precursor to a fully-automated restart.

My minor contribution is this: if you use ā€˜now()ā€™ on your template expression, you donā€™t need to define a date_time sensor at all - which seems silly. Also, at least here (0.100.3), LastUpdated is already a timestamp (at least when queried with state_attr), so no need to convert. The final template expression looks like this:

{{ ( as_timestamp(now()) - state_attr('sensor.living_room_temperature_1', 'LastUpdated') ) > 600 }}

What kind of temperature sensor are you using? Specifically, which integration?

Iā€™m asking because LastUpdated is not an attribute of Home Assistantā€™s sensor entity. There is last_updated and itā€™s a property of the entityā€™s State Object. The State Object also supports attributes but LastUpdated is not one of them.

LastUpdated must be unique to the sensor platform you are using and the clue is that its name is in propercase. All of Home Assistantā€™s nomenclature (entity names, properties, options, etc) is expressed in lowercase. The other clue is that you stated its value is a timestamp whereas Home Assistant stores datetime values as a datetime object (or a string).

if you use ā€˜now()ā€™ on your template expression, you donā€™t need to define a date_time sensor at all - which seems silly.

now() is a function. If used in a Template Sensor, it is evaluated when Home Assistant starts and never again (until the next restart). That means if you use this template in a Template Sensor:

{{ ( as_timestamp(now()) - state_attr('sensor.living_room_temperature_1', 'LastUpdated') ) > 600 }}

after startup, the template will be evaluated only when the value of LastUpdated changes. If there is a need for this template to be evaluated periodically, like when the time changes from one minute to the next, this template will fail to do that. Thatā€™s because Home Assistant only monitors the changes of entities (that it can identify within the template) and not functions such as now().

Thatā€™s why a date_time sensor is often employed in Template Sensors when thereā€™s a need to have the template evaluated periodically. For example, sensor.time changes every minute whereas sensor.date changes once every day.

2 Likes

Interesting, I just went poking around and noticed that this is indeed not common on most integrations - I was so accustomed to seeing it with the entities Iā€™m monitoring that I assumed it to be standard.

The particular integration Iā€™m pulling this attribute from is an Open Energy Monitor integration using the emoncms platform. It exposes a rather rich set of attributes for each entity:

- FeedId
- Tag
- FeedName
- Size
- UserId
- LastUpdated (in epoch format)
- LastUpdatedStr (in datetime format)
- unit_of_measurement
- friendly_name

With regards to the usage of the now() function:

Ouch, that explains what I observed when I put this in practice and was not seeing the automation trigger once the condition was met. My bad and thanks a lot for pointing this newbie mistake!

Conclusion?

Huge thanks to Taras for correcting my mistakes! And to everyone looking at this thread for advice on watchdog automations for sensors prone to freezing, disregard what I said earlier, especially the bit about now() :wink:

1 Like

Hello together,

I am currently facing a similar challange. I have about 10 Aqara Temperature Sensors and I control our heating system with them. For security reasons, I would like to get a notification when a sensor is not working anymore, so I would like to get notified when a sensor has not changed its state for ~2 hour.

Iā€™ve been trying to figure out your solutions and I have created the following automation, but itā€™s not working.

Any idea whatā€™s wrong?

Thank you!

- id: sensor_warning_test
  alias: Sensor Warning Test
  trigger:
    platform: state
    entity_id: sensor.sensor_wohnzimmer_temp
  condition:
    condition: template
    value_template: "{{ ( as_timestamp(now()) - state_attr('sensor.sensor_wohnzimmer_temp', 'LastUpdated') ) > 10 }}"
  action:
    service: notify.alles
    data:
      title: Sensor-Warning!
      message: 'Sensor Wohnzimmer has not been updated for 10 Seconds!'
1 Like

I have put together a standalone application for this purpose meanwhile. It is one single binary (written in Go) which subscribes to specified MQTT topics, monitors incoming messages and alerts via Telegram in case a topic stops receiving messages (time threshold is calculated automatically based on past transmission frequency). It also supports pinging hosts and alerting in case of no reply. It has a simple web ui (see screenshot below) for viewing status and reloading configuration.

I use it now to monitor all my home automation devices, it does this task only but reliably. Let me know if this is of any interest - if so, I can upload the source code to github.

1 Like

If you paste this into the Template Editor, does it report a numeric value?

{{ as_timestamp(now()) - state_attr('sensor.sensor_wohnzimmer_temp', 'LastUpdated') }}

It just says:

Unknown error rendering template

Thatā€™s the same template used in your automationā€™s condition and probably explains why the automation doesnā€™t work.

Paste this into the Template Editor and confirm it returns a valid timestamp:

{{ state_attr('sensor.sensor_wohnzimmer_temp', 'LastUpdated') }}

If it does not report a timestamp then you need to re-design your template.

Thanks for this hint, I have now changed the template to the following:

{{ (as_timestamp(now())-as_timestamp(states.sensor.sensor_wohnzimmer_temp.last_updated))
      | int //60}}

Returns: 27

{{ (as_timestamp(now())-as_timestamp(states.sensor.sensor_wohnzimmer_temp.last_updated))
      | int //60 > 30}}

Returns: False / True

The whole automation now looks like this, but it seems like there is something wrong with the trigger - it doesnā€™t get triggered when the ā€œlast_updatedā€ value gets over 30 Minutes.
Any ideas?

- id: sensor_warning_test
  alias: Sensor Warning Test
  trigger:
  - entity_id: sensor.sensor_wohnzimmer_temp
    platform: state
  condition:
  - condition: template
    value_template: '{{ (as_timestamp(now())-as_timestamp(states.sensor.sensor_wohnzimmer_temp.last_updated))
      | int //60 > 30}}'
  action:
  - data:
      message: Sensor Wohnzimmer has not been updated for 30 Minutes!
      title: Sensor-Warning!
    service: notify.alles