diff --git a/lib/extension/bridge.js b/lib/extension/bridge.js index 023a27a6a..535a63ed5 100644 --- a/lib/extension/bridge.js +++ b/lib/extension/bridge.js @@ -42,7 +42,16 @@ class Bridge extends Extension { this.coordinatorVersion = await this.zigbee.getCoordinatorVersion(); this.eventBus.on(`groupMembersChanged`, () => this.publishGroups()); - this.eventBus.on(`devicesChanged`, () => this.publishDevices()); + this.eventBus.on(`devicesChanged`, () => { + this.publishDevices(); + this.publishInfo(); + }); + this.eventBus.on(`deviceRenamed`, () => { + this.publishInfo(); + }); + this.eventBus.on(`groupRenamed`, () => { + this.publishInfo(); + }); this.zigbee.on('permitJoinChanged', (data) => this.permitJoinChanged(data)); await this.publishInfo(); await this.publishDevices(); @@ -305,7 +314,7 @@ class Bridge extends Extension { } } - changeEntityOptions(entityType, message) { + async changeEntityOptions(entityType, message) { if (typeof message !== 'object' || !message.hasOwnProperty('id') || !message.hasOwnProperty('options')) { throw new Error(`Invalid payload`); } @@ -319,6 +328,7 @@ class Bridge extends Extension { }; const oldOptions = cleanup(entity.settings); const newOptions = cleanup(settings.getEntity(ID)); + await this.publishInfo(); return utils.getResponse(message, {from: oldOptions, to: newOptions, id: ID}, null); } diff --git a/lib/util/settings.schema.json b/lib/util/settings.schema.json index a2d53ed24..914009380 100644 --- a/lib/util/settings.schema.json +++ b/lib/util/settings.schema.json @@ -445,28 +445,7 @@ }, "patternProperties": { "^.*$": { - "type": "object", - "properties": { - "friendly_name": { - "type": "string" - }, - "retain": { - "type": "boolean" - }, - "retention": { - "type": "number" - }, - "qos": { - "type": "number" - }, - "filtered_attributes": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["friendly_name"] + "$ref": "#/definitions/device" } } }, @@ -477,37 +456,77 @@ }, "patternProperties": { "^.*$": { - "type": "object", - "properties": { - "friendly_name": { - "type": "string" - }, - "retain": { - "type": "boolean" - }, - "devices": { - "type": "array", - "items": { - "type": "string" - } - }, - "optimistic": { - "type": "boolean" - }, - "qos": { - "type": "number" - }, - "filtered_attributes": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["friendly_name"] + "$ref": "#/definitions/group" } } } }, - "required": ["mqtt"] + "required": ["mqtt"], + "definitions": { + "device": { + "type": "object", + "properties": { + "friendly_name": { + "type": "string", + "title": "Friendly name", + "description": "Used in the MQTT topic of a device. By default this is the device ID" + }, + "retain": { + "type": "boolean", + "title": "Retain", + "description": "Retain MQTT messages of this device" + }, + "retention": { + "type": "number", + "title": "Retention", + "description": "Sets the MQTT Message Expiry in seconds" + }, + "qos": { + "type": "number", + "title": "QoS", + "descritption": "QoS level for MQTT messages of this device" + }, + "filtered_attributes": { + "type": "array", + "items": { + "type": "string" + }, + "examples": ["temperature", "battery", "action"], + "title": "Filtered attributes", + "description": "Allows to prevent certain attributes from being published" + } + }, + "required": ["friendly_name"] + }, + "group": { + "type": "object", + "properties": { + "friendly_name": { + "type": "string" + }, + "retain": { + "type": "boolean" + }, + "devices": { + "type": "array", + "items": { + "type": "string" + } + }, + "optimistic": { + "type": "boolean" + }, + "qos": { + "type": "number" + }, + "filtered_attributes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["friendly_name"] + } + } } \ No newline at end of file diff --git a/test/bind.test.js b/test/bind.test.js index a383b34bc..882a2016d 100644 --- a/test/bind.test.js +++ b/test/bind.test.js @@ -43,7 +43,7 @@ describe('Bind', () => { expect(endpoint.bind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.bind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.bind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(5); + expect(MQTT.publish).toHaveBeenCalledTimes(6); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/device/bind', stringify({"data":{"from":"remote","to":"bulb_color","clusters":["genScenes","genOnOff","genLevelCtrl"],"failed":[]},"status":"ok"}), @@ -267,7 +267,7 @@ describe('Bind', () => { expect(endpoint.bind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.bind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.bind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_bind', message: {from: 'remote', to: 'bulb_color', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log'); @@ -298,7 +298,7 @@ describe('Bind', () => { expect(endpoint.unbind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.unbind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.unbind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_unbind', message: {from: 'remote', to: 'bulb_color', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log'); @@ -319,7 +319,7 @@ describe('Bind', () => { expect(endpoint.unbind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.unbind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.unbind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_unbind', message: {from: 'remote', to: 'Coordinator', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log'); @@ -339,7 +339,7 @@ describe('Bind', () => { expect(endpoint.bind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.bind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.bind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_bind', message: {from: 'remote', to: 'group_1', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log'); @@ -359,7 +359,7 @@ describe('Bind', () => { expect(endpoint.bind).toHaveBeenCalledWith("genOnOff", target); expect(endpoint.bind).toHaveBeenCalledWith("genLevelCtrl", target); expect(endpoint.bind).toHaveBeenCalledWith("genScenes", target); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_bind', message: {from: 'remote', to: 'group_1', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log'); @@ -413,7 +413,7 @@ describe('Bind', () => { expect(endpoint.unbind).toHaveBeenCalledWith("genOnOff", 901); expect(endpoint.unbind).toHaveBeenCalledWith("genLevelCtrl", 901); expect(endpoint.unbind).toHaveBeenCalledWith("genScenes", 901); - expect(MQTT.publish).toHaveBeenCalledTimes(4); + expect(MQTT.publish).toHaveBeenCalledTimes(5); expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({type: 'device_unbind', message: {from: 'remote', to: 'default_bind_group', cluster: 'genScenes'}}); expect(MQTT.publish.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/bridge/log');