diff --git a/lib/extension/deviceAvailability.js b/lib/extension/deviceAvailability.js index 4c70433e..e658a429 100644 --- a/lib/extension/deviceAvailability.js +++ b/lib/extension/deviceAvailability.js @@ -4,18 +4,13 @@ const utils = require('../util/utils'); const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters'); const BaseExtension = require('./baseExtension'); -// Some EndDevices should be pinged +// Pingable end devices, some end devices should be pinged // e.g. E11-G13 https://github.com/Koenkk/zigbee2mqtt/issues/775#issuecomment-453683846 -const pingableModels = [ - 'E11-G13', - '53170161', +const pingableEndDevices = [ + zigbeeHerdsmanConverters.devices.find((d) => d.model === 'E11-G13'), + zigbeeHerdsmanConverters.devices.find((d) => d.model === '53170161'), ]; -const forcedPingable = - zigbeeHerdsmanConverters.devices.filter((d) => pingableModels.includes(d.model)); - -const toZigbeeCandidates = ['state', 'brightness', 'color', 'color_temp']; - const Hours25 = 1000 * 60 * 60 * 25; /** @@ -29,22 +24,14 @@ class DeviceAvailability extends BaseExtension { this.timers = {}; this.state = {}; - // Initialize blacklist - this.blacklist = settings.get().advanced.availability_blacklist.map((e) => { - return settings.getEntity(e).ID; - }); - - // Initialize whitelist - this.whitelist = settings.get().advanced.availability_whitelist.map((e) => { - return settings.getEntity(e).ID; - }); + this.blacklist = settings.get().advanced.availability_blacklist.map((e) => settings.getEntity(e).ID); + this.whitelist = settings.get().advanced.availability_whitelist.map((e) => settings.getEntity(e).ID); } - isAllowed(device) { + inWhitelistOrNotInBlacklist(device) { const ieeeAddr = device.ieeeAddr; - const deviceSettings = settings.getDevice(ieeeAddr); - const name = deviceSettings.friendly_name; + const name = deviceSettings.friendlyName; // Whitelist is not empty and device is in it, enable availability if (this.whitelist.length > 0) { @@ -60,15 +47,12 @@ class DeviceAvailability extends BaseExtension { } isPingable(device) { - // Device is on forcedPingable-list, enable availability - if (forcedPingable.find((d) => d.zigbeeModel.includes(device.modelID))) { + if (pingableEndDevices.find((d) => d.zigbeeModel.includes(device.modelID))) { return true; } // Device is a mains powered router - const result = utils.isRouter(device) && !utils.isBatteryPowered(device); - - return result; + return utils.isRouter(device) && !utils.isBatteryPowered(device); } onMQTTConnected() { @@ -76,7 +60,7 @@ class DeviceAvailability extends BaseExtension { // Mark all devices as online on start this.publishAvailability(device, true); - if (this.isAllowed(device)) { + if (this.inWhitelistOrNotInBlacklist(device)) { if (this.isPingable(device)) { this.setTimerPingable(device); } else { @@ -90,21 +74,20 @@ class DeviceAvailability extends BaseExtension { async handleIntervalPingable(device) { // When a device is already unavailable, log the ping failed on 'debug' instead of 'error'. - const entity = this.zigbee.resolveEntity(device.ieeeAddr); - if (!entity) { + const resolvedEntity = this.zigbee.resolveEntity(device.ieeeAddr); + if (!resolvedEntity) { logger.debug(`Stop pinging '${device.ieeeAddr}', device is not known anymore`); return; } - const ieeeAddr = device.ieeeAddr; - const level = this.state.hasOwnProperty(ieeeAddr) && !this.state[ieeeAddr] ? 'debug' : 'error'; + const level = this.state.hasOwnProperty(device.ieeeAddr) && !this.state[device.ieeeAddr] ? 'debug' : 'error'; try { await device.ping(); this.publishAvailability(device, true); - logger.debug(`Successfully pinged '${entity.name}'`); + logger.debug(`Successfully pinged '${resolvedEntity.name}'`); } catch (error) { this.publishAvailability(device, false); - logger[level](`Failed to ping '${entity.name}'`); + logger[level](`Failed to ping '${resolvedEntity.name}'`); } finally { this.setTimerPingable(device); } @@ -112,12 +95,12 @@ class DeviceAvailability extends BaseExtension { async handleIntervalNotPingable(device) { const ago = Date.now() - device.lastSeen; - const entity = this.zigbee.resolveEntity(device.ieeeAddr); - if (!entity || !device.lastSeen) { + const resolvedEntity = this.zigbee.resolveEntity(device.ieeeAddr); + if (!resolvedEntity || !device.lastSeen) { return; } - logger.debug(`Non-pingable device '${entity.name}' was last seen '${ago / 1000}' seconds ago.`); + logger.debug(`Non-pingable device '${resolvedEntity.name}' was last seen '${ago / 1000}' seconds ago.`); if (ago > Hours25) { this.publishAvailability(device, false); @@ -143,23 +126,19 @@ class DeviceAvailability extends BaseExtension { } async onReconnect(device) { - if (device && device.modelID) { - const definition = zigbeeHerdsmanConverters.findByZigbeeModel(device.modelID); - - if (definition) { - const used = []; - try { - for (const key of toZigbeeCandidates) { - const converter = definition.toZigbee.find((tz) => tz.key.includes(key)); - if (converter && !used.includes(converter)) { - await converter.convertGet(device.endpoints[0], key, {}); - used.push(converter); - } + const resolvedEntity = this.zigbee.resolveEntity(device); + if (resolvedEntity && resolvedEntity.definition) { + const used = []; + try { + for (const key of ['state', 'brightness', 'color', 'color_temp']) { + const converter = resolvedEntity.definition.toZigbee.find((tz) => tz.key.includes(key)); + if (converter && !used.includes(converter)) { + await converter.convertGet(device.endpoints[0], key, {}); + used.push(converter); } - } catch (error) { - const entity = this.zigbee.resolveEntity(device.ieeeAddr); - logger.error(`Failed to read state of '${entity.name}' after reconnect`); } + } catch (error) { + logger.error(`Failed to read state of '${resolvedEntity.name}' after reconnect`); } } } @@ -171,7 +150,7 @@ class DeviceAvailability extends BaseExtension { } const deviceSettings = settings.getDevice(ieeeAddr); - const name = deviceSettings ? deviceSettings.friendly_name : ieeeAddr; + const name = deviceSettings ? deviceSettings.friendlyName : ieeeAddr; const topic = `${name}/availability`; const payload = available ? 'online' : 'offline'; if (this.state[ieeeAddr] !== available) { @@ -186,7 +165,7 @@ class DeviceAvailability extends BaseExtension { return; } - if (this.isAllowed(device)) { + if (this.inWhitelistOrNotInBlacklist(device)) { this.publishAvailability(data.device, true); if (this.isPingable(device)) {