From 884e3aa4756ea02b8ab3408ac94d97d054e3bf55 Mon Sep 17 00:00:00 2001 From: Koenkk Date: Sat, 9 Jun 2018 12:27:04 +0200 Subject: [PATCH] Refactor remove device & remove from home assistant --- lib/controller.js | 47 +++++++++++++++++++++++++++----------------- lib/homeassistant.js | 16 +++++++++++++++ lib/util/settings.js | 11 +++++++++++ lib/zigbee.js | 25 ++++++++++------------- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index d04012e4..5600d6c8 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -162,7 +162,7 @@ class Controller { getDeviceStartupLogMessage(device) { let friendlyName = 'unknown'; let type = 'unknown'; - let friendlyDevice = { model: 'unkown', description: 'unknown' }; + let friendlyDevice = {model: 'unkown', description: 'unknown'}; const mappedModel = zigbeeShepherdConverters.findByZigbeeModel(device.modelId); if (mappedModel) { friendlyDevice = mappedModel; @@ -310,20 +310,33 @@ class Controller { this.mqtt.log('devices', devices); } else if (option === 'remove') { - if (message.toString() !== null && message.toString() !== '' && message.toString().length > 0) { - const deviceID = Object.keys(settings.get().devices).find((id) => - settings.getDevice(id).friendly_name === message.toString() - ); - if (!deviceID) { - logger.error(`Cannot handle '${topic}' because deviceID of '${message.toString()}' cannot be found`); - return; - } - settings.removeDevice(deviceID); - this.zigbee.removedevice(deviceID); - } else { - logger.error(`Cannot handle MQTT config option '${option}' with Payload is null - we need the friendly_name to proceed`); + message = message.toString(); + const deviceID = settings.getIDByFriendlyName(message); + const device = this.zigbee.getDevice(deviceID); + + if (!deviceID) { + logger.error(`Cannot handle '${topic}' because device with friendly_name '${message}' cannot be found`); return; } + + // Remove from zigbee network and settings. + this.zigbee.removeDevice(deviceID, (error) => { + if (!error) { + // Clear Home Assistant MQTT discovery message + const mappedModel = zigbeeShepherdConverters.findByZigbeeModel(device.modelId); + if (settings.get().homeassistant && mappedModel) { + homeassistant.clear(deviceID, mappedModel.model, this.mqtt); + } + + // Remove from configuration.yaml + settings.removeDevice(deviceID); + + logger.info(`Successfully removed ${deviceID}`); + this.mqtt.log('removed_device', message); + } else { + logger.error(`Failed to remove ${deviceID}`); + } + }); } else { logger.warn(`Cannot handle MQTT config option '${option}' with message '${message}'`); } @@ -334,9 +347,7 @@ class Controller { const topicPrefix = withPrefix ? topic.split('/')[2] : ''; // Map friendlyName to deviceID. - const deviceID = Object.keys(settings.get().devices).find((id) => - settings.getDevice(id).friendly_name === friendlyName - ); + const deviceID = settings.getIDByFriendlyName(friendlyName); if (!deviceID) { logger.error(`Cannot handle '${topic}' because deviceID of '${friendlyName}' cannot be found`); @@ -349,7 +360,7 @@ class Controller { json = JSON.parse(message); } catch (e) { // Cannot be parsed to JSON, assume state message. - json = { state: message.toString() }; + json = {state: message.toString()}; } // Find ep for this device @@ -383,7 +394,7 @@ class Controller { this.zigbee.publish(deviceID, message.cid, message.cmd, message.zclData, ep, callback); - published.push({ message: message, converter: converter }); + published.push({message: message, converter: converter}); }); /** diff --git a/lib/homeassistant.js b/lib/homeassistant.js index ac5166b6..576a3d51 100644 --- a/lib/homeassistant.js +++ b/lib/homeassistant.js @@ -285,7 +285,23 @@ function discover(deviceID, model, mqtt) { discovered[deviceID] = true; } +function clear(deviceID, model, mqtt) { + // Check if there are configs. + if (!mapping[model]) { + return; + } + + mapping[model].forEach((config) => { + const topic = `${config.type}/${deviceID}/${config.object_id}/config`; + const payload = ''; + mqtt.publish(topic, payload, {retain: true, qos: 0}, null, 'homeassistant'); + }); + + discovered[deviceID] = false; +} + module.exports = { mapping: mapping, discover: (deviceID, model, mqtt) => discover(deviceID, model, mqtt), + clear: (deviceID, model, mqtt) => clear(deviceID, model, mqtt), }; diff --git a/lib/util/settings.js b/lib/util/settings.js index 9ce81409..ffb8e1a2 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -34,10 +34,21 @@ function removeDevice(id) { } } +function getIDByFriendlyName(friendlyName) { + if (!settings.devices) { + return null; + } + + return Object.keys(settings.devices).find((id) => + settings.devices[id].friendly_name === friendlyName + ); +} + module.exports = { get: () => settings, write: () => write(), getDevice: (id) => settings.devices ? settings.devices[id] : false, addDevice: (id) => addDevice(id), removeDevice: (id) => removeDevice(id), + getIDByFriendlyName: (friendlyName) => getIDByFriendlyName(friendlyName), }; diff --git a/lib/zigbee.js b/lib/zigbee.js index 2595ea49..740266a2 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -108,30 +108,25 @@ class Zigbee { return this.shepherd.list().filter((device) => device.type !== 'Coordinator'); } - removedevice(deviceID) { - this.shepherd.remove(deviceID, (err) => { - if (err) { - logger.warn(`Failed to remove ${deviceID}`); - this.forceRemove(deviceID); + removeDevice(deviceID, callback) { + this.shepherd.remove(deviceID, (error) => { + if (error) { + logger.warn(`Failed to remove '${deviceID}', trying force remove...`); + this._forceRemove(deviceID, callback); } else { - logger.info(`Successfully removed ${deviceID}`); + callback(null); } }); } - forceRemove(deviceID) { + _forceRemove(deviceID, callback) { const device = this.shepherd._findDevByAddr(deviceID); - // force + if (device) { - return this.shepherd._unregisterDev(device, (err) => { - if (err) { - logger.warn(`Failed to force remove ${deviceID}`); - } else { - logger.info(`Successfully removed by force ${deviceID}`); - } - }); + return this.shepherd._unregisterDev(device, (error) => callback(error)); } else { logger.warn(`Could not find ${deviceID} for force removal`); + callback(true); } }