diff --git a/lib/extension/bridge.js b/lib/extension/bridge.js index f053bcb2..4a4da8f5 100644 --- a/lib/extension/bridge.js +++ b/lib/extension/bridge.js @@ -18,6 +18,7 @@ class Bridge extends Extension { this.requestLookup = { 'device/options': this.deviceOptions.bind(this), + 'device/configure_reporting': this.deviceConfigureReporting.bind(this), 'device/remove': this.deviceRemove.bind(this), 'device/rename': this.deviceRename.bind(this), 'group/add': this.groupAdd.bind(this), @@ -310,6 +311,29 @@ class Bridge extends Extension { return utils.getResponse(message, {from: oldOptions, to: newOptions, id: ID}, null); } + async deviceConfigureReporting(message) { + if (typeof message !== 'object' || !message.hasOwnProperty('id') || !message.hasOwnProperty('cluster') || + !message.hasOwnProperty('maximum_report_interval') || !message.hasOwnProperty('minimum_report_interval') || + !message.hasOwnProperty('reportable_change') || !message.hasOwnProperty('attribute')) { + throw new Error(`Invalid payload`); + } + + const ID = message.id; + const endpoint = this.getEntity('device', ID).endpoint; + await endpoint.configureReporting(message.cluster, [{ + attribute: message.attribute, minimumReportInterval: message.minimum_report_interval, + maximumReportInterval: message.maximum_report_interval, reportableChange: message.reportable_change, + }]); + + this.publishDevices(); + + return utils.getResponse(message, { + id: message.id, cluster: message.cluster, maximum_report_interval: message.maximum_report_interval, + minimum_report_interval: message.minimum_report_interval, reportable_change: message.reportable_change, + attribute: message.attribute, + }, null); + } + renameEntity(entityType, message) { const deviceAndHasLast = entityType === 'device' && typeof message === 'object' && message.last === true; if (typeof message !== 'object' || (!message.hasOwnProperty('from') && !deviceAndHasLast) || diff --git a/test/bridge.test.js b/test/bridge.test.js index f352e403..c22425de 100644 --- a/test/bridge.test.js +++ b/test/bridge.test.js @@ -819,4 +819,43 @@ describe('Bridge', () => { {retain: false, qos: 0}, expect.any(Function) ); }); + + it('Should allow to configure reporting', async () => { + 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', stringify({id: 'bulb', cluster: 'genLevelCtrl', attribute: 'currentLevel', maximum_report_interval: 10, minimum_report_interval: 1, reportable_change: 1})); + await flushPromises(); + expect(endpoint.configureReporting).toHaveBeenCalledTimes(1); + expect(endpoint.configureReporting).toHaveBeenCalledWith('genLevelCtrl', [{"attribute": "currentLevel", "maximumReportInterval": 10, "minimumReportInterval": 1, "reportableChange": 1}]); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/bridge/response/device/configure_reporting', + stringify({"data":{id: 'bulb', cluster: 'genLevelCtrl', attribute: 'currentLevel', maximum_report_interval: 10, minimum_report_interval: 1, reportable_change: 1},"status":"ok"}), + {retain: false, qos: 0}, expect.any(Function) + ); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/bridge/devices', + expect.any(String), + { retain: true, qos: 0 }, + expect.any(Function) + ); + }); + + it('Should throw error when configure reporting is called with misformed payload', async () => { + 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', stringify({id: 'bulb', cluster: 'genLevelCtrl', attribute_lala: 'currentLevel', maximum_report_interval: 10, minimum_report_interval: 1, reportable_change: 1})); + await flushPromises(); + expect(endpoint.configureReporting).toHaveBeenCalledTimes(0); + expect(MQTT.publish).toHaveBeenCalledWith( + 'zigbee2mqtt/bridge/response/device/configure_reporting', + stringify({"data":{},"status":"error","error":"Invalid payload"}), + {retain: false, qos: 0}, expect.any(Function) + ); + }); });