Keep cached device state until Zigbee2MQTT is stopped (#15770)

* Fix extension path to make debugginge easier in VScode

* Fix linting error

* Add setting "cache_state_persist_on_leave" (default false)

This setting does not remove a device from State if it leaves the network

* Merge from upstream kk/dev

* Re-define cache_state_persist_on_leave to be a timeout

Allows the config to specify how long the state should be held (and the device to re-join & maintain the state).

Remove all pending deletions if the system is stopped

* Add debug. Fix "time" test

* Disable esline warnings for long debug lines

* Simplify state maintenance for leave/join devices

* Restore default configuration.yaml

* Don't track device presence via events, but examine herdsman on system stop

* Update configuration.yaml

* Update state.ts

* Update state.ts

* Update controller.test.js

* Update eventBus.ts

* Update eventBus.ts

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
This commit is contained in:
MattandKoen Kanters authored and GitHub committed 2022-12-31 10:15:11 +01:00
1 parent af27e910d8
commit 19bd87de4a
3 files changed
+17 -5

No files matched your search

+1 -1
View File
@@ -57,7 +57,7 @@ export class Controller {
});
this.zigbee = new Zigbee(this.eventBus);
this.mqtt = new MQTT(this.eventBus);
this.state = new State(this.eventBus);
this.state = new State(this.eventBus, this.zigbee);
this.restartCallback = restartCallback;
this.exitCallback = exitCallback;
+7 -4
View File
@@ -17,10 +17,10 @@ class State {
private state: {[s: string | number]: KeyValue} = {};
private file = data.joinPath('state.json');
private timer: NodeJS.Timer = null;
private eventBus: EventBus;
constructor(eventBus: EventBus) {
constructor(private readonly eventBus: EventBus, private readonly zigbee: Zigbee) {
this.eventBus = eventBus;
this.zigbee = zigbee;
}
start(): void {
@@ -28,11 +28,14 @@ class State {
// Save the state on every interval
this.timer = setInterval(() => this.save(), saveInterval);
this.eventBus.onDeviceLeave(this, (data) => delete this.state[data.ieeeAddr]);
}
stop(): void {
this.eventBus.removeListeners(this);
// Remove any invalid states (ie when the device has left the network) when the system is stopped
Object.keys(this.state)
.filter((k) => typeof k === 'string' && !this.zigbee.resolveEntity(k)) // string key = ieeeAddr
.forEach((k) => delete this.state[k]);
clearTimeout(this.timer);
this.save();
}
+9
View File
@@ -719,4 +719,13 @@ describe('Controller', () => {
await flushPromises();
expect(logger.debug).toHaveBeenCalledWith(`Received Zigbee message from 'Coordinator', type 'attributeReport', cluster 'genBasic', data '{"modelId":null}' from endpoint 1, ignoring since it is from coordinator`);
});
it('Should remove state of removed device when stopped', async () => {
await controller.start();
const device = controller.zigbee.resolveEntity('bulb');
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({"brightness":50,"color_temp":370,"linkquality":99,"state":"ON"});
device.zh.isDeleted = true;
await controller.stop();
expect(controller.state.state[device.ieeeAddr]).toStrictEqual(undefined);
});
});