From 07dc837b766a774b55bceb5877b2ae47f6fb1f93 Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Wed, 15 Apr 2020 22:34:59 +0200 Subject: [PATCH] Refactor receive --- lib/controller.js | 8 +++---- lib/extension/homeassistant.js | 12 ++++++++++ .../{deviceReceive.js => receive.js} | 24 ++++--------------- test/homeassistant.test.js | 23 +++++++++++++++++- ...{deviceReceive.test.js => receive.test.js} | 19 +-------------- 5 files changed, 43 insertions(+), 43 deletions(-) rename lib/extension/{deviceReceive.js => receive.js} (86%) rename test/{deviceReceive.test.js => receive.test.js} (96%) diff --git a/lib/controller.js b/lib/controller.js index b12ac55d9..f407d8c83 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -9,7 +9,7 @@ const utils = require('./util/utils'); // Extensions const ExtensionEntityPublish = require('./extension/entityPublish'); -const ExtensionDeviceReceive = require('./extension/deviceReceive'); +const ExtensionReceive = require('./extension/receive'); const ExtensionNetworkMap = require('./extension/networkMap'); const ExtensionSoftReset = require('./extension/legacy/softReset'); const ExtensionHomeAssistant = require('./extension/homeassistant'); @@ -37,7 +37,7 @@ class Controller { const args = [this.zigbee, this.mqtt, this.state, this.publishEntityState, this.eventBus]; this.extensions = [ new ExtensionEntityPublish(...args), - new ExtensionDeviceReceive(...args), + new ExtensionReceive(...args), new ExtensionDeviceGroupMembership(...args), new ExtensionConfigure(...args), new ExtensionNetworkMap(...args), @@ -289,8 +289,6 @@ class Controller { resolvedEntity.settings.filtered_attributes.forEach((a) => delete messagePayload[a]); } - this.eventBus.emit('publishEntityState', {payload: messagePayload, entity: resolvedEntity}); - if (Object.entries(messagePayload).length) { if (settings.get().experimental.output === 'attribute_and_json') { await this.mqtt.publish(resolvedEntity.name, JSON.stringify(messagePayload), options); @@ -304,6 +302,8 @@ class Controller { } } } + + this.eventBus.emit('publishEntityState', {payload: messagePayload, entity: resolvedEntity}); } async iteratePayloadAttributeOutput(topicRoot, payload, options) { diff --git a/lib/extension/homeassistant.js b/lib/extension/homeassistant.js index 440d8ebc4..f1281f3ac 100644 --- a/lib/extension/homeassistant.js +++ b/lib/extension/homeassistant.js @@ -1623,6 +1623,18 @@ class HomeAssistant extends Extension { } } + /** + * Publish an empty value for click and action payload, in this way Home Assistant + * can use Home Assistant entities in automations. + * https://github.com/Koenkk/zigbee2mqtt/issues/959#issuecomment-480341347 + */ + if (settings.get().advanced.homeassistant_legacy_triggers) { + const key = ['action', 'click'].find((k) => data.payload.hasOwnProperty(k) && data.payload[k] !== ''); + if (key) { + this.publishEntityState(data.entity.device.ieeeAddr, {[key]: ''}); + } + } + /** * Implements the MQTT device trigger (https://www.home-assistant.io/integrations/device_trigger.mqtt/) * The MQTT device trigger does not support JSON parsing, so it cannot listen to zigbee2mqtt/my_device diff --git a/lib/extension/deviceReceive.js b/lib/extension/receive.js similarity index 86% rename from lib/extension/deviceReceive.js rename to lib/extension/receive.js index b7238063d..4e02b41fc 100755 --- a/lib/extension/deviceReceive.js +++ b/lib/extension/receive.js @@ -4,10 +4,9 @@ const utils = require('../util/utils'); const debounce = require('debounce'); const Extension = require('./extension'); -class DeviceReceive extends Extension { +class Receive extends Extension { constructor(zigbee, mqtt, state, publishEntityState, eventBus) { super(zigbee, mqtt, state, publishEntityState, eventBus); - this.coordinator = null; this.elapsed = {}; this.debouncers = {}; } @@ -54,7 +53,7 @@ class DeviceReceive extends Extension { return result; } - canHandleEvent(type, data, resolvedEntity) { + shouldProcess(type, data, resolvedEntity) { if (type !== 'message' || !resolvedEntity) { return false; } @@ -98,7 +97,7 @@ class DeviceReceive extends Extension { } onZigbeeEvent(type, data, resolvedEntity) { - if (!this.canHandleEvent(type, data, resolvedEntity)) { + if (!this.shouldProcess(type, data, resolvedEntity)) { return; } @@ -144,21 +143,6 @@ class DeviceReceive extends Extension { this.publishDebounce(data.device.ieeeAddr, payload, debounce, debounceIgnore); } else { this.publishEntityState(data.device.ieeeAddr, payload); - - if (settings.get().homeassistant && settings.get().advanced.homeassistant_legacy_triggers) { - /** - * Publish an empty value for click and action payload, in this way Home Assistant - * can use Home Assistant entities in automations. - * https://github.com/Koenkk/zigbee2mqtt/issues/959#issuecomment-480341347 - */ - Object.keys(payload).forEach((key) => { - if (['action', 'click'].includes(key)) { - const counterPayload = {}; - counterPayload[key] = ''; - this.publishEntityState(data.device.ieeeAddr, counterPayload); - } - }); - } } }; @@ -178,4 +162,4 @@ class DeviceReceive extends Extension { } } -module.exports = DeviceReceive; +module.exports = Receive; diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index d2d7178ac..ad992c138 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -517,7 +517,7 @@ describe('HomeAssistant extension', () => { MQTT.publish.mockClear(); await zigbeeHerdsman.events.message(payload); await flushPromises(); - // 1 publish is the publish from deviceReceive + // 1 publish is the publish from receive expect(MQTT.publish).toHaveBeenCalledTimes(1); }); @@ -939,4 +939,25 @@ describe('HomeAssistant extension', () => { await flushPromises(); expect(logger.error).toHaveBeenCalledTimes(0); }); + + it('Should counter an action/click payload with an empty payload', async () => { + controller = new Controller(false); + await controller.start(); + await flushPromises(); + MQTT.publish.mockClear(); + const device = zigbeeHerdsman.devices.WXKG11LM; + const data = {onOff: 1} + const payload = {data, cluster: 'genOnOff', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload); + await flushPromises(); + expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/button'); + expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({click: 'single', linkquality: 10}); + expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false}); + expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/button'); + expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({click: '', linkquality: 10}); + expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false}); + expect(MQTT.publish.mock.calls[2][0]).toStrictEqual('homeassistant/device_automation/0x0017880104e45520/click_single/config'); + expect(MQTT.publish.mock.calls[3][0]).toStrictEqual('zigbee2mqtt/button/click'); + }); }); diff --git a/test/deviceReceive.test.js b/test/receive.test.js similarity index 96% rename from test/deviceReceive.test.js rename to test/receive.test.js index 00e9ee5a0..7bc052233 100755 --- a/test/deviceReceive.test.js +++ b/test/receive.test.js @@ -8,7 +8,7 @@ const flushPromises = () => new Promise(setImmediate); const mocksClear = [MQTT.publish, logger.warn, logger.debug]; -describe('Device receive', () => { +describe('Receive', () => { let controller; beforeEach(async () => { @@ -33,23 +33,6 @@ describe('Device receive', () => { expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false}); }); - - it('Should handle a zigbee message and counter it when Home Assistant integration is enabled', async () => { - settings.set(['homeassistant'], true); - const device = zigbeeHerdsman.devices.WXKG11LM; - const data = {onOff: 1} - const payload = {data, cluster: 'genOnOff', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; - await zigbeeHerdsman.events.message(payload); - await flushPromises(); - expect(MQTT.publish).toHaveBeenCalledTimes(2); - expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/button'); - expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({click: 'single', linkquality: 10}); - expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 0, "retain": false}); - expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/button'); - expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({click: '', linkquality: 10}); - expect(MQTT.publish.mock.calls[1][2]).toStrictEqual({"qos": 0, "retain": false}); - }); - it('Should handle a zigbee message which uses ep (left)', async () => { const device = zigbeeHerdsman.devices.WXKG02LM; const data = {onOff: 1}