Skip to content

Commit

Permalink
Fix old state being published due to debounce. #3572
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenkk committed May 29, 2020
1 parent 89a6c97 commit 5f63dcb
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
2 changes: 1 addition & 1 deletion lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ class Controller {
}
}

this.eventBus.emit('publishEntityState', {payload: messagePayload, entity: resolvedEntity});
this.eventBus.emit('publishEntityState', {payload: messagePayload, entity: resolvedEntity, stateChangeReason});
}

async iteratePayloadAttributeOutput(topicRoot, payload, options) {
Expand Down
17 changes: 16 additions & 1 deletion lib/extension/receive.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,33 @@ class Receive extends Extension {
super(zigbee, mqtt, state, publishEntityState, eventBus);
this.elapsed = {};
this.debouncers = {};
this.eventBus.on('publishEntityState', (data) => this.onPublishEntityState(data));
}

async onZigbeeStarted() {
this.coordinator = this.zigbee.getDevicesByType('Coordinator')[0];
}

async onPublishEntityState(data) {
/**
* Prevent that outdated properties are being published.
* In case that e.g. the state is currently held back by a debounce and a new state is published
* remove it from the to be send debounced message.
*/
if (data.entity.type === 'device' && this.debouncers[data.entity.device.ieeeAddr] &&
data.stateChangeReason !== 'publishDebounce') {
for (const key of Object.keys(data.payload)) {
delete this.debouncers[data.entity.device.ieeeAddr].payload[key];
}
}
}

publishDebounce(ieeeAddr, payload, time, debounceIgnore) {
if (!this.debouncers[ieeeAddr]) {
this.debouncers[ieeeAddr] = {
payload: {},
publish: debounce(() => {
this.publishEntityState(ieeeAddr, this.debouncers[ieeeAddr].payload);
this.publishEntityState(ieeeAddr, this.debouncers[ieeeAddr].payload, 'publishDebounce');
this.debouncers[ieeeAddr].payload = {};
}, time * 1000),
};
Expand Down
14 changes: 14 additions & 0 deletions test/receive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ describe('Receive', () => {
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({temperature: 0.07, pressure: 2, humidity: 0.03, linkquality: 13});
});

it('Shouldnt republish old state', async () => {
// https://github.com/Koenkk/zigbee2mqtt/issues/3572
jest.useFakeTimers();
const device = zigbeeHerdsman.devices.bulb;
settings.set(['devices', device.ieeeAddr, 'debounce'], 0.1);
await zigbeeHerdsman.events.message({data: {onOff: 0}, cluster: 'genOnOff', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10});
await MQTT.events.message('zigbee2mqtt/bulb/set', JSON.stringify({state: 'ON'}));
await flushPromises();
jest.runAllTimers();
expect(MQTT.publish).toHaveBeenCalledTimes(2);
expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({state: 'ON'});
expect(JSON.parse(MQTT.publish.mock.calls[1][1])).toStrictEqual({state: 'ON', linkquality: 10});
});

it('Should handle a zigbee message with 1 precision', async () => {
const device = zigbeeHerdsman.devices.WSDCGQ11LM;
settings.set(['devices', device.ieeeAddr, 'temperature_precision'], 1);
Expand Down

0 comments on commit 5f63dcb

Please sign in to comment.