diff --git a/lib/controller.ts b/lib/controller.ts index 6f6ab05cb..9099c2a1c 100644 --- a/lib/controller.ts +++ b/lib/controller.ts @@ -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; diff --git a/lib/state.ts b/lib/state.ts index 676fa39f4..48e9128cd 100644 --- a/lib/state.ts +++ b/lib/state.ts @@ -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(); } diff --git a/test/controller.test.js b/test/controller.test.js index 8a18982e3..7d793889e 100644 --- a/test/controller.test.js +++ b/test/controller.test.js @@ -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); + }); });