From 342d4c17b91ae861f867df5bff8cf58bffde3d7f Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Thu, 27 Feb 2020 21:06:27 +0100 Subject: [PATCH] Fix debounce, debounce_ignore, retain and qos in device_options not honored. #3004 --- lib/controller.js | 5 +++-- lib/extension/deviceReceive.js | 12 +++++------- lib/util/utils.js | 11 +++++++++++ test/deviceReceive.test.js | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index d4f56964f..f0fe0b772 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -264,9 +264,10 @@ class Controller { messagePayload = newState; } + const deviceOptions = settings.get().device_options; const options = { - retain: entity.settings.hasOwnProperty('retain') ? entity.settings.retain : false, - qos: entity.settings.hasOwnProperty('qos') ? entity.settings.qos : 0, + retain: utils.getObjectsProperty([entity.settings, deviceOptions], 'retain', false), + qos: utils.getObjectsProperty([entity.settings, deviceOptions], 'qos', 0), }; if (entity.type === 'device' && settings.get().mqtt.include_device_information) { diff --git a/lib/extension/deviceReceive.js b/lib/extension/deviceReceive.js index 371721e7a..518601314 100755 --- a/lib/extension/deviceReceive.js +++ b/lib/extension/deviceReceive.js @@ -116,6 +116,9 @@ class DeviceReceive extends BaseExtension { return; } + const debounce = settingsDevice.debounce || settings.get().device_options.debounce; + const debounceIgnore = settingsDevice.debounce_ignore || settings.get().device_options.debounce_ignore; + // Convert this Zigbee message to a MQTT message. // Get payload for the message. // - If a payload is returned publish it to the MQTT broker @@ -137,13 +140,8 @@ class DeviceReceive extends BaseExtension { } // Check if we have to debounce - if (settingsDevice && settingsDevice.hasOwnProperty('debounce')) { - this.publishDebounce( - data.device.ieeeAddr, - payload, - settingsDevice.debounce, - settingsDevice.debounce_ignore, - ); + if (debounce) { + this.publishDebounce(data.device.ieeeAddr, payload, debounce, debounceIgnore); } else { this.publishEntityState(data.device.ieeeAddr, payload); diff --git a/lib/util/utils.js b/lib/util/utils.js index 619f28669..592b4f0be 100644 --- a/lib/util/utils.js +++ b/lib/util/utils.js @@ -108,11 +108,22 @@ function equalsPartial(object, expected) { return true; } +function getObjectsProperty(objects, key, defaultValue) { + for (const object of objects) { + if (object.hasOwnProperty(key)) { + return object[key]; + } + } + + return defaultValue; +} + module.exports = { millisecondsToSeconds: (milliseconds) => milliseconds / 1000, secondsToMilliseconds: (seconds) => seconds * 1000, getZigbee2mqttVersion, objectHasProperties, + getObjectsProperty, getPostfixes: () => postfixes, isXiaomiDevice: (device) => { return device.modelID !== 'lumi.router' && xiaomiManufacturerID.includes(device.manufacturerID) && diff --git a/test/deviceReceive.test.js b/test/deviceReceive.test.js index 77841489b..00e9ee5a0 100755 --- a/test/deviceReceive.test.js +++ b/test/deviceReceive.test.js @@ -110,6 +110,32 @@ describe('Device receive', () => { expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 1, "retain": false}); }); + it('Should debounce and retain messages when set via device_options', async () => { + jest.useFakeTimers(); + const device = zigbeeHerdsman.devices.WSDCGQ11LM; + settings.set(['device_options', 'debounce'], 0.1); + settings.set(['device_options', 'retain'], true); + delete settings.get().devices['0x0017880104e45522']['retain']; + const data1 = {measuredValue: 8} + const payload1 = {data: data1, cluster: 'msTemperatureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload1); + const data2 = {measuredValue: 1} + const payload2 = {data: data2, cluster: 'msRelativeHumidity', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload2); + const data3 = {measuredValue: 2} + const payload3 = {data: data3, cluster: 'msPressureMeasurement', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload3); + await flushPromises(); + jest.advanceTimersByTime(50); + expect(MQTT.publish).toHaveBeenCalledTimes(0); + jest.runAllTimers(); + await flushPromises(); + expect(MQTT.publish).toHaveBeenCalledTimes(1); + expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/weather_sensor'); + expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({temperature: 0.08, humidity: 0.01, pressure: 2, linkquality: 10}); + expect(MQTT.publish.mock.calls[0][2]).toStrictEqual({"qos": 1, "retain": true}); + }); + it('Should debounce messages only with the same payload values for provided debounce_ignore keys', async () => { jest.useFakeTimers(); const device = zigbeeHerdsman.devices.WSDCGQ11LM;