diff --git a/lib/extension/deviceBind.js b/lib/extension/deviceBind.js index d94e6d786..75c1cc6a8 100644 --- a/lib/extension/deviceBind.js +++ b/lib/extension/deviceBind.js @@ -1,7 +1,6 @@ const settings = require('../util/settings'); const logger = require('../util/logger'); const utils = require('../util/utils'); -const zigbeeShepherdConverters = require('zigbee-shepherd-converters'); const postfixes = utils.getPostfixes(); const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/(bind|unbind)/.+$`); @@ -56,20 +55,6 @@ class DeviceBind { return {type, ...this.getIDAndPostfix(topic)}; } - getEp(ID, postfix) { - let source = null; - if (postfix) { - const device = this.zigbee.getDevice(ID); - const mappedDevice = zigbeeShepherdConverters.findByZigbeeModel(device.modelId); - const epID = mappedDevice.ep(device)[postfix]; - source = this.zigbee.getEndpoint(ID, epID); - } else { - source = this.zigbee.getEndpoint(ID); - } - - return source; - } - onMQTTMessage(topic, message) { topic = this.parseTopic(topic); @@ -79,28 +64,21 @@ class DeviceBind { // Find source; can only be a device. const sourceEntity = settings.resolveEntity(topic.ID); - const source = this.getEp(sourceEntity.ID, topic.postfix); - if (!source) { - logger.error(`Failed to find device '${sourceEntity.ID}'`); - return false; - } + const source = utils.getEndpointByEntityID(this.zigbee, topic.ID, topic.postfix); - // Find target; can be a device or group. const targetEntityIDPostfix= this.getIDAndPostfix(message.toString()); const targetEntity = settings.resolveEntity(targetEntityIDPostfix.ID); let target = null; - if (targetEntity.type === 'device') { - target = this.getEp(targetEntity.ID, targetEntityIDPostfix.postfix); - - if (!target) { - logger.error(`Failed to find target device '${targetEntity.ID}'`); - return false; - } + target = utils.getEndpointByEntityID(this.zigbee, targetEntity.ID, targetEntityIDPostfix.postfix); } else if (targetEntity.type === 'group') { target = targetEntity.ID; } + if (!source || !target) { + return false; + } + // Find which clusters are supported by both the source and target. // Groups are assumed to support all clusters (as we don't know which devices are in) let supported = []; diff --git a/lib/util/utils.js b/lib/util/utils.js index b971986e4..e61df1bc9 100644 --- a/lib/util/utils.js +++ b/lib/util/utils.js @@ -1,3 +1,6 @@ +const zigbeeShepherdConverters = require('zigbee-shepherd-converters'); +const logger = require('../util/logger'); + // Xiaomi uses 4151 and 4447 (lumi.plug) as manufacturer ID. const xiaomiManufacturerID = [4151, 4447]; const ikeaTradfriManufacturerID = [4476]; @@ -29,6 +32,41 @@ const postfixes = [ 'top_left', 'top_right', 'white', 'rgb', 'system', 'top', 'bottom', ]; +function getEndpointByEntityID(zigbee, entityID, epName) { + const device = zigbee.getDevice(entityID); + if (!device) { + logger.error(`Failed to find device with entity ID '${entityID}'`); + return; + } + + const mappedDevice = zigbeeShepherdConverters.findByZigbeeModel(device.modelId); + if (!mappedDevice) { + logger.error(`Device with model ID ${device.modelId} is not supported`); + return; + } + + let epID = null; + if (epName) { + if (!mappedDevice.ep) { + logger.error(`Device ${mappedDevice.model} doesn't define eps`); + return; + } + + epID = mappedDevice.ep(device)[epName]; + if (!epID) { + logger.error(`Device ${mappedDevice.model} doesn't have ep named '${epName}'`); + return; + } + } + + const endpoint = zigbee.getEndpoint(entityID, epID); + if (!endpoint) { + logger.error(`Failed to retrieve for entity ID ${entityID} and endpoint ID ${epID}`); + } + + return endpoint; +} + module.exports = { millisecondsToSeconds: (milliseconds) => milliseconds / 1000, secondsToMilliseconds: (seconds) => seconds * 1000, @@ -37,4 +75,5 @@ module.exports = { isNumeric: (string) => /^\d+$/.test(string), toLocalISOString: (dDate) => toLocalISOString(dDate), getPostfixes: () => postfixes, + getEndpointByEntityID, }; diff --git a/test/deviceBind.test.js b/test/deviceBind.test.js index 314cf9163..1b6a68078 100644 --- a/test/deviceBind.test.js +++ b/test/deviceBind.test.js @@ -52,8 +52,12 @@ const zigbee = { getDevice: (ID) => { if (ID === 'switch_ep2') { return {modelId: 'lumi.sensor_86sw2.es1'}; - } else if (ID == 'switch_ep3') { + } else if (ID === 'switch_ep3') { return {modelId: 'DNCKAT_S003'}; + } else if (ID === 'bulb') { + return {modelId: 'TRADFRI bulb E27 WS opal 980lm'}; + } else if (ID === 'remote') { + return {modelId: 'TRADFRI remote control'}; } throw new Error(`No mock for ${ID}`);