zigbee2mqtt/lib/extension/deviceReport.js

102 lines
3.4 KiB
JavaScript

const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
const logger = require('../util/logger');
const candidates = {
'genOnOff': {
attrs: ['onOff'],
reportIntervalMin: 3,
reportIntervalMax: 300,
reportableChange: 0,
},
'genLevelCtrl': {
attrs: ['currentLevel'],
},
'lightingColorCtrl': {
attrs: ['colorTemperature', 'currentX', 'currentY'],
},
};
const reportInterval = {
min: 3,
max: 3600,
};
const reportableChange = 1;
class DeviceReport {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishEntityState = publishEntityState;
}
setupReporting(mappedDevice, device) {
let epId = null;
// Check if this device uses a different epId.
if (mappedDevice.hasOwnProperty('ep')) {
const eps = mappedDevice.ep(device);
epId = eps[''] || null;
}
const endpoint = this.zigbee.getEndpoint(device.ieeeAddr, epId);
if (!endpoint) {
logger.error(`Failed to setup reporting for ${device.ieeeAddr}, endpoint not found`);
return;
}
logger.debug(`Setting up reporting for ${device.ieeeAddr}`);
Object.values(endpoint.clusters).filter((c) => c).forEach((c) => {
const cluster = c.attrs.cid;
if (candidates[cluster]) {
const candidate = candidates[cluster];
let attributeNames = candidate.attrs.filter((a) => c.attrs.hasOwnProperty(a));
// Sometimes a cluster has no attributes, in this case setup reporting for all attributes.
attributeNames = attributeNames.length ? attributeNames : candidate.attrs;
const attributes = attributeNames.map((attribute) => {
return {
attr: attribute,
min: candidate.hasOwnProperty('reportIntervalMin')?
candidate.reportIntervalMin:reportInterval.min,
max: candidate.hasOwnProperty('reportIntervalMax')?
candidate.reportIntervalMax:reportInterval.max,
change: candidate.hasOwnProperty('reportableChange')?
candidate.reportableChange:reportableChange,
};
});
if (attributes.length > 0) {
this.zigbee.report(endpoint, cluster, attributes);
}
}
});
}
onZigbeeStarted() {
this.zigbee.getAllClients().forEach((device) => {
const mappedDevice = zigbeeShepherdConverters.findByZigbeeModel(device.modelId);
if (mappedDevice) {
this.setupReporting(mappedDevice, device);
}
});
}
onZigbeeMessage(message, device, mappedDevice) {
// Handle messages of type endDeviceAnnce and devIncoming.
// This message is typically send when a device comes online after being powered off
// Ikea TRADFRI tend to forget their reporting after powered off.
// Re-setup reporting.
// https://github.com/Koenkk/zigbee2mqtt/issues/966
if (device && mappedDevice && ['endDeviceAnnce', 'devIncoming'].includes(message.type)) {
this.setupReporting(mappedDevice, device);
}
}
}
module.exports = DeviceReport;