HomeyScript - Dead device checks

I have had some challenges with devices being “dead” as in not reporting updates or actually being dead. Primairly the problem has been related to zigbee devices which is reporting temperature which again is used as input to advanced flows to control temperature. It ends up being quite elaborate and I am wondering if there is some better way to do this. Process consist of a homey flow which triggers scripts where the output from the script is then used to determine if action should be taken to check the device ( meaning restart etc manually).

// Get all Zigbee devices and convert to array
const zigbeeDevicesArray = Object.values(await Homey.devices.getDevices());

// Filter Zigbee devices based on the 'measure_temperature' capability and a specific driver ID
const zigbeeFilteredDevices = zigbeeDevicesArray.filter(device =>
  device.capabilitiesObj &&
  device.capabilitiesObj.measure_temperature &&
  device.driverId === 'homey:app:com.xiaomi-mi:weather' // Filtering to include only Xiaomi Mi weather devices
);

// Map Zigbee devices to include name and last update information from all relevant capabilities
const zigbeeDeviceInfoArray = zigbeeFilteredDevices.map(device => {
  const temperatureCapability = device.capabilitiesObj.measure_temperature;
  const humidityCapability = device.capabilitiesObj.measure_humidity;
  const pressureCapability = device.capabilitiesObj.measure_pressure;

  const tempUpdated = new Date(temperatureCapability.lastUpdated);
  const humidityUpdated = humidityCapability ? new Date(humidityCapability.lastUpdated) : tempUpdated;
  const pressureUpdated = pressureCapability ? new Date(pressureCapability.lastUpdated) : tempUpdated;
  const mostRecentUpdate = new Date(Math.max(tempUpdated, humidityUpdated, pressureUpdated));

  const formattedMostRecentDate = new Intl.DateTimeFormat('en-GB', {
    year: 'numeric', month: '2-digit', day: '2-digit',
    hour: '2-digit', minute: '2-digit', second: '2-digit',
    timeZone: 'Europe/Oslo',
    timeZoneName: 'short'
  }).format(mostRecentUpdate);

  return {
    name: device.name,
    lastUpdated: formattedMostRecentDate,
    lastUpdatedRaw: mostRecentUpdate
  };
});

// Find the Zigbee device with the oldest temperature update
const oldestZigbeeDevice = zigbeeDeviceInfoArray.reduce((oldest, device) => {
  return (!oldest || device.lastUpdatedRaw < oldest.lastUpdatedRaw) ? device : oldest;
}, null);

// Actions based on the found oldest device
if (oldestZigbeeDevice) {
  // Calculate the number of hours since the last update of the oldest device
  const currentTime = new Date();
  const zigbeeDevice_hoursSinceUpdate = Math.round(
    (currentTime - oldestZigbeeDevice.lastUpdatedRaw) / (1000 * 60 * 60)
  );

  // Set tags for Homey flow, ensuring they are descriptive and protocol-specific
  await tag('zigbee_oldestDeviceName', oldestZigbeeDevice.name);
  await tag('zigbee_oldestReadingDate', oldestZigbeeDevice.lastUpdated);
  await tag('zigbee_hoursSinceLastUpdate', zigbeeDevice_hoursSinceUpdate);

  // Return values for testing and further use in flows or debugging
  return {
    zigbee_oldestDeviceName: oldestZigbeeDevice.name,
    zigbee_oldestReadingDate: oldestZigbeeDevice.lastUpdated,
    zigbee_hoursSinceLastUpdate: zigbeeDevice_hoursSinceUpdate
  };
} else {
  log('No Zigbee devices found with temperature measurement capabilities from Xiaomi Mi weather.');
  return 'No Zigbee devices found';
}

1 Like

thanks. So this script basically does the same I guess.

Of course sensors shouldn’t go silent to start with.
Do you happen to have Aqara sensors and Ikea tradfri lights in Homey’s zigbee mesh?
This combo caused the Aqara’s to go silent @ Pro 2019.
Replacing the Ikea with Lidl lights solved it.

What is the solution for Z-Wave? I see you have a script for it, but the script you have published is only for ZigBee with Aqara app as i see it.

Not directly for ZWAVE, but for anything else this can be used :

Z-Wave do not have “Last seen” data available, so it can be based only on capabilities update date.

Yeah, that is right. That’s why i was asking for the Z-Wave . Maybe @mikkel_Antonsen , do now, something we do not :blush: Ps @Sharkys : you should update your script. “DriverUri” does not work for people that are adding new script. “ownerUri” works better.

It might be very possible you are using the test version of Homeyscript?
Please use the stable version when you are not busy or wanting to test the script, now it’s all becoming very confusing imho
I think when HS app test version gets promoted to stable, we can discuss what does not work anymore in existing scripts added as new scripts?
Just a thought.

I have it actually already updated locally, both of them but there is existing issue which Athom shall address. Waiting for their actions until HomeyScript 3.5.2 will be released.

1 Like

I have done it this way :slight_smile: Seems to work fine

async function fetchOldestZWaveDeviceDetails() {
    // Get all Z-Wave devices and convert to array
    const zWaveDevicesArray = Object.values(await Homey.devices.getDevices());

    // Filter Z-Wave devices based on the ‘measure_temperature’ capability and the specific driver ID for Z-TRM3
    const zWaveFilteredDevices = zWaveDevicesArray.filter(device =>
      device.capabilitiesObj &&
      device.capabilitiesObj.measure_temperature &&
      device.driverId === 'homey:app:no.thermofloor:Z-TRM3'
    );

    // Check if any devices are found after filtering
    if (zWaveFilteredDevices.length === 0) {
        console.log('No Z-Wave devices found with temperature measurement capabilities for the specified driver.');
        return 'No Z-Wave devices found';
    }

    // Map Z-Wave devices to include name and last update information from all relevant capabilities
    const zWaveDeviceInfoArray = zWaveFilteredDevices.map(device => {
      const temperatureCapability = device.capabilitiesObj.measure_temperature;
      const humidityCapability = device.capabilitiesObj.measure_humidity;
      const pressureCapability = device.capabilitiesObj.measure_pressure;

      const tempUpdated = new Date(temperatureCapability.lastUpdated);
      const humidityUpdated = humidityCapability ? new Date(humidityCapability.lastUpdated) : tempUpdated;
      const pressureUpdated = pressureCapability ? new Date(pressureCapability.lastUpdated) : tempUpdated;
      const mostRecentUpdate = new Date(Math.max(tempUpdated, humidityUpdated, pressureUpdated));

      const formattedMostRecentDate = new Intl.DateTimeFormat('en-GB', {
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit', second: '2-digit',
        timeZone: 'Europe/Oslo',
        timeZoneName: 'short'
      }).format(mostRecentUpdate);

      return {
        name: device.name,
        lastUpdated: formattedMostRecentDate,
        lastUpdatedRaw: mostRecentUpdate
      };
    });

    // Find the Z-Wave device with the oldest temperature update
    const oldestZWaveDevice = zWaveDeviceInfoArray.reduce((oldest, device) => {
      return (!oldest || device.lastUpdatedRaw < oldest.lastUpdatedRaw) ? device : oldest;
    });

    // Calculate the number of hours since the last update of the oldest device
    const currentTime = new Date();
    console.log(`Current Time: ${currentTime.toISOString()}`);
    console.log(`Last Updated: ${oldestZWaveDevice.lastUpdatedRaw.toISOString()}`);

    if (isNaN(oldestZWaveDevice.lastUpdatedRaw.getTime())) {
        console.log("Invalid date detected for last update.");
        return 'Invalid date';
    }

    const zWaveDevice_hoursSinceUpdate = Math.round(
      (currentTime - oldestZWaveDevice.lastUpdatedRaw) / (1000 * 60 * 60)
    );

    if (zWaveDevice_hoursSinceUpdate < 0) {
        console.log("Detected negative hours since last update, which may indicate future timestamp in device data.");
    }

    // Set tags for Homey flow, ensuring they are descriptive and protocol-specific
    await tag('oldest_zwave_DeviceName', oldestZWaveDevice.name);
    await tag('oldest_zwave_ReadingDate', oldestZWaveDevice.lastUpdated);
    await tag('z_wavedevice_hourssinceupdate', zWaveDevice_hoursSinceUpdate);

    // Log details for further actions or debugging
    console.log(`Oldest Z-Wave device details: Name - ${oldestZWaveDevice.name}, Last Update - ${oldestZWaveDevice.lastUpdated}, Hours Since Last Update - ${zWaveDevice_hoursSinceUpdate}`);

    // Return a structured object with relevant details
    return {
        oldest_zwave_DeviceName: oldestZWaveDevice.name,
        oldest_zwave_ReadingDate: oldestZWaveDevice.lastUpdated,
        z_wavedevice_hourssinceupdate: zWaveDevice_hoursSinceUpdate
    };
}

// Execute the function
fetchOldestZWaveDeviceDetails().then(details => {
    console.log("Z-Wave device details fetched successfully.");
    console.log("Returned:", details);
});