Allow joining for a specific amount of time. https://github.com/nurikk/z2m-frontend/issues/202

This commit is contained in:
Koen Kanters
2021-01-03 11:08:33 +01:00
parent 1298769d4d
commit d53b63d67e
5 changed files with 44 additions and 18 deletions
+12 -5
View File
@@ -43,6 +43,7 @@ class Bridge extends Extension {
this.eventBus.on(`groupMembersChanged`, () => this.publishGroups());
this.eventBus.on(`devicesChanged`, () => this.publishDevices());
this.zigbee.on('permitJoinChanged', (data) => this.permitJoinChanged(data));
await this.publishInfo();
await this.publishDevices();
await this.publishGroups();
@@ -61,6 +62,10 @@ class Bridge extends Extension {
logger.add(new EventTransport({level: logger.getLevel()}));
}
permitJoinChanged(data) {
this.publishInfo();
}
async onMQTTMessage(topic, message) {
const match = topic.match(requestRegex);
if (match && this.requestLookup[match[1].toLowerCase()]) {
@@ -165,9 +170,11 @@ class Bridge extends Extension {
}
let value;
let time;
let resolvedEntity;
if (typeof message === 'object') {
value = message.value;
time = message.time;
if (message.device) {
resolvedEntity = this.zigbee.resolveEntity(message.device);
if (!resolvedEntity || resolvedEntity.type !== 'device') {
@@ -178,11 +185,11 @@ class Bridge extends Extension {
value = message;
}
await this.zigbee.permitJoin(value, resolvedEntity);
await this.publishInfo();
return utils.getResponse(
message, resolvedEntity ? {value: value, device: message.device} : {value: value}, null,
);
await this.zigbee.permitJoin(value, resolvedEntity, time);
const response = {value};
if (resolvedEntity) response.device = message.device;
if (time) response.time = message.time;
return utils.getResponse(message, response, null);
}
configLastSeen(message) {
+4 -3
View File
@@ -68,6 +68,7 @@ class Zigbee extends events.EventEmitter {
this.herdsman.on('deviceJoined', (data) => this.emit('event', 'deviceJoined', data));
this.herdsman.on('deviceLeave', (data) => this.emit('event', 'deviceLeave', data));
this.herdsman.on('message', (data) => this.emit('event', 'message', data));
this.herdsman.on('permitJoinChanged', (data) => this.emit('permitJoinChanged', data));
logger.info('zigbee-herdsman started');
logger.info(`Coordinator firmware version: '${stringify(await this.getCoordinatorVersion())}'`);
@@ -118,15 +119,15 @@ class Zigbee extends events.EventEmitter {
logger.info('zigbee-herdsman stopped');
}
async permitJoin(permit, resolvedEntity) {
async permitJoin(permit, resolvedEntity, time=undefined) {
permit ?
logger.info(`Zigbee: allowing new devices to join${resolvedEntity ? ` via ${resolvedEntity.name}` : ''}.`) :
logger.info('Zigbee: disabling joining new devices.');
if (resolvedEntity && permit) {
await this.herdsman.permitJoin(permit, resolvedEntity.device);
await this.herdsman.permitJoin(permit, resolvedEntity.device, time);
} else {
await this.herdsman.permitJoin(permit);
await this.herdsman.permitJoin(permit, undefined, time);
}
}
+24 -6
View File
@@ -201,8 +201,7 @@ describe('Bridge', () => {
MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', 'true');
await flushPromises();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, undefined, undefined);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/permit_join',
stringify({"data":{"value":true},"status":"ok"}),
@@ -214,8 +213,7 @@ describe('Bridge', () => {
MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({"value": false}));
await flushPromises();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/permit_join',
stringify({"data":{"value":false},"status":"ok"}),
@@ -235,6 +233,27 @@ 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, time: 10});
await flushPromises();
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
});
it('Should allow permit join via device', async () => {
const device = zigbeeHerdsman.devices.bulb;
zigbeeHerdsman.permitJoin.mockClear();
@@ -242,8 +261,7 @@ describe('Bridge', () => {
MQTT.events.message('zigbee2mqtt/bridge/request/permit_join', stringify({value: true, device: 'bulb'}));
await flushPromises();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, device);
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/info', expect.any(String), { retain: true, qos: 0 }, expect.any(Function));
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, device, undefined);
expect(MQTT.publish).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/response/permit_join',
stringify({"data":{"value":true,"device":"bulb"},"status":"ok"}),
+2 -2
View File
@@ -36,7 +36,7 @@ describe('Controller', () => {
expect(zigbeeHerdsman.setLED).toHaveBeenCalledTimes(0);
expect(zigbeeHerdsman.setTransmitPower).toHaveBeenCalledTimes(0);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true);
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 LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (Router)');
expect(logger.info).toHaveBeenCalledWith('remote (0x0017880104e45517): 324131092621 - Philips Hue dimmer switch (EndDevice)');
@@ -202,7 +202,7 @@ describe('Controller', () => {
settings.set(['permit_join'], false);
await controller.start();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined);
});
it('Start controller with disable_led', async () => {
+2 -2
View File
@@ -123,12 +123,12 @@ describe('Bridge legacy', () => {
MQTT.events.message('zigbee2mqtt/bridge/config/permit_join', 'true');
await flushPromises();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(true, undefined, undefined);
zigbeeHerdsman.permitJoin.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/config/permit_join', 'false');
await flushPromises();
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledTimes(1);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false);
expect(zigbeeHerdsman.permitJoin).toHaveBeenCalledWith(false, undefined, undefined);
});
it('Should allow to reset', async () => {