A script to check sensor last update

Hello everyone,
In my home set-up I have a bunch of Aqara sensors directly connected to a Homey that I use to monitor temperature and humidity (and for some of them, to trigger some automations based on those). Overtime they run out of battery and I only realised it when the automations don’t start or for the “passive” ones, only when I dive a little deeper in the Insights section.

My idea was to use a script to read at a regular interval (say every day) the last updated value of a given sensor and send a notification if this value is greater than one day (meaning that the sensor is battery dead or disconnected). I have a little experience with Javascript but not so much to dive into object and classes, so each of my attempt so far has miserably failed.

Can anyone be so nice to put me on the right path?
Thanks!

Not a script, but maybe useable

First create a numeric variable, it’s used to store the temperature of the sensor every 24h at 7AM.
If the stored temp and the real sensor’s temp is equal → send notification.
While the chance of the temp being exactly equal to the temp 24h ago is very small.
If it is equal, the battery or connection is down.

If…
Time is 7AM
And…
Logics [[Stored24hrsTemp]] is exactly [[RealSensorTemperature]]
Then…
Send notification
Else…
Logics set [[Stored24hrsTemp]] to [[RealSensorTemperature]]

In HomeyScript, there is an example script for getting sensor values:
example-printSensorValues.js

Hi Peter,
thanks for your suggestion! I was also considering using a flow and your logic definitely helps. (and works fine!) The only drawback is having to repeat it for every sensor. But I can live with that!

Thanks again!

1 Like

Hi JPe,
Thanks for your reply. I have been playing indeed with that script and I was able to get my home sensors’ values. But when it comes to the lastChanged property of the DeviceCapability class, it goes beyond my scripting skills and I don’t know how to cycle through and read those values. :frowning:

Don’t know ider, maybe @robertklep can give an example or hint?

Perhaps something like this:

const INVALIDATE_AFTER = 86400;

const invalidatedDevices = [];
for (const device of Object.values(await Homey.devices.getDevices())) {
  for (const capabilityObj of Object.values(device.capabilitiesObj || {})) {
    if (capabilityObj.lastUpdated && (Date.now() - new Date(capabilityObj.lastUpdated) > INVALIDATE_AFTER * 1000)) {
      invalidatedDevices.push(device.name);
    }
  }
}
await tag('InvalidatedDevices', invalidatedDevices.join(', '));
return invalidatedDevices.length != 0;

This will mark a device as invalid if it hasn’t updated for at least one day (86400 seconds). It will set a token that can be used in a notification.

2 Likes

Thanks Robert, a good starting point, however running it, (almost?) all my devices showed up as timed-out. Soo I added some console.log and found that per device, there are several loglines, here is an example from an active sensor:

sensor T & H Sensor Terras 2022-05-01T14:45:19.470Z 120299 ---ok----
sensor T & H Sensor Terras 2022-05-01T14:45:19.551Z 120222 ---ok----
sensor T & H Sensor Terras 2022-04-26T09:59:52.787Z 449246990 >NOK<
sensor T & H Sensor Terras 2022-03-15T02:43:00.909Z 4104258872 >NOK<

looks like memory pollution for me.

There isn’t a per-device “last updated” field so it has to check every capability of each device, that’s why you get multiple logs per device.

Right now, it will mark a device as “invalid” if one of the capabilities is older than 1 day, but I guess it makes more sense if it only invalidates a device is all of the capabilities are too old:

const INVALIDATE_AFTER = 86400;

const invalidatedDevices = [];
for (const device of Object.values(await Homey.devices.getDevices())) {
  if (! device.capabilitiesObj) continue;
  let count = 0;
  for (const capabilityObj of Object.values(device.capabilitiesObj)) {
    if (! capabilityObj.lastUpdated || (Date.now() - new Date(capabilityObj.lastUpdated) > INVALIDATE_AFTER * 1000)) {
      count++;
    }
  }
  if (count && count === Object.keys(device.capabilitiesObj).length) {
    invalidatedDevices.push(device.name);
  }
}
await tag('InvalidatedDevices', invalidatedDevices.join(', '));
return invalidatedDevices.length != 0;

EDIT: I modified the script to handle capabilities that don’t have a lastUpdated. These are now treated the same as an “expired” capability.

2 Likes