mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-07-29 06:49:47 +00:00
feat: Add clear_cache option to device remove request (#32631)
Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.5.3/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
|
||||
+21
-13
@@ -664,20 +664,25 @@ export default class Bridge extends Extension {
|
||||
entityType: T,
|
||||
message: string | KeyValue,
|
||||
): Promise<Zigbee2MQTTResponse<T extends "device" ? "bridge/response/device/remove" : "bridge/response/group/remove">> {
|
||||
const ID = typeof message === "object" ? message.id : message.trim();
|
||||
const messageIsObject = typeof message === "object";
|
||||
const ID = messageIsObject ? message.id : message.trim();
|
||||
const entity = this.getEntity(entityType, ID);
|
||||
// note: entity.name is dynamically retrieved, will change once device is removed (friendly => ieee)
|
||||
const friendlyName = entity.name;
|
||||
let block = false;
|
||||
let force = false;
|
||||
let clearCache = false;
|
||||
let blockForceLog = "";
|
||||
|
||||
if (entityType === "device" && typeof message === "object") {
|
||||
block = !!message.block;
|
||||
force = !!message.force;
|
||||
blockForceLog = ` (block: ${block}, force: ${force})`;
|
||||
} else if (entityType === "group" && typeof message === "object") {
|
||||
force = !!message.force;
|
||||
if (entityType === "device" && messageIsObject) {
|
||||
const payload = message as Zigbee2MQTTAPI["bridge/request/device/remove"];
|
||||
block = !!payload.block;
|
||||
force = !!payload.force;
|
||||
clearCache = !!payload.clear_cache;
|
||||
blockForceLog = ` (block: ${block}, force: ${force}, clear cache: ${clearCache})`;
|
||||
} else if (entityType === "group" && messageIsObject) {
|
||||
const payload = message as Zigbee2MQTTAPI["bridge/request/group/remove"];
|
||||
force = !!payload.force;
|
||||
blockForceLog = ` (force: ${force})`;
|
||||
}
|
||||
|
||||
@@ -690,9 +695,13 @@ export default class Bridge extends Extension {
|
||||
}
|
||||
|
||||
if (force) {
|
||||
entity.zh.removeFromDatabase();
|
||||
entity.zh.removeFromDatabase(clearCache);
|
||||
} else {
|
||||
await entity.zh.removeFromNetwork();
|
||||
await entity.zh.removeFromNetwork(clearCache);
|
||||
}
|
||||
|
||||
if (clearCache) {
|
||||
this.zigbee.removeDeviceFromLookup(entity.ID);
|
||||
}
|
||||
|
||||
settings.removeDevice(entity.ID as string);
|
||||
@@ -717,19 +726,18 @@ export default class Bridge extends Extension {
|
||||
|
||||
logger.info(`Successfully removed ${entityType} '${friendlyName}'${blockForceLog}`);
|
||||
|
||||
await this.publishGroups();
|
||||
|
||||
if (entity instanceof Device) {
|
||||
await this.publishGroups();
|
||||
await this.publishDevices();
|
||||
// Refresh Cluster definition
|
||||
await this.publishDefinitions();
|
||||
|
||||
const responseData: Zigbee2MQTTAPI["bridge/response/device/remove"] = {id: ID, block, force};
|
||||
const responseData: Zigbee2MQTTAPI["bridge/response/device/remove"] = {id: ID, block, force, clear_cache: clearCache};
|
||||
|
||||
return utils.getResponse(message, responseData);
|
||||
}
|
||||
|
||||
await this.publishGroups();
|
||||
|
||||
const responseData: Zigbee2MQTTAPI["bridge/response/group/remove"] = {id: ID, force};
|
||||
|
||||
return utils.getResponse(
|
||||
|
||||
@@ -622,12 +622,14 @@ export interface Zigbee2MQTTAPI {
|
||||
id: string;
|
||||
block?: boolean;
|
||||
force?: boolean;
|
||||
clear_cache?: boolean;
|
||||
};
|
||||
|
||||
"bridge/response/device/remove": {
|
||||
id: string;
|
||||
block: boolean;
|
||||
force: boolean;
|
||||
clear_cache: boolean;
|
||||
};
|
||||
|
||||
"bridge/request/device/ota_update/check": {
|
||||
|
||||
+6
-2
@@ -467,7 +467,11 @@ export default class Zigbee {
|
||||
return this.resolveGroup(id);
|
||||
}
|
||||
|
||||
removeGroupFromLookup(id: number): void {
|
||||
this.groupLookup.delete(id);
|
||||
removeDeviceFromLookup(ieee: string): boolean {
|
||||
return this.deviceLookup.delete(ieee);
|
||||
}
|
||||
|
||||
removeGroupFromLookup(id: number): boolean {
|
||||
return this.groupLookup.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@
|
||||
"winston-syslog": "^2.7.1",
|
||||
"winston-transport": "^4.9.0",
|
||||
"ws": "^8.21.1",
|
||||
"zigbee-herdsman": "10.6.3",
|
||||
"zigbee-herdsman": "10.7.0",
|
||||
"zigbee-herdsman-converters": "26.85.0",
|
||||
"zigbee2mqtt-frontend": "0.9.21",
|
||||
"zigbee2mqtt-windfront": "2.13.0"
|
||||
|
||||
Generated
+7
-7
@@ -5,7 +5,7 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
zigbee-herdsman: 10.6.3
|
||||
zigbee-herdsman: 10.7.0
|
||||
|
||||
importers:
|
||||
|
||||
@@ -63,8 +63,8 @@ importers:
|
||||
specifier: ^8.21.1
|
||||
version: 8.21.1
|
||||
zigbee-herdsman:
|
||||
specifier: 10.6.3
|
||||
version: 10.6.3
|
||||
specifier: 10.7.0
|
||||
version: 10.7.0
|
||||
zigbee-herdsman-converters:
|
||||
specifier: 26.85.0
|
||||
version: 26.85.0
|
||||
@@ -1521,8 +1521,8 @@ packages:
|
||||
resolution: {integrity: sha512-pqPq5ftbRSS/sxS6sM0Ax3zl/Z/NbDYspQriUSaQemIs4PEfa6Pqwz4F0tCi/kCg2XQNjV5fdfuqrZiiTJuCRQ==}
|
||||
engines: {node: '>=20.15.0'}
|
||||
|
||||
zigbee-herdsman@10.6.3:
|
||||
resolution: {integrity: sha512-LSscRq7Q71J8naavNimH6twhcOMNn4lI+mar5AURvH4nnlDBtrrNy36t05TiMs6ZA4PkiYnpGeaSEU6ZMlus/w==}
|
||||
zigbee-herdsman@10.7.0:
|
||||
resolution: {integrity: sha512-eKp9Y2/+RJ+SxVttud1gkSvm5u5Vl5Uk6uWjmcZRVEdaMpcoJduNHQHSapXFtTqmYVgpsnydIhva7k5xAePZFg==}
|
||||
|
||||
zigbee-on-host@0.2.4:
|
||||
resolution: {integrity: sha512-NIG6CWp+Yfn7PjqEIRvenHqpwT1U7rSkyimnFOUIFpnmxQOJKrmcwWDfn6WjbU/YIYYWSQPlj+g13icu1xwlyg==}
|
||||
@@ -2836,11 +2836,11 @@ snapshots:
|
||||
dependencies:
|
||||
iconv-lite: 0.7.3
|
||||
semver: 7.8.5
|
||||
zigbee-herdsman: 10.6.3
|
||||
zigbee-herdsman: 10.7.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
zigbee-herdsman@10.6.3:
|
||||
zigbee-herdsman@10.7.0:
|
||||
dependencies:
|
||||
'@date-fns/tz': 1.5.0
|
||||
'@serialport/bindings-cpp': 13.0.1
|
||||
|
||||
@@ -2973,6 +2973,7 @@ describe("Extension: Bridge", () => {
|
||||
|
||||
it("Should allow to remove device by string", async () => {
|
||||
const device = devices.bulb;
|
||||
const removeSpy = vi.spyOn(controller.zigbee, "removeDeviceFromLookup");
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
mockMQTTEvents.message("zigbee2mqtt/bridge/request/device/remove", "bulb");
|
||||
await flushPromises();
|
||||
@@ -2981,11 +2982,12 @@ describe("Extension: Bridge", () => {
|
||||
expect(device.removeFromNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(device.removeFromDatabase).not.toHaveBeenCalled();
|
||||
expect(settings.getDevice("bulb")).toBeUndefined();
|
||||
expect(removeSpy).not.toHaveBeenCalled();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bulb", "", {retain: true});
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bridge/devices", expect.any(String), expect.any(Object));
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {id: "bulb", block: false, force: false}, status: "ok"}),
|
||||
stringify({data: {id: "bulb", block: false, force: false, clear_cache: false}, status: "ok"}),
|
||||
{},
|
||||
);
|
||||
expect(settings.get().blocklist).toStrictEqual([]);
|
||||
@@ -2995,52 +2997,76 @@ describe("Extension: Bridge", () => {
|
||||
|
||||
it("Should allow to remove device by object ID", async () => {
|
||||
const device = devices.bulb;
|
||||
const removeSpy = vi.spyOn(controller.zigbee, "removeDeviceFromLookup");
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
mockMQTTEvents.message("zigbee2mqtt/bridge/request/device/remove", stringify({id: "bulb"}));
|
||||
await flushPromises();
|
||||
expect(device.removeFromNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(device.removeFromDatabase).not.toHaveBeenCalled();
|
||||
expect(settings.getDevice("bulb")).toBeUndefined();
|
||||
expect(removeSpy).not.toHaveBeenCalled();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bridge/devices", expect.any(String), expect.any(Object));
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {id: "bulb", block: false, force: false}, status: "ok"}),
|
||||
stringify({data: {id: "bulb", block: false, force: false, clear_cache: false}, status: "ok"}),
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it("Should allow to force remove device", async () => {
|
||||
const device = devices.bulb;
|
||||
const removeSpy = vi.spyOn(controller.zigbee, "removeDeviceFromLookup");
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
mockMQTTEvents.message("zigbee2mqtt/bridge/request/device/remove", stringify({id: "bulb", force: true}));
|
||||
await flushPromises();
|
||||
expect(device.removeFromDatabase).toHaveBeenCalledTimes(1);
|
||||
expect(device.removeFromNetwork).not.toHaveBeenCalled();
|
||||
expect(settings.getDevice("bulb")).toBeUndefined();
|
||||
expect(removeSpy).not.toHaveBeenCalled();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bridge/devices", expect.any(String), expect.any(Object));
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {id: "bulb", block: false, force: true}, status: "ok"}),
|
||||
stringify({data: {id: "bulb", block: false, force: true, clear_cache: false}, status: "ok"}),
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it("Should allow to block device", async () => {
|
||||
const device = devices.bulb;
|
||||
const removeSpy = vi.spyOn(controller.zigbee, "removeDeviceFromLookup");
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
mockMQTTEvents.message("zigbee2mqtt/bridge/request/device/remove", stringify({id: "bulb", block: true, force: true}));
|
||||
await flushPromises();
|
||||
expect(device.removeFromDatabase).toHaveBeenCalledTimes(1);
|
||||
expect(settings.getDevice("bulb")).toBeUndefined();
|
||||
expect(removeSpy).not.toHaveBeenCalled();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bridge/devices", expect.any(String), expect.any(Object));
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {id: "bulb", block: true, force: true}, status: "ok"}),
|
||||
stringify({data: {id: "bulb", block: true, force: true, clear_cache: false}, status: "ok"}),
|
||||
{},
|
||||
);
|
||||
expect(settings.get().blocklist).toStrictEqual(["0x000b57fffec6a5b2"]);
|
||||
});
|
||||
|
||||
it("Should allow to clear cache when removing device", async () => {
|
||||
const device = devices.bulb;
|
||||
const removeSpy = vi.spyOn(controller.zigbee, "removeDeviceFromLookup");
|
||||
mockMQTTPublishAsync.mockClear();
|
||||
mockMQTTEvents.message("zigbee2mqtt/bridge/request/device/remove", stringify({id: "bulb", clear_cache: true}));
|
||||
await flushPromises();
|
||||
expect(device.removeFromNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(device.removeFromDatabase).not.toHaveBeenCalled();
|
||||
expect(settings.getDevice("bulb")).toBeUndefined();
|
||||
expect(removeSpy).toHaveNthReturnedWith(1, true);
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith("zigbee2mqtt/bridge/devices", expect.any(String), expect.any(Object));
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {id: "bulb", block: false, force: false, clear_cache: true}, status: "ok"}),
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it("Should allow to remove group", async () => {
|
||||
const group = groups.group_1;
|
||||
const removeGroupFromLookup = vi.spyOn(controller.zigbee, "removeGroupFromLookup");
|
||||
@@ -3105,7 +3131,11 @@ describe("Extension: Bridge", () => {
|
||||
await flushPromises();
|
||||
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
|
||||
"zigbee2mqtt/bridge/response/device/remove",
|
||||
stringify({data: {}, status: "error", error: "Failed to remove device 'bulb' (block: false, force: false) (Error: device timeout)"}),
|
||||
stringify({
|
||||
data: {},
|
||||
status: "error",
|
||||
error: "Failed to remove device 'bulb' (block: false, force: false, clear cache: false) (Error: device timeout)",
|
||||
}),
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user