mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-28 23:00:55 +00:00
fix: Use Map for State (#27105)
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ type EventBusListener<K> = K extends keyof EventBusMap
|
||||
: never;
|
||||
|
||||
export default class EventBus {
|
||||
private callbacksByExtension: Map<string, {event: keyof EventBusMap; callback: EventBusListener<keyof EventBusMap>}[]> = new Map();
|
||||
private callbacksByExtension = new Map<string, {event: keyof EventBusMap; callback: EventBusListener<keyof EventBusMap>}[]>();
|
||||
private emitter = new events.EventEmitter<EventBusMap>();
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -20,15 +20,15 @@ const RETRIEVE_ON_RECONNECT: readonly {keys: string[]; condition?: (state: KeyVa
|
||||
|
||||
export default class Availability extends Extension {
|
||||
/** Mapped by IEEE address */
|
||||
private readonly timers: Map<string, NodeJS.Timeout> = new Map();
|
||||
private readonly timers = new Map<string, NodeJS.Timeout>();
|
||||
/** Mapped by IEEE address or Group ID */
|
||||
private readonly lastPublishedAvailabilities: Map<string | number, boolean> = new Map();
|
||||
private readonly lastPublishedAvailabilities = new Map<string | number, boolean>();
|
||||
/** Mapped by IEEE address */
|
||||
private readonly pingBackoffs: Map<string, number> = new Map();
|
||||
private readonly pingBackoffs = new Map<string, number>();
|
||||
/** IEEE addresses, waiting for last seen changes to take them out of "availability sleep" */
|
||||
private readonly backoffPausedDevices: Set<string> = new Set();
|
||||
private readonly backoffPausedDevices = new Set<string>();
|
||||
/** Mapped by IEEE address */
|
||||
private readonly retrieveStateDebouncers: Map<string, () => void> = new Map();
|
||||
private readonly retrieveStateDebouncers = new Map<string, () => void>();
|
||||
private pingQueue: Device[] = [];
|
||||
private pingQueueExecuting = false;
|
||||
private stopped = false;
|
||||
|
||||
@@ -567,7 +567,7 @@ export default class Bind extends Extension {
|
||||
);
|
||||
|
||||
if (polls.length) {
|
||||
const toPoll: Set<zh.Endpoint> = new Set();
|
||||
const toPoll = new Set<zh.Endpoint>();
|
||||
|
||||
// Add bound devices
|
||||
for (const endpoint of data.device.zh.endpoints) {
|
||||
|
||||
@@ -106,7 +106,7 @@ export default class Groups extends Extension {
|
||||
// Invalidate the last optimistic group state when group state is changed directly.
|
||||
delete this.lastOptimisticState[entity.ID];
|
||||
|
||||
const groupsToPublish: Set<Group> = new Set();
|
||||
const groupsToPublish = new Set<Group>();
|
||||
|
||||
for (const member of entity.zh.members) {
|
||||
const device = this.zigbee.resolveEntity(member.getDevice()) as Device;
|
||||
|
||||
@@ -1472,7 +1472,7 @@ export class HomeAssistant extends Extension {
|
||||
const discovered = this.getDiscovered(entity);
|
||||
discovered.discovered = true;
|
||||
const lastDiscoveredTopics = Object.keys(discovered.messages);
|
||||
const newDiscoveredTopics: Set<string> = new Set();
|
||||
const newDiscoveredTopics = new Set<string>();
|
||||
|
||||
for (const config of this.getConfigs(entity)) {
|
||||
const payload = {...config.discovery_payload};
|
||||
|
||||
@@ -185,9 +185,9 @@ export default class NetworkMap extends Extension {
|
||||
|
||||
async networkScan(includeRoutes: boolean): Promise<Zigbee2MQTTNetworkMap> {
|
||||
logger.info(`Starting network scan (includeRoutes '${includeRoutes}')`);
|
||||
const lqis: Map<Device, zh.LQI> = new Map();
|
||||
const routingTables: Map<Device, zh.RoutingTable> = new Map();
|
||||
const failed: Map<Device, string[]> = new Map();
|
||||
const lqis = new Map<Device, zh.LQI>();
|
||||
const routingTables = new Map<Device, zh.RoutingTable>();
|
||||
const failed = new Map<Device, string[]>();
|
||||
const requestWithRetry = async <T>(request: () => Promise<T>): Promise<T> => {
|
||||
try {
|
||||
const result = await request();
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import utils from './util/utils';
|
||||
const NS = 'z2m:mqtt';
|
||||
|
||||
export default class MQTT {
|
||||
private publishedTopics: Set<string> = new Set();
|
||||
private publishedTopics = new Set<string>();
|
||||
private connectionTimer?: NodeJS.Timeout;
|
||||
private client!: MqttClient;
|
||||
private eventBus: EventBus;
|
||||
|
||||
+33
-21
@@ -1,4 +1,4 @@
|
||||
import fs from 'node:fs';
|
||||
import {existsSync, readFileSync, writeFileSync} from 'node:fs';
|
||||
|
||||
import objectAssignDeep from 'object-assign-deep';
|
||||
|
||||
@@ -7,9 +7,8 @@ import logger from './util/logger';
|
||||
import * as settings from './util/settings';
|
||||
import utils from './util/utils';
|
||||
|
||||
const saveInterval = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
const dontCacheProperties = [
|
||||
const SAVE_INTERVAL = 1000 * 60 * 5; // 5 minutes
|
||||
const CACHE_IGNORE_PROPERTIES = [
|
||||
'action',
|
||||
'action_.*',
|
||||
'button',
|
||||
@@ -32,8 +31,8 @@ const dontCacheProperties = [
|
||||
];
|
||||
|
||||
class State {
|
||||
private state: {[s: string | number]: KeyValue} = {};
|
||||
private file = data.joinPath('state.json');
|
||||
private readonly state = new Map<string | number, KeyValue>();
|
||||
private readonly file = data.joinPath('state.json');
|
||||
private timer?: NodeJS.Timeout;
|
||||
|
||||
constructor(
|
||||
@@ -48,15 +47,15 @@ class State {
|
||||
this.load();
|
||||
|
||||
// Save the state on every interval
|
||||
this.timer = setInterval(() => this.save(), saveInterval);
|
||||
this.timer = setInterval(() => this.save(), SAVE_INTERVAL);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
// Remove any invalid states (ie when the device has left the network) when the system is stopped
|
||||
for (const key in this.state) {
|
||||
if (typeof key === 'string' && !this.zigbee.resolveEntity(key)) {
|
||||
for (const [key] of this.state) {
|
||||
if (typeof key === 'string' && key.startsWith('0x') && !this.zigbee.resolveEntity(key)) {
|
||||
// string key = ieeeAddr
|
||||
delete this.state[key];
|
||||
this.state.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +63,21 @@ class State {
|
||||
this.save();
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.state.clear();
|
||||
}
|
||||
|
||||
private load(): void {
|
||||
if (fs.existsSync(this.file)) {
|
||||
this.state.clear();
|
||||
|
||||
if (existsSync(this.file)) {
|
||||
try {
|
||||
this.state = JSON.parse(fs.readFileSync(this.file, 'utf8'));
|
||||
const stateObj = JSON.parse(readFileSync(this.file, 'utf8')) as KeyValue;
|
||||
|
||||
for (const key in stateObj) {
|
||||
this.state.set(key.startsWith('0x') ? key : Number.parseInt(key, 10), stateObj[key]);
|
||||
}
|
||||
|
||||
logger.debug(`Loaded state from file ${this.file}`);
|
||||
} catch (error) {
|
||||
logger.debug(`Failed to load state from file ${this.file} (corrupt file?) (${(error as Error).message})`);
|
||||
@@ -80,9 +90,11 @@ class State {
|
||||
private save(): void {
|
||||
if (settings.get().advanced.cache_state_persistent) {
|
||||
logger.debug(`Saving state to file ${this.file}`);
|
||||
const json = JSON.stringify(this.state, null, 4);
|
||||
|
||||
const json = JSON.stringify(Object.fromEntries(this.state), null, 4);
|
||||
|
||||
try {
|
||||
fs.writeFileSync(this.file, json, 'utf8');
|
||||
writeFileSync(this.file, json, 'utf8');
|
||||
} catch (error) {
|
||||
logger.error(`Failed to write state to '${this.file}' (${error})`);
|
||||
}
|
||||
@@ -92,28 +104,28 @@ class State {
|
||||
}
|
||||
|
||||
exists(entity: Device | Group): boolean {
|
||||
return this.state[entity.ID] !== undefined;
|
||||
return this.state.has(entity.ID);
|
||||
}
|
||||
|
||||
get(entity: Group | Device): KeyValue {
|
||||
return this.state[entity.ID] || {};
|
||||
return this.state.get(entity.ID) || {};
|
||||
}
|
||||
|
||||
set(entity: Group | Device, update: KeyValue, reason?: string): KeyValue {
|
||||
const fromState = this.state[entity.ID] || {};
|
||||
const fromState = this.state.get(entity.ID) || {};
|
||||
const toState = objectAssignDeep({}, fromState, update);
|
||||
const newCache = {...toState};
|
||||
const entityDontCacheProperties = entity.options.filtered_cache || [];
|
||||
|
||||
utils.filterProperties(dontCacheProperties.concat(entityDontCacheProperties), newCache);
|
||||
utils.filterProperties(CACHE_IGNORE_PROPERTIES.concat(entityDontCacheProperties), newCache);
|
||||
|
||||
this.state[entity.ID] = newCache;
|
||||
this.state.set(entity.ID, newCache);
|
||||
this.eventBus.emitStateChange({entity, from: fromState, to: toState, reason, update});
|
||||
return toState;
|
||||
}
|
||||
|
||||
remove(ID: string | number): void {
|
||||
delete this.state[ID];
|
||||
remove(ID: string | number): boolean {
|
||||
return this.state.delete(ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ export function migrateIfNecessary(): void {
|
||||
while (currentSettings.version !== finalVersion) {
|
||||
let migrationNotesFileName: string | undefined;
|
||||
// don't duplicate outputs
|
||||
const migrationNotes: Set<string> = new Set();
|
||||
const migrationNotes = new Set<string>();
|
||||
const transfers: SettingsTransfer[] = [];
|
||||
const changes: SettingsChange[] = [];
|
||||
const additions: SettingsAdd[] = [];
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ export default class Zigbee {
|
||||
// @ts-expect-error initialized in start
|
||||
private herdsman: Controller;
|
||||
private eventBus: EventBus;
|
||||
private groupLookup: Map<number /* group ID */, Group> = new Map();
|
||||
private deviceLookup: Map<string /* IEEE address */, Device> = new Map();
|
||||
private groupLookup = new Map<number /* group ID */, Group>();
|
||||
private deviceLookup = new Map<string /* IEEE address */, Device>();
|
||||
|
||||
constructor(eventBus: EventBus) {
|
||||
this.eventBus = eventBus;
|
||||
|
||||
+33
-41
@@ -13,6 +13,9 @@ import {devices, mockController as mockZHController, events as mockZHEvents, ret
|
||||
|
||||
import type {Mock, MockInstance} from 'vitest';
|
||||
|
||||
import type Device from '../lib/model/device';
|
||||
import type {Device as ZhDevice} from './mocks/zigbeeHerdsman';
|
||||
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
@@ -54,6 +57,11 @@ describe('Controller', () => {
|
||||
let controller: Controller;
|
||||
let mockExit: Mock;
|
||||
|
||||
const getZ2MDevice = (zhDevice: string | number | ZhDevice): Device => {
|
||||
// @ts-expect-error private
|
||||
return controller.zigbee.resolveEntity(zhDevice)! as Device;
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
@@ -64,7 +72,7 @@ describe('Controller', () => {
|
||||
data.writeDefaultConfiguration();
|
||||
settings.reRead();
|
||||
controller = new Controller(vi.fn(), mockExit);
|
||||
mocksClear.forEach((m) => m.mockClear());
|
||||
for (const mock of mocksClear) mock.mockClear();
|
||||
settings.reRead();
|
||||
data.writeDefaultState();
|
||||
});
|
||||
@@ -264,8 +272,7 @@ describe('Controller', () => {
|
||||
mockLogger.error.mockClear();
|
||||
// @ts-expect-error private
|
||||
controller.mqtt.client.reconnecting = true;
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb');
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {
|
||||
state: 'ON',
|
||||
brightness: 50,
|
||||
@@ -302,7 +309,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state).toStrictEqual({});
|
||||
expect(controller.state.state).toStrictEqual(new Map());
|
||||
});
|
||||
|
||||
it('Should remove device not on passlist on startup', async () => {
|
||||
@@ -737,8 +744,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
settings.set(['advanced', 'output'], 'attribute');
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {
|
||||
dummy: {1: 'yes', 2: 'no'},
|
||||
color: {r: 100, g: 50, b: 10},
|
||||
@@ -763,8 +769,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
settings.set(['advanced', 'output'], 'attribute_and_json');
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5);
|
||||
@@ -784,8 +789,7 @@ describe('Controller', () => {
|
||||
settings.set(['advanced', 'output'], 'attribute_and_json');
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'filtered_attributes'], ['color_temp', 'linkquality']);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(3);
|
||||
@@ -799,8 +803,7 @@ describe('Controller', () => {
|
||||
settings.set(['advanced', 'output'], 'attribute_and_json');
|
||||
settings.set(['device_options', 'filtered_attributes'], ['color_temp', 'linkquality']);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(3);
|
||||
@@ -815,16 +818,15 @@ describe('Controller', () => {
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'filtered_cache'], ['linkquality']);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
|
||||
const device = getZ2MDevice('bulb');
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
|
||||
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87});
|
||||
await flushPromises();
|
||||
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'});
|
||||
expect(controller.state.get(device)).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'});
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5);
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/state', 'ON', {qos: 0, retain: true});
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/brightness', '200', {qos: 0, retain: true});
|
||||
@@ -842,16 +844,15 @@ describe('Controller', () => {
|
||||
settings.set(['device_options', 'filtered_cache'], ['linkquality']);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
|
||||
const device = getZ2MDevice('bulb');
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
|
||||
await controller.publishEntityState(device, {state: 'ON', brightness: 200, color_temp: 370, linkquality: 87});
|
||||
await flushPromises();
|
||||
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'});
|
||||
expect(controller.state.get(device)).toStrictEqual({brightness: 200, color_temp: 370, state: 'ON'});
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(5);
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/state', 'ON', {qos: 0, retain: true});
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/bulb/brightness', '200', {qos: 0, retain: true});
|
||||
@@ -867,8 +868,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
settings.set(['mqtt', 'include_device_information'], true);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
let device = controller.zigbee.resolveEntity('bulb')!;
|
||||
let device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
@@ -892,8 +892,7 @@ describe('Controller', () => {
|
||||
);
|
||||
|
||||
// Unsupported device should have model "unknown"
|
||||
// @ts-expect-error private
|
||||
device = controller.zigbee.resolveEntity('unsupported2')!;
|
||||
device = getZ2MDevice('unsupported2');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
@@ -918,8 +917,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], false);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
@@ -933,8 +931,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], true);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
@@ -950,8 +947,7 @@ describe('Controller', () => {
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'retain'], true);
|
||||
settings.set(['devices', devices.bulb.ieeeAddr, 'retention'], 37);
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
@@ -965,8 +961,7 @@ describe('Controller', () => {
|
||||
data.writeEmptyState();
|
||||
await controller.start();
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {});
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledTimes(0);
|
||||
@@ -977,8 +972,7 @@ describe('Controller', () => {
|
||||
data.removeState();
|
||||
await controller.start();
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await controller.publishEntityState(device, {brightness: 200});
|
||||
await flushPromises();
|
||||
@@ -1005,8 +999,7 @@ describe('Controller', () => {
|
||||
data.writeEmptyState();
|
||||
await controller.start();
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
const device = getZ2MDevice('bulb');
|
||||
await controller.publishEntityState(device, {state: 'ON'});
|
||||
await controller.publishEntityState(device, {brightness: 200});
|
||||
await flushPromises();
|
||||
@@ -1020,7 +1013,7 @@ describe('Controller', () => {
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state).toStrictEqual({});
|
||||
expect(controller.state.state).toStrictEqual(new Map());
|
||||
});
|
||||
|
||||
it('Start controller with force_disable_retain', async () => {
|
||||
@@ -1120,14 +1113,13 @@ describe('Controller', () => {
|
||||
|
||||
it('Should remove state of removed device when stopped', async () => {
|
||||
await controller.start();
|
||||
const device = getZ2MDevice('bulb');
|
||||
// @ts-expect-error private
|
||||
const device = controller.zigbee.resolveEntity('bulb')!;
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
expect(controller.state.get(device)).toStrictEqual({brightness: 50, color_temp: 370, linkquality: 99, state: 'ON'});
|
||||
device.zh.isDeleted = true;
|
||||
await controller.stop();
|
||||
// @ts-expect-error private
|
||||
expect(controller.state.state[device.ieeeAddr]).toStrictEqual(undefined);
|
||||
expect(controller.state.state.get(device.ieeeAddr)).toStrictEqual(undefined);
|
||||
});
|
||||
|
||||
it('EventBus should handle errors', async () => {
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('Extension: Bridge', () => {
|
||||
// @ts-expect-error private
|
||||
extension.restartRequired = false;
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {[devices.bulb.ieeeAddr]: {brightness: 50}};
|
||||
controller.state.state = new Map([[devices.bulb.ieeeAddr, {brightness: 50}]]);
|
||||
fs.rmSync(deviceIconsDir, {force: true, recursive: true});
|
||||
});
|
||||
|
||||
@@ -2809,7 +2809,7 @@ describe('Extension: Bridge', () => {
|
||||
mockMQTTEvents.message('zigbee2mqtt/bridge/request/device/remove', 'bulb');
|
||||
await flushPromises();
|
||||
// @ts-expect-error private
|
||||
expect(controller.state[device.ieeeAddr]).toBeUndefined();
|
||||
expect(controller.state.state.get(device.ieeeAddr)).toBeUndefined();
|
||||
expect(device.removeFromNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(device.removeFromDatabase).not.toHaveBeenCalled();
|
||||
expect(settings.getDevice('bulb')).toBeUndefined();
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('Extension: Groups', () => {
|
||||
groups.gledopto_group.command.mockClear();
|
||||
zhcGlobalStore.clear();
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {};
|
||||
controller.state.clear();
|
||||
});
|
||||
|
||||
it('Should publish group state change when a device in it changes state', async () => {
|
||||
@@ -461,7 +461,7 @@ describe('Extension: Groups', () => {
|
||||
await flushPromises();
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {};
|
||||
controller.state.clear();
|
||||
|
||||
await mockMQTTEvents.message('zigbee2mqtt/bulb_color/set', stringify({state: 'OFF'}));
|
||||
await flushPromises();
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('Extension: OTAUpdate', () => {
|
||||
updateSpy.mockClear();
|
||||
isUpdateAvailableSpy.mockClear();
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {};
|
||||
controller.state.clear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('Extension: Publish', () => {
|
||||
beforeEach(async () => {
|
||||
data.writeDefaultConfiguration();
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {};
|
||||
controller.state.clear();
|
||||
settings.reRead();
|
||||
loadTopicGetSetRegex();
|
||||
mocksClear.forEach((m) => m.mockClear());
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('Extension: Receive', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
// @ts-expect-error private
|
||||
controller.state.state = {};
|
||||
controller.state.clear();
|
||||
data.writeDefaultConfiguration();
|
||||
settings.reRead();
|
||||
mocksClear.forEach((m) => m.mockClear());
|
||||
|
||||
Reference in New Issue
Block a user