mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-06 19:00:13 +00:00
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 <koenkanters94@gmail.com>
This commit is contained in:
committed by
Koen Kanters
co-authored by
Koen Kanters
parent
b6186623f0
commit
2124d3450c
@@ -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();
|
||||
|
||||
+10
-27
@@ -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<MQTTResponse> {
|
||||
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;
|
||||
time = Number.parseInt(message, 10);
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = value.toLowerCase() === 'true';
|
||||
}
|
||||
await this.zigbee.permitJoin(time, device);
|
||||
|
||||
await this.zigbee.permitJoin(value, device, time);
|
||||
const response: {time: number; device?: string} = {time};
|
||||
|
||||
const response: {value: boolean; device?: string; time?: number} = {value};
|
||||
|
||||
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,
|
||||
|
||||
@@ -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}',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Vendored
-1
@@ -120,7 +120,6 @@ declare global {
|
||||
legacy_triggers: boolean;
|
||||
experimental_event_entities: boolean;
|
||||
};
|
||||
permit_join: boolean;
|
||||
availability?: {
|
||||
active: {timeout: number};
|
||||
passive: {timeout: number};
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
|
||||
@@ -43,7 +43,6 @@ const ajvRestartRequiredGroupOptions = new Ajv({allErrors: true})
|
||||
.addKeyword({keyword: 'requiresRestart', validate: (s: unknown) => !s})
|
||||
.compile(schemaJson.definitions.group);
|
||||
const defaults: RecursivePartial<Settings> = {
|
||||
permit_join: false,
|
||||
external_converters: [],
|
||||
mqtt: {
|
||||
base_topic: 'zigbee2mqtt',
|
||||
|
||||
+4
-12
@@ -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<void> {
|
||||
if (permit) {
|
||||
async permitJoin(time: number, device?: Device): Promise<void> {
|
||||
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 {
|
||||
|
||||
+5
-5
@@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
Generated
+20
-16
@@ -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
|
||||
|
||||
+46
-93
@@ -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,70 +2579,52 @@ 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'}),
|
||||
{retain: false, qos: 0},
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
zigbeeHerdsman.permitJoin.mockClear();
|
||||
MQTT.publish.mockClear();
|
||||
MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: false}));
|
||||
await flushPromises();
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {value: false}, 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'}));
|
||||
await flushPromises();
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {value: false}, 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}));
|
||||
await flushPromises();
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(0);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {}, status: 'error', error: 'Invalid payload'}),
|
||||
stringify({data: {time: 1}, status: 'ok'}),
|
||||
{retain: false, qos: 0},
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
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}));
|
||||
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, 10);
|
||||
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(0, undefined);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {value: false, time: 10}, status: 'ok'}),
|
||||
stringify({data: {time: 0}, status: 'ok'}),
|
||||
{retain: false, qos: 0},
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
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(1, undefined);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {time: 1}, status: 'ok'}),
|
||||
{retain: false, qos: 0},
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
'zigbee2mqtt/bridge/response/permit_join',
|
||||
stringify({data: {}, status: 'error', error: 'Invalid payload'}),
|
||||
{retain: false, qos: 0},
|
||||
expect.any(Function),
|
||||
);
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 }}'}],
|
||||
|
||||
@@ -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});
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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, []);
|
||||
|
||||
Reference in New Issue
Block a user