Implemented device debounce option. #1264

This commit is contained in:
Koen Kanters 2019-03-16 23:41:46 +01:00
parent a8cf925fcb
commit e6044da604
3 changed files with 53 additions and 2 deletions

View File

@ -1,6 +1,7 @@
const settings = require('../util/settings');
const logger = require('../util/logger');
const utils = require('../util/utils');
const debounce = require('debounce');
/**
* This extensions handles messages received from devices.
@ -13,12 +14,28 @@ class DeviceReceive {
this.publishEntityState = publishEntityState;
this.coordinator = null;
this.elapsed = {};
this.debouncers = {};
}
onZigbeeStarted() {
this.coordinator = this.zigbee.getCoordinator().device.ieeeAddr;
}
publishDebounce(ieeeAddr, payload, time) {
if (!this.debouncers[ieeeAddr]) {
this.debouncers[ieeeAddr] = {
payload: {},
publish: debounce(() => {
this.publishEntityState(ieeeAddr, this.debouncers[ieeeAddr].payload);
this.debouncers[ieeeAddr].payload = {};
}, time * 1000),
};
}
this.debouncers[ieeeAddr].payload = {...this.debouncers[ieeeAddr].payload, ...payload};
this.debouncers[ieeeAddr].publish();
}
onZigbeeMessage(message, device, mappedDevice) {
if (message.type == 'devInterview') {
if (!settings.getDevice(message.data)) {
@ -45,7 +62,8 @@ class DeviceReceive {
}
// Check if this is a new device.
if (!settings.getDevice(device.ieeeAddr)) {
const settingsDevice = settings.getDevice(device.ieeeAddr);
if (!settingsDevice) {
logger.info(`New device '${device.modelId}' with address ${device.ieeeAddr} connected!`);
settings.addDevice(device.ieeeAddr);
this.mqtt.log('device_connected', device.ieeeAddr, {modelID: device.modelId});
@ -141,7 +159,12 @@ class DeviceReceive {
this.elapsed[device.ieeeAddr] = now;
}
this.publishEntityState(device.ieeeAddr, payload);
// Check if we have to debounce
if (settingsDevice && settingsDevice.hasOwnProperty('debounce')) {
this.publishDebounce(device.ieeeAddr, payload, settingsDevice.debounce);
} else {
this.publishEntityState(device.ieeeAddr, payload);
}
};
let payload = {};

View File

@ -32,6 +32,7 @@
},
"homepage": "https://koenkk.github.io/zigbee2mqtt",
"dependencies": {
"debounce": "*",
"git-last-commit": "*",
"js-yaml": "*",
"mkdir-recursive": "*",

View File

@ -3,6 +3,8 @@ const settings = require('../lib/util/settings');
const devices = require('zigbee-shepherd-converters').devices;
const utils = require('./utils');
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Devices
const WXKG11LM = devices.find((d) => d.model === 'WXKG11LM');
const WXKG02LM = devices.find((d) => d.model === 'WXKG02LM');
@ -63,6 +65,31 @@ describe('DeviceReceive', () => {
expect(publishEntityState.mock.calls[0][1]).toStrictEqual({temperature: -0.85});
});
it('Should debounce messages', async () => {
const device = {ieeeAddr: '0x12345678'};
jest.spyOn(settings, 'getDevice').mockReturnValue({debounce: 0.1});
const message1 = utils.zigbeeMessage(
device, 'msTemperatureMeasurement', 'attReport', {measuredValue: 8}, 1
);
const message2 = utils.zigbeeMessage(
device, 'msRelativeHumidity', 'attReport', {measuredValue: 1}, 1
);
const message3 = utils.zigbeeMessage(
device, 'msPressureMeasurement', 'attReport', {measuredValue: 2}, 1
);
deviceReceive.onZigbeeMessage(message1, device, WSDCGQ11LM);
deviceReceive.onZigbeeMessage(message2, device, WSDCGQ11LM);
deviceReceive.onZigbeeMessage(message3, device, WSDCGQ11LM);
await wait(200);
expect(publishEntityState).toHaveBeenCalledTimes(1);
expect(publishEntityState.mock.calls[0][1]).toStrictEqual({temperature: 0.08, humidity: 0.01, pressure: 2});
deviceReceive.onZigbeeMessage(message1, device, WSDCGQ11LM);
await wait(200);
expect(publishEntityState).toHaveBeenCalledTimes(2);
expect(publishEntityState.mock.calls[1][1]).toStrictEqual({temperature: 0.08});
});
it('Should handle a zigbee message with 1 precision', () => {
const device = {ieeeAddr: '0x12345678'};
jest.spyOn(settings, 'getDevice').mockReturnValue({temperature_precision: 1});