diff --git a/lib/controller.js b/lib/controller.js index 9b0ce7175..dda7d2ef6 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -3,6 +3,7 @@ const Zigbee = require('./zigbee'); const State = require('./state'); const logger = require('./util/logger'); const settings = require('./util/settings'); +const ExtensionNetworkMap = require('./extension/networkMap'); const zigbeeShepherdConverters = require('zigbee-shepherd-converters'); const homeassistant = require('./homeassistant'); const objectAssignDeep = require(`object-assign-deep`); @@ -94,6 +95,11 @@ class Controller { }); } + // Initialize extensions. + this.extensions = [ + new ExtensionNetworkMap(this.zigbee, this.mqtt, this.state), + ]; + // Resend all cached states. this.sendAllCachedStates(); } @@ -337,6 +343,12 @@ class Controller { handleMQTTMessage(topic, message) { logger.debug(`Recieved mqtt message on topic '${topic}' with data '${message}'`); + // Find extensions that could handle this. + const extensions = this.extensions.filter((e) => e.handleMQTTMessage); + + // Call extensions. + const extensionResults = extensions.map((e) => e.handleMQTTMessage(topic, message)); + if (topic.match(mqttConfigRegex)) { this.handleMQTTMessageConfig(topic, message); } else if (topic.match(mqttDeviceRegex) || topic.match(mqttDevicePrefixRegex)) { @@ -348,7 +360,7 @@ class Controller { clearTimeout(timer); }, 20000); } - } else { + } else if (!extensionResults.includes(true)) { logger.warn(`Cannot handle MQTT message with topic '${topic}' and message '${message}'`); } } diff --git a/lib/extension/networkMap.js b/lib/extension/networkMap.js new file mode 100644 index 000000000..cc1be59f3 --- /dev/null +++ b/lib/extension/networkMap.js @@ -0,0 +1,38 @@ + +const settings = require('../util/settings'); + +class NetworkMap { + constructor(zigbee, mqtt, state) { + this.zigbee = zigbee; + this.mqtt = mqtt; + this.state = state; + + // Subscribe to topic. + this.topic = `${settings.get().mqtt.base_topic}/bridge/networkmap`; + this.mqtt.subscribe(this.topic); + + // Set supported formats + this.supportedFormats = { + 'raw': this.raw, + }; + } + + handleMQTTMessage(topic, message) { + message = message.toString(); + + if (topic === this.topic && this.supportedFormats.hasOwnProperty(message)) { + this.zigbee.networkScan((result)=> { + const converted = this.supportedFormats[message](result); + this.mqtt.publish(`bridge/networkmap/${message}`, converted, {}); + }); + + return true; + } + } + + raw(topology) { + return JSON.stringify(topology); + } +} + +module.exports = NetworkMap; diff --git a/lib/mqtt.js b/lib/mqtt.js index fcbc21282..47133551e 100644 --- a/lib/mqtt.js +++ b/lib/mqtt.js @@ -70,7 +70,11 @@ class MQTT { handleConnect() { logger.info('Connected to MQTT server'); this.publish('bridge/state', 'online', {retain: true, qos: 0}); - this.subscriptions.forEach((topic) => this.client.subscribe(topic)); + this.subscriptions.forEach((topic) => this.subscribe(topic)); + } + + subscribe(topic) { + this.client.subscribe(topic); } handleMessage(topic, message) { diff --git a/lib/zigbee.js b/lib/zigbee.js index f43366eec..6a813ebba 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -212,6 +212,14 @@ class Zigbee { device.read(cid, attr, callback); } + networkScan(callback) { + logger.info('Starting network scan...'); + this.shepherd.lqiScan().then((result) => { + logger.info('Network scan completed'); + callback(result); + }); + } + registerOnAfIncomingMsg(ieeeAddr, ep) { const device = this._findDevice(ieeeAddr, ep); device.onAfIncomingMsg = (message) => {