From 1a5176d9a703c340fedf229fa03913999afa213b Mon Sep 17 00:00:00 2001 From: koenkk Date: Sun, 13 Aug 2023 09:04:55 +0200 Subject: [PATCH 1/2] feat: Support coordinator check --- lib/extension/bridge.ts | 9 +++++++++ lib/zigbee.ts | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/lib/extension/bridge.ts b/lib/extension/bridge.ts index a8d65e29c7..19ada2f10e 100644 --- a/lib/extension/bridge.ts +++ b/lib/extension/bridge.ts @@ -46,6 +46,7 @@ export default class Bridge extends Extension { 'install_code/add': this.installCodeAdd, 'touchlink/scan': this.touchlinkScan, 'health_check': this.healthCheck, + 'coordinator_check': this.coordinatorCheck, 'options': this.bridgeOptions, // Below are deprecated 'config/last_seen': this.configLastSeen, @@ -181,6 +182,14 @@ export default class Bridge extends Extension { return utils.getResponse(message, {healthy: true}, null); } + @bind async coordinatorCheck(message: string | KeyValue): Promise { + const result = await this.zigbee.coordinatorCheck(); + const missingRouters = result.missingRouters.map((d) => { + return {ieee_address: d.ieeeAddr, friendly_name: d.name}; + }); + return utils.getResponse(message, {missing_routers: missingRouters}, null); + } + @bind async groupAdd(message: string | KeyValue): Promise { if (typeof message === 'object' && !message.hasOwnProperty('friendly_name')) { throw new Error(`Invalid payload`); diff --git a/lib/zigbee.ts b/lib/zigbee.ts index d73102de94..77814ae42e 100644 --- a/lib/zigbee.ts +++ b/lib/zigbee.ts @@ -195,6 +195,11 @@ export default class Zigbee { return this.herdsman.backup(); } + async coordinatorCheck(): Promise<{missingRouters: Device[]}> { + const check = await this.herdsman.coordinatorCheck(); + return {missingRouters: check.missingRouters.map((d) => this.resolveDevice(d.ieeeAddr))}; + } + async getNetworkParameters(): Promise { return this.herdsman.getNetworkParameters(); } From 5a02bf02d58fa94b27d326191e71bcdd8b67f184 Mon Sep 17 00:00:00 2001 From: koenkk Date: Sun, 13 Aug 2023 09:12:55 +0200 Subject: [PATCH 2/2] add tests --- test/bridge.test.js | 12 ++++++++++++ test/frontend.test.js | 2 +- test/stub/zigbeeHerdsman.js | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/test/bridge.test.js b/test/bridge.test.js index 75a29995e8..21e08ced2c 100644 --- a/test/bridge.test.js +++ b/test/bridge.test.js @@ -408,6 +408,18 @@ describe('Bridge', () => { ); }); + it('Should allow a coordinator check', async () => { + MQTT.publish.mockClear(); + zigbeeHerdsman.coordinatorCheck.mockReturnValueOnce({missingRouters: [zigbeeHerdsman.getDeviceByIeeeAddr('0x000b57fffec6a5b2')]}) + MQTT.events.message('zigbee2mqtt/bridge/request/coordinator_check', ''); + await flushPromises(); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/bridge/response/coordinator_check', + stringify({"data":{"missing_routers":[{"friendly_name":"bulb","ieee_address":"0x000b57fffec6a5b2"}]},"status":"ok"}), + {retain: false, qos: 0}, expect.any(Function) + ); + }); + it('Should allow to remove device by string', async () => { const device = zigbeeHerdsman.devices.bulb; settings.set(['groups'], {'1': {friendly_name: 'group_1', retain: false, devices: ['0x999b57fffec6a5b9/1', '0x000b57fffec6a5b2/1', 'bulb', 'bulb/right', 'other_bulb', 'bulb_1', '0x000b57fffec6a5b2', 'bulb/room/2']}}); diff --git a/test/frontend.test.js b/test/frontend.test.js index fd6b3fa608..b164123c75 100644 --- a/test/frontend.test.js +++ b/test/frontend.test.js @@ -197,7 +197,7 @@ describe('Frontend', () => { }); - it('onlythis Websocket interaction', async () => { + it('Websocket interaction', async () => { controller = new Controller(jest.fn(), jest.fn()); await controller.start(); diff --git a/test/stub/zigbeeHerdsman.js b/test/stub/zigbeeHerdsman.js index a2e5c919d0..fa4f96c984 100644 --- a/test/stub/zigbeeHerdsman.js +++ b/test/stub/zigbeeHerdsman.js @@ -214,6 +214,7 @@ const mock = { touchlinkIdentify: jest.fn(), start: jest.fn(), backup: jest.fn(), + coordinatorCheck: jest.fn(), isStopping: jest.fn(), permitJoin: jest.fn(), addInstallCode: jest.fn(),