From 2124d3450cbc5ad5901a7fa2d657b881152a6db6 Mon Sep 17 00:00:00 2001 From: Nerivec <62446222+Nerivec@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:18:23 +0200 Subject: [PATCH] fix!: Improve permit join (#24257) * fix: Improve permit join * Update Home Assistant permit join switch * Remove `permit_join` from `settings.schema.json` * Update zigbee-herdsman version to pre-release. * Fix pnpm overrides * Update test/homeassistant.test.js --------- Co-authored-by: Koen Kanters --- lib/controller.ts | 13 ---- lib/extension/bridge.ts | 37 +++--------- lib/extension/homeassistant.ts | 5 +- lib/types/types.d.ts | 1 - lib/util/settings.schema.json | 6 -- lib/util/settings.ts | 1 - lib/zigbee.ts | 16 ++--- package.json | 10 +-- pnpm-lock.yaml | 36 ++++++----- test/bridge.test.js | 107 +++++++++------------------------ test/controller.test.js | 19 ------ test/homeassistant.test.js | 5 +- test/settings.test.js | 8 +-- test/stub/data.js | 1 - test/stub/zigbeeHerdsman.js | 3 +- 15 files changed, 80 insertions(+), 188 deletions(-) diff --git a/lib/controller.ts b/lib/controller.ts index 60dcde1733..e36ed832a0 100644 --- a/lib/controller.ts +++ b/lib/controller.ts @@ -167,19 +167,6 @@ export class Controller { logger.info(`Currently ${deviceCount} devices are joined.`); - // Enable zigbee join - try { - if (settings.get().permit_join) { - logger.warning('`permit_join` set to `true` in configuration.yaml.'); - logger.warning('Allowing new devices to join.'); - logger.warning('Set `permit_join` to `false` once you joined all devices.'); - } - - await this.zigbee.permitJoin(settings.get().permit_join); - } catch (error) { - logger.error(`Failed to set permit join to ${settings.get().permit_join} (${(error as Error).message})`); - } - // MQTT try { await this.mqtt.connect(); diff --git a/lib/extension/bridge.ts b/lib/extension/bridge.ts index d5d1549d30..69ff55963f 100644 --- a/lib/extension/bridge.ts +++ b/lib/extension/bridge.ts @@ -225,10 +225,6 @@ export default class Bridge extends Extension { if (restartRequired) this.restartRequired = true; // Apply some settings on-the-fly. - if (newSettings.permit_join != undefined) { - await this.zigbee.permitJoin(settings.get().permit_join); - } - if (newSettings.homeassistant != undefined) { await this.enableDisableExtension(!!settings.get().homeassistant, 'HomeAssistant'); } @@ -323,17 +319,15 @@ export default class Bridge extends Extension { } @bind async permitJoin(message: KeyValue | string): Promise { - if (typeof message === 'object' && message.value === undefined) { - throw new Error('Invalid payload'); - } - - let value: boolean | string; let time: number | undefined; let device: Device | undefined; if (typeof message === 'object') { - value = message.value; - time = message.time; + if (message.time === undefined) { + throw new Error('Invalid payload'); + } + + time = Number.parseInt(message.time, 10); if (message.device) { const resolved = this.zigbee.resolveEntity(message.device); @@ -345,25 +339,15 @@ export default class Bridge extends Extension { } } } else { - value = message; - } - - if (typeof value === 'string') { - value = value.toLowerCase() === 'true'; + time = Number.parseInt(message, 10); } - await this.zigbee.permitJoin(value, device, time); + await this.zigbee.permitJoin(time, device); - const response: {value: boolean; device?: string; time?: number} = {value}; + const response: {time: number; device?: string} = {time}; - if (typeof message === 'object') { - if (device) { - response.device = message.device; - } - - if (time != undefined) { - response.time = message.time; - } + if (device) { + response.device = device.name; } return utils.getResponse(message, response); @@ -679,7 +663,6 @@ export default class Bridge extends Extension { }, network: utils.toSnakeCaseObject(await this.zigbee.getNetworkParameters()), log_level: logger.getLevel(), - permit_join: this.zigbee.getPermitJoin(), permit_join_timeout: this.zigbee.getPermitJoinTimeout(), restart_required: this.restartRequired, config, diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index 4e964d2b7e..f641a129d5 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -2203,8 +2203,9 @@ export default class HomeAssistant extends Extension { value_template: '{{ value_json.permit_join | lower }}', command_topic: `${baseTopic}/request/permit_join`, state_on: 'true', - payload_on: '{"value": true, "time": 254}', - payload_off: 'false', + state_off: 'false', + payload_on: '{"time": 254}', + payload_off: '{"time": 0}', }, }, ); diff --git a/lib/types/types.d.ts b/lib/types/types.d.ts index aee04cd7b7..312a442892 100644 --- a/lib/types/types.d.ts +++ b/lib/types/types.d.ts @@ -120,7 +120,6 @@ declare global { legacy_triggers: boolean; experimental_event_entities: boolean; }; - permit_join: boolean; availability?: { active: {timeout: number}; passive: {timeout: number}; diff --git a/lib/util/settings.schema.json b/lib/util/settings.schema.json index defa569e0e..8043099cd6 100644 --- a/lib/util/settings.schema.json +++ b/lib/util/settings.schema.json @@ -51,12 +51,6 @@ } ] }, - "permit_join": { - "type": "boolean", - "default": false, - "title": "Permit join", - "description": "Allow new devices to join (re-applied at restart)" - }, "availability": { "oneOf": [ { diff --git a/lib/util/settings.ts b/lib/util/settings.ts index 7ecdd7a469..eabd8be7fe 100644 --- a/lib/util/settings.ts +++ b/lib/util/settings.ts @@ -43,7 +43,6 @@ const ajvRestartRequiredGroupOptions = new Ajv({allErrors: true}) .addKeyword({keyword: 'requiresRestart', validate: (s: unknown) => !s}) .compile(schemaJson.definitions.group); const defaults: RecursivePartial = { - permit_join: false, external_converters: [], mqtt: { base_topic: 'zigbee2mqtt', diff --git a/lib/zigbee.ts b/lib/zigbee.ts index 5786cdc713..8a7e5e2b52 100644 --- a/lib/zigbee.ts +++ b/lib/zigbee.ts @@ -225,26 +225,18 @@ export default class Zigbee { logger.info('Stopped zigbee-herdsman'); } - getPermitJoin(): boolean { - return this.herdsman.getPermitJoin(); - } - - getPermitJoinTimeout(): number | undefined { + getPermitJoinTimeout(): number { return this.herdsman.getPermitJoinTimeout(); } - async permitJoin(permit: boolean, device?: Device, time?: number): Promise { - if (permit) { + async permitJoin(time: number, device?: Device): Promise { + if (time > 0) { logger.info(`Zigbee: allowing new devices to join${device ? ` via ${device.name}` : ''}.`); } else { logger.info('Zigbee: disabling joining new devices.'); } - if (device && permit) { - await this.herdsman.permitJoin(permit, device.zh, time); - } else { - await this.herdsman.permitJoin(permit, undefined, time); - } + await this.herdsman.permitJoin(time, device?.zh); } @bind private resolveDevice(ieeeAddr: string): Device | undefined { diff --git a/package.json b/package.json index cb3b655406..c0ba7d1d12 100644 --- a/package.json +++ b/package.json @@ -61,9 +61,9 @@ "winston-syslog": "^2.7.1", "winston-transport": "^4.9.0", "ws": "^8.18.0", - "zigbee-herdsman": "2.1.9", - "zigbee-herdsman-converters": "20.58.0", - "zigbee2mqtt-frontend": "0.7.6" + "zigbee-herdsman": "3.0.0-pre.0", + "zigbee-herdsman-converters": "20.28.0", + "zigbee2mqtt-frontend": "0.7.4" }, "devDependencies": { "@babel/core": "^7.26.0", @@ -93,8 +93,8 @@ "typescript": "^5.7.2", "typescript-eslint": "^8.15.0" }, - "overrides": { - "zigbee-herdsman-converters": { + "pnpm": { + "overrides": { "zigbee-herdsman": "$zigbee-herdsman" } }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f0d0bb94d2..a7378bcb44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + zigbee-herdsman: 3.0.0-pre.0 + importers: .: @@ -81,11 +84,11 @@ importers: specifier: ^8.18.0 version: 8.18.0 zigbee-herdsman: - specifier: 2.1.3 - version: 2.1.3 + specifier: 3.0.0-pre.0 + version: 3.0.0-pre.0 zigbee-herdsman-converters: - specifier: 20.25.0 - version: 20.25.0 + specifier: 20.28.0 + version: 20.28.0 zigbee2mqtt-frontend: specifier: 0.7.4 version: 0.7.4 @@ -95,13 +98,13 @@ importers: version: 2.8.0 devDependencies: '@babel/core': - specifier: ^7.25.7 + specifier: ^7.25.8 version: 7.25.8 '@babel/plugin-proposal-decorators': specifier: ^7.25.7 version: 7.25.7(@babel/core@7.25.8) '@babel/preset-env': - specifier: ^7.25.7 + specifier: ^7.25.8 version: 7.25.8(@babel/core@7.25.8) '@babel/preset-typescript': specifier: ^7.25.7 @@ -131,7 +134,7 @@ importers: specifier: ^4.0.9 version: 4.0.9 '@types/node': - specifier: ^22.7.4 + specifier: ^22.7.5 version: 22.7.5 '@types/object-assign-deep': specifier: ^0.4.3 @@ -164,10 +167,10 @@ importers: specifier: ^0.2.3 version: 0.2.3 typescript: - specifier: ^5.6.2 + specifier: ^5.6.3 version: 5.6.3 typescript-eslint: - specifier: ^8.8.0 + specifier: ^8.8.1 version: 8.8.1(eslint@9.12.0)(typescript@5.6.3) packages: @@ -2800,11 +2803,11 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zigbee-herdsman-converters@20.25.0: - resolution: {integrity: sha512-iqCQmcdwrUGz00IhvtB36l3YN9sCWPhbx8D+lf9owyjpE5To7u2pOn4GA4g6QWQCU7BndCif8fXed1FWt9/nrg==} + zigbee-herdsman-converters@20.28.0: + resolution: {integrity: sha512-AMCuG4mlIR21JgShIyFnZsCimfITH2HpjQLS0vaAqIKmbYrG7sBF0MU/iznYc/8JqNq+Jav3BdV+BrE1M3GpEg==} - zigbee-herdsman@2.1.3: - resolution: {integrity: sha512-1LiSb3L2ZFzNOuGJHMWBFPRgPs1WVMS4CagtvYxEVUdifhVivp1vMNrCxBsbwNhDiNBh/Blk0pTR0szJttLzrA==} + zigbee-herdsman@3.0.0-pre.0: + resolution: {integrity: sha512-3mCSmdwu5eJb0DEJrTDSQPYEQAz1mOGAbqvXyEOjo6UOllo++GyzpmawTxWBH4FLWrbuKc9SefiVqQdC/4uZbQ==} zigbee2mqtt-frontend@0.7.4: resolution: {integrity: sha512-skWNYxThSa6Ywn7aRB0ZvRKWifpqbku4+vUM5BbXiNaXYxCCbU0b3pN258Ahxt3NsLtYk2zBdYoQcXuBZxmJxw==} @@ -5939,7 +5942,7 @@ snapshots: yocto-queue@0.1.0: {} - zigbee-herdsman-converters@20.25.0: + zigbee-herdsman-converters@20.28.0: dependencies: axios: 1.7.7 buffer-crc32: 1.0.0 @@ -5947,12 +5950,13 @@ snapshots: iconv-lite: 0.6.3 semver: 7.6.3 tar-stream: 3.1.7 - zigbee-herdsman: 2.1.3 + uri-js: 4.4.1 + zigbee-herdsman: 3.0.0-pre.0 transitivePeerDependencies: - debug - supports-color - zigbee-herdsman@2.1.3: + zigbee-herdsman@3.0.0-pre.0: dependencies: '@serialport/bindings-cpp': 12.0.1 '@serialport/parser-delimiter': 12.0.0 diff --git a/test/bridge.test.js b/test/bridge.test.js index 9f9fc8c431..7bd2ddfb5b 100644 --- a/test/bridge.test.js +++ b/test/bridge.test.js @@ -64,6 +64,7 @@ describe('Bridge', () => { logger.warning.mockClear(); logger.setTransportsEnabled(false); MQTT.publish.mockClear(); + zigbeeHerdsman.permitJoin.mockClear(); const device = zigbeeHerdsman.devices.bulb; device.interview.mockClear(); device.removeFromDatabase.mockClear(); @@ -203,14 +204,13 @@ describe('Bridge', () => { mqtt: {base_topic: 'zigbee2mqtt', force_disable_retain: false, include_device_information: false, server: 'mqtt://localhost'}, ota: {disable_automatic_update_check: false, update_check_interval: 1440}, passlist: [], - permit_join: true, serial: {disable_led: false, port: '/dev/dummy'}, }, config_schema: settings.schema, coordinator: {ieee_address: '0x00124b00120144ae', meta: {revision: 20190425, version: 1}, type: 'z-Stack'}, log_level: 'info', network: {channel: 15, extended_pan_id: [0, 11, 22], pan_id: 5674}, - permit_join: false, + permit_join_timeout: 0, restart_required: false, version: version.version, zigbee_herdsman: zhVersion, @@ -2579,50 +2579,47 @@ describe('Bridge', () => { ); }); - it('Should allow permit join', async () => { - zigbeeHerdsman.permitJoin.mockClear(); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', 'true'); + it('Should allow permit join on all', async () => { + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 1})); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, undefined, undefined); + expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(1, undefined); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: true}, status: 'ok'}), + stringify({data: {time: 1}, status: 'ok'}), {retain: false, qos: 0}, expect.any(Function), ); + }); - zigbeeHerdsman.permitJoin.mockClear(); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: false})); + it('Should disallow permit join on all', async () => { + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 0})); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined); + expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(0, undefined); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: false}, status: 'ok'}), + stringify({data: {time: 0}, status: 'ok'}), {retain: false, qos: 0}, expect.any(Function), ); + }); - zigbeeHerdsman.permitJoin.mockClear(); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: 'False'})); + it('Should allow permit join with number string (automatically on all)', async () => { + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', '1'); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined); + expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(1, undefined); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: false}, status: 'ok'}), + stringify({data: {time: 1}, status: 'ok'}), {retain: false, qos: 0}, expect.any(Function), ); + }); - // Invalid payload - zigbeeHerdsman.permitJoin.mockClear(); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value_bla: false})); + it('Should not allow permit join with invalid payload', async () => { + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time_bla: false})); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(0); expect(MQTT.publish).toHaveBeenCalledWith( @@ -2633,21 +2630,6 @@ describe('Bridge', () => { ); }); - it('Should allow permit join for certain time', async () => { - zigbeeHerdsman.permitJoin.mockClear(); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: false, time: 10})); - await flushPromises(); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, 10); - expect(MQTT.publish).toHaveBeenCalledWith( - 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: false, time: 10}, status: 'ok'}), - {retain: false, qos: 0}, - expect.any(Function), - ); - }); - it('Should republish bridge info when permit join changes', async () => { MQTT.publish.mockClear(); await zigbeeHerdsman.events.permitJoinChanged({permitted: false, timeout: 10}); @@ -2665,23 +2647,22 @@ describe('Bridge', () => { it('Should allow permit join via device', async () => { const device = zigbeeHerdsman.devices.bulb; - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: true, device: 'bulb'})); + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 123, device: 'bulb'})); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, device, undefined); + expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(123, device); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: true, device: 'bulb'}, status: 'ok'}), + stringify({data: {time: 123, device: 'bulb'}, status: 'ok'}), {retain: false, qos: 0}, expect.any(Function), ); + }); - // Device does not exist - zigbeeHerdsman.permitJoin.mockClear(); + it('Should not allow permit join via non-existing device', async () => { MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: true, device: 'bulb_not_existing_woeeee'})); + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 123, device: 'bulb_not_existing_woeeee'})); await flushPromises(); expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(0); expect(MQTT.publish).toHaveBeenCalledWith( @@ -2694,11 +2675,11 @@ describe('Bridge', () => { it('Should put transaction in response when request is done with transaction', async () => { MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: false, transaction: 22})); + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 0, transaction: 22})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', - stringify({data: {value: false}, status: 'ok', transaction: 22}), + stringify({data: {time: 0}, status: 'ok', transaction: 22}), {retain: false, qos: 0}, expect.any(Function), ); @@ -2709,7 +2690,7 @@ describe('Bridge', () => { throw new Error('Failed to connect to adapter'); }); MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: false})); + MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({time: 0})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/permit_join', @@ -3555,7 +3536,6 @@ describe('Bridge', () => { const device = zigbeeHerdsman.devices.bulb; const endpoint = device.getEndpoint(1); endpoint.configureReporting.mockClear(); - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message( 'zigbee2mqtt/bridge/request/device/configure_reporting', @@ -3600,7 +3580,6 @@ describe('Bridge', () => { const device = zigbeeHerdsman.devices.bulb; const endpoint = device.getEndpoint(1); endpoint.configureReporting.mockClear(); - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message( 'zigbee2mqtt/bridge/request/device/configure_reporting', @@ -3627,7 +3606,6 @@ describe('Bridge', () => { const device = zigbeeHerdsman.devices.bulb; const endpoint = device.getEndpoint(1); endpoint.configureReporting.mockClear(); - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message( 'zigbee2mqtt/bridge/request/device/configure_reporting', @@ -3654,7 +3632,6 @@ describe('Bridge', () => { const device = zigbeeHerdsman.devices.bulb; const endpoint = device.getEndpoint(1); endpoint.configureReporting.mockClear(); - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message( 'zigbee2mqtt/bridge/request/device/configure_reporting', @@ -3704,7 +3681,6 @@ describe('Bridge', () => { }); it('Should allow to restart', async () => { - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message('zigbee2mqtt/bridge/request/restart', ''); await flushPromises(); @@ -3718,24 +3694,6 @@ describe('Bridge', () => { ); }); - it('Change options', async () => { - zigbeeHerdsman.permitJoin.mockClear(); - settings.apply({permit_join: false}); - MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/options', stringify({options: {permit_join: true}})); - await flushPromises(); - expect(settings.get().permit_join).toBe(true); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, undefined, undefined); - expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), {retain: true, qos: 0}, expect.any(Function)); - expect(MQTT.publish).toHaveBeenCalledWith( - 'zigbee2mqtt/bridge/response/options', - stringify({data: {restart_required: false}, status: 'ok'}), - {retain: false, qos: 0}, - expect.any(Function), - ); - }); - it('Change options and apply - homeassistant', async () => { expect(controller.extensions.find((e) => e.constructor.name === 'HomeAssistant')).toBeUndefined(); MQTT.publish.mockClear(); @@ -3807,7 +3765,6 @@ describe('Bridge', () => { }); it('Change options restart required', async () => { - zigbeeHerdsman.permitJoin.mockClear(); settings.apply({serial: {port: '123'}}); MQTT.publish.mockClear(); MQTT.events.message('zigbee2mqtt/bridge/request/options', stringify({options: {serial: {port: '/dev/newport'}}})); @@ -3822,7 +3779,6 @@ describe('Bridge', () => { }); it('Change options array', async () => { - zigbeeHerdsman.permitJoin.mockClear(); expect(settings.get().advanced.ext_pan_id).toStrictEqual([221, 221, 221, 221, 221, 221, 221, 221]); MQTT.publish.mockClear(); MQTT.events.message( @@ -3840,7 +3796,6 @@ describe('Bridge', () => { }); it('Change options with null', async () => { - zigbeeHerdsman.permitJoin.mockClear(); expect(settings.get().serial).toStrictEqual({disable_led: false, port: '/dev/dummy'}); MQTT.publish.mockClear(); MQTT.events.message('zigbee2mqtt/bridge/request/options', stringify({options: {serial: {disable_led: false, port: null}}})); @@ -3855,7 +3810,6 @@ describe('Bridge', () => { }); it('Change options invalid payload', async () => { - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); MQTT.events.message('zigbee2mqtt/bridge/request/options', 'I am invalid'); await flushPromises(); @@ -3868,13 +3822,12 @@ describe('Bridge', () => { }); it('Change options not valid against schema', async () => { - zigbeeHerdsman.permitJoin.mockClear(); MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/options', stringify({options: {permit_join: 'true'}})); + MQTT.events.message('zigbee2mqtt/bridge/request/options', stringify({options: {external_converters: 'true'}})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/options', - stringify({data: {}, error: 'permit_join must be boolean', status: 'error'}), + stringify({data: {}, error: 'external_converters must be array', status: 'error'}), {retain: false, qos: 0}, expect.any(Function), ); diff --git a/test/controller.test.js b/test/controller.test.js index 939daf82d3..82c243f044 100644 --- a/test/controller.test.js +++ b/test/controller.test.js @@ -10,7 +10,6 @@ const stringify = require('json-stable-stringify-without-jsonify'); const flushPromises = require('./lib/flushPromises'); const tmp = require('tmp'); const mocksClear = [ - zigbeeHerdsman.permitJoin, MQTT.end, zigbeeHerdsman.stop, logger.debug, @@ -84,8 +83,6 @@ describe('Controller', () => { }); expect(zigbeeHerdsman.start).toHaveBeenCalledTimes(1); expect(zigbeeHerdsman.setTransmitPower).toHaveBeenCalledTimes(0); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, undefined, undefined); expect(logger.info).toHaveBeenCalledWith(`Currently ${Object.values(zigbeeHerdsman.devices).length - 1} devices are joined.`); expect(logger.info).toHaveBeenCalledWith( 'bulb (0x000b57fffec6a5b2): LED1545G12 - IKEA TRADFRI bulb E26/E27, white spectrum, globe, opal, 980 lm (Router)', @@ -105,15 +102,6 @@ describe('Controller', () => { expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/remote', stringify({brightness: 255}), {retain: true, qos: 0}, expect.any(Function)); }); - it('Start controller when permit join fails', async () => { - zigbeeHerdsman.permitJoin.mockImplementationOnce(() => { - throw new Error('failed!'); - }); - await controller.start(); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(MQTT.connect).toHaveBeenCalledTimes(1); - }); - it('Start controller with specific MQTT settings', async () => { const ca = tmp.fileSync().name; fs.writeFileSync(ca, 'ca'); @@ -283,13 +271,6 @@ describe('Controller', () => { expect(mockExit).toHaveBeenCalledWith(1, false); }); - it('Start controller with permit join true', async () => { - settings.set(['permit_join'], false); - await controller.start(); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1); - expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined); - }); - it('Start controller and stop with restart', async () => { await controller.start(); await controller.stop(true); diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index 45c7fb1a84..05687cc5e0 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -2813,8 +2813,9 @@ describe('HomeAssistant extension', () => { value_template: '{{ value_json.permit_join | lower }}', command_topic: 'zigbee2mqtt/bridge/request/permit_join', state_on: 'true', - payload_on: '{"value": true, "time": 254}', - payload_off: 'false', + state_off: 'false', + payload_on: '{"time": 254}', + payload_off: '{"time": 0}', origin: origin, device: devicePayload, availability: [{topic: 'zigbee2mqtt/bridge/state', value_template: '{{ value_json.state }}'}], diff --git a/test/settings.test.js b/test/settings.test.js index d29407c4d4..1902648da5 100644 --- a/test/settings.test.js +++ b/test/settings.test.js @@ -13,7 +13,7 @@ const yaml = require('js-yaml'); const objectAssignDeep = require(`object-assign-deep`); const minimalConfig = { - permit_join: true, + external_converters: [], homeassistant: true, mqtt: {base_topic: 'zigbee2mqtt', server: 'localhost'}, }; @@ -55,12 +55,12 @@ describe('Settings', () => { }); it('Should return settings', () => { - write(configurationFile, {permit_join: true}); + write(configurationFile, {external_converters: ['abcd.js']}); const s = settings.get(); const expected = objectAssignDeep.noMutate({}, settings.testing.defaults); expected.devices = {}; expected.groups = {}; - expected.permit_join = true; + expected.external_converters = ['abcd.js']; expect(s).toStrictEqual(expected); }); @@ -964,7 +964,7 @@ describe('Settings', () => { }, }); settings.reRead(); - settings.apply({permit_join: false}); + settings.apply({external_converters: []}); expect(settings.get().device_options.homeassistant).toStrictEqual({temperature: null}); expect(settings.get().devices['0x1234567812345678'].homeassistant).toStrictEqual({humidity: null}); }); diff --git a/test/stub/data.js b/test/stub/data.js index 66a9f80e49..8e00f0d2eb 100644 --- a/test/stub/data.js +++ b/test/stub/data.js @@ -10,7 +10,6 @@ const stateFile = path.join(mockDir, 'state.json'); function writeDefaultConfiguration() { const config = { homeassistant: false, - permit_join: true, mqtt: { base_topic: 'zigbee2mqtt', server: 'mqtt://localhost', diff --git a/test/stub/zigbeeHerdsman.js b/test/stub/zigbeeHerdsman.js index 5cdfe3c563..75a12437ca 100644 --- a/test/stub/zigbeeHerdsman.js +++ b/test/stub/zigbeeHerdsman.js @@ -895,8 +895,7 @@ const mock = { getGroupByID: jest.fn().mockImplementation((groupID) => { return Object.values(groups).find((d) => d.groupID === groupID); }), - getPermitJoin: jest.fn().mockReturnValue(false), - getPermitJoinTimeout: jest.fn().mockReturnValue(undefined), + getPermitJoinTimeout: jest.fn().mockReturnValue(0), reset: jest.fn(), createGroup: jest.fn().mockImplementation((groupID) => { const group = new Group(groupID, []);