From 0328ad7cb694c4fcafe8651ee16a0c4c771e2745 Mon Sep 17 00:00:00 2001 From: tb-killa Date: Mon, 4 Jun 2018 10:55:00 +0200 Subject: [PATCH 1/8] Update zigbee.js Add "removedevice" Function into zigbee.js --- lib/zigbee.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/zigbee.js b/lib/zigbee.js index 677a98080..544c3db08 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -108,6 +108,22 @@ class Zigbee { return this.shepherd.list().filter((device) => device.type !== 'Coordinator'); } + removedevice(deviceID) { + if (deviceID) { + logger.info(`Found Device with ID ${deviceID}`); + this.shepherd.remove('deviceID', function (err) { + if (err) { + console.log(`Failed to removed ${deviceID}`); + } else { + console.log(`Successfully removed ${deviceID}`); + } + }); + } else { + logger.error('removedevice function need deviceID to proceed'); + return; + } + } + ping(deviceID) { const device = this.shepherd._findDevByAddr(deviceID); From 34feef6cf42693a5d7e1dee961e35961dd141203 Mon Sep 17 00:00:00 2001 From: tb-killa Date: Mon, 4 Jun 2018 11:00:46 +0200 Subject: [PATCH 2/8] Update controller.js ADD "remove" MQTT Topic with "message" - Check --- lib/controller.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/controller.js b/lib/controller.js index eefa97428..f60aedf7c 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -309,6 +309,20 @@ 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; + } + this.zigbee.removedevice(deviceID) + } else { + logger.error(`Cannot handle MQTT config option '${option}' with Payload is null - we need the friendly_name to proceed`); + return; + } } else { logger.warn(`Cannot handle MQTT config option '${option}' with message '${message}'`); } From 0f2f7462a552dd30a5bda73cec0e746dac37ea0f Mon Sep 17 00:00:00 2001 From: Marius Ciotlos Date: Wed, 6 Jun 2018 22:13:32 +0300 Subject: [PATCH 3/8] Added force remove --- lib/controller.js | 2 +- lib/zigbee.js | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index f60aedf7c..fc35e2aa6 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -318,7 +318,7 @@ class Controller { logger.error(`Cannot handle '${topic}' because deviceID of '${message.toString()}' cannot be found`); return; } - this.zigbee.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`); return; diff --git a/lib/zigbee.js b/lib/zigbee.js index 544c3db08..925fcf43f 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -109,19 +109,26 @@ class Zigbee { } removedevice(deviceID) { - if (deviceID) { - logger.info(`Found Device with ID ${deviceID}`); - this.shepherd.remove('deviceID', function (err) { - if (err) { - console.log(`Failed to removed ${deviceID}`); - } else { - console.log(`Successfully removed ${deviceID}`); - } - }); + this.shepherd.remove('deviceID', (err) => { + if (err) { + logger.warn(`Failed to remove ${deviceID}`); + this.forceRemove(deviceID); } else { - logger.error('removedevice function need deviceID to proceed'); - return; + logger.info(`Successfully removed ${deviceID}`); } + }); + } + + forceRemove(deviceID) { + const device = this.shepherd._findDevByAddr(deviceID); + // force + return this.shepherd._unregisterDev(device, (err) => { + if (err) { + logger.warn(`Failed to force remove ${deviceID}`); + } else { + logger.info(`Successfully removed by force ${deviceID}`); + } + }); } ping(deviceID) { From 9bc87b765a0a2bc746cf8848c1aaa26465cf2db6 Mon Sep 17 00:00:00 2001 From: Marius Ciotlos Date: Wed, 6 Jun 2018 22:19:50 +0300 Subject: [PATCH 4/8] Formatting --- lib/controller.js | 32 ++++++++++++++++---------------- lib/zigbee.js | 12 ++++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index fc35e2aa6..a2a0b0f05 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; @@ -309,20 +309,20 @@ 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; - } - this.zigbee.removedevice(deviceID); - } else { - logger.error(`Cannot handle MQTT config option '${option}' with Payload is null - we need the friendly_name to proceed`); - return; + } 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; } + this.zigbee.removedevice(deviceID); + } else { + logger.error(`Cannot handle MQTT config option '${option}' with Payload is null - we need the friendly_name to proceed`); + return; + } } else { logger.warn(`Cannot handle MQTT config option '${option}' with message '${message}'`); } @@ -348,7 +348,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 @@ -382,7 +382,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/zigbee.js b/lib/zigbee.js index 925fcf43f..232d8496f 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -111,10 +111,10 @@ class Zigbee { removedevice(deviceID) { this.shepherd.remove('deviceID', (err) => { if (err) { - logger.warn(`Failed to remove ${deviceID}`); - this.forceRemove(deviceID); + logger.warn(`Failed to remove ${deviceID}`); + this.forceRemove(deviceID); } else { - logger.info(`Successfully removed ${deviceID}`); + logger.info(`Successfully removed ${deviceID}`); } }); } @@ -124,13 +124,13 @@ class Zigbee { // force return this.shepherd._unregisterDev(device, (err) => { if (err) { - logger.warn(`Failed to force remove ${deviceID}`); + logger.warn(`Failed to force remove ${deviceID}`); } else { - logger.info(`Successfully removed by force ${deviceID}`); + logger.info(`Successfully removed by force ${deviceID}`); } }); } - + ping(deviceID) { const device = this.shepherd._findDevByAddr(deviceID); From 7c53e9bb150fa6db53ab7c71b0e8357f50ae599a Mon Sep 17 00:00:00 2001 From: Marius Ciotlos Date: Thu, 7 Jun 2018 20:41:11 +0300 Subject: [PATCH 5/8] Added settings removal and bug fixes --- lib/controller.js | 1 + lib/util/settings.js | 8 ++++++++ lib/zigbee.js | 20 ++++++++++++-------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index a2a0b0f05..d04012e47 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -318,6 +318,7 @@ class Controller { 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`); diff --git a/lib/util/settings.js b/lib/util/settings.js index d642381a5..9ce814094 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -27,9 +27,17 @@ function addDevice(id) { writeRead(); } +function removeDevice(id) { + if (settings.devices) { + delete settings.devices[id]; + writeRead(); + } +} + module.exports = { get: () => settings, write: () => write(), getDevice: (id) => settings.devices ? settings.devices[id] : false, addDevice: (id) => addDevice(id), + removeDevice: (id) => removeDevice(id), }; diff --git a/lib/zigbee.js b/lib/zigbee.js index 232d8496f..2595ea49a 100644 --- a/lib/zigbee.js +++ b/lib/zigbee.js @@ -109,7 +109,7 @@ class Zigbee { } removedevice(deviceID) { - this.shepherd.remove('deviceID', (err) => { + this.shepherd.remove(deviceID, (err) => { if (err) { logger.warn(`Failed to remove ${deviceID}`); this.forceRemove(deviceID); @@ -122,13 +122,17 @@ class Zigbee { forceRemove(deviceID) { const device = this.shepherd._findDevByAddr(deviceID); // force - return this.shepherd._unregisterDev(device, (err) => { - if (err) { - logger.warn(`Failed to force remove ${deviceID}`); - } else { - logger.info(`Successfully removed by force ${deviceID}`); - } - }); + 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}`); + } + }); + } else { + logger.warn(`Could not find ${deviceID} for force removal`); + } } ping(deviceID) { From 884e3aa4756ea02b8ab3408ac94d97d054e3bf55 Mon Sep 17 00:00:00 2001 From: Koenkk Date: Sat, 9 Jun 2018 12:27:04 +0200 Subject: [PATCH 6/8] 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 d04012e47..5600d6c82 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 ac5166b6a..576a3d512 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 9ce814094..ffb8e1a26 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 2595ea49a..740266a28 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); } } From db0d8c1cdd06e16bdb234685438772399854920d Mon Sep 17 00:00:00 2001 From: Koenkk Date: Sun, 10 Jun 2018 17:35:14 +0200 Subject: [PATCH 7/8] Best effort remove device --- lib/controller.js | 46 +++++++++++++++++++++++++------------------- lib/util/settings.js | 4 ++-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index 5600d6c82..1133b8393 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -311,32 +311,38 @@ class Controller { this.mqtt.log('devices', devices); } else if (option === 'remove') { message = message.toString(); - const deviceID = settings.getIDByFriendlyName(message); + const IDByFriendlyName = settings.getIDByFriendlyName(message); + const deviceID = IDByFriendlyName ? IDByFriendlyName : 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 cleanup = () => { + // Clear Home Assistant MQTT discovery message + if (settings.get().homeassistant && device) { const mappedModel = zigbeeShepherdConverters.findByZigbeeModel(device.modelId); - if (settings.get().homeassistant && mappedModel) { + if (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}`); } - }); + + // Remove from configuration.yaml + settings.removeDevice(deviceID); + + logger.info(`Successfully removed ${deviceID}`); + this.mqtt.log('removed_device', message); + }; + + // Remove from zigbee network. + if (device) { + this.zigbee.removeDevice(deviceID, (error) => { + if (!error) { + cleanup(); + } else { + logger.error(`Failed to remove ${deviceID}`); + } + }); + } else { + cleanup(); + } } else { logger.warn(`Cannot handle MQTT config option '${option}' with message '${message}'`); } diff --git a/lib/util/settings.js b/lib/util/settings.js index ffb8e1a26..c29e34dc4 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -28,7 +28,7 @@ function addDevice(id) { } function removeDevice(id) { - if (settings.devices) { + if (settings.devices && settings.devices[id]) { delete settings.devices[id]; writeRead(); } @@ -47,7 +47,7 @@ function getIDByFriendlyName(friendlyName) { module.exports = { get: () => settings, write: () => write(), - getDevice: (id) => settings.devices ? settings.devices[id] : false, + getDevice: (id) => settings.devices ? settings.devices[id] : null, addDevice: (id) => addDevice(id), removeDevice: (id) => removeDevice(id), getIDByFriendlyName: (friendlyName) => getIDByFriendlyName(friendlyName), From cbc1b3ab39f4b79727896aa5ea6226f8d47381fd Mon Sep 17 00:00:00 2001 From: Koenkk Date: Sun, 10 Jun 2018 17:37:16 +0200 Subject: [PATCH 8/8] removed_device -> device_removed --- lib/controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controller.js b/lib/controller.js index 1133b8393..50c439905 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -328,7 +328,7 @@ class Controller { settings.removeDevice(deviceID); logger.info(`Successfully removed ${deviceID}`); - this.mqtt.log('removed_device', message); + this.mqtt.log('device_removed', message); }; // Remove from zigbee network.