diff --git a/src/controller/model/endpoint.ts b/src/controller/model/endpoint.ts index 76ae1d37b0..f433b03ac9 100644 --- a/src/controller/model/endpoint.ts +++ b/src/controller/model/endpoint.ts @@ -64,6 +64,7 @@ interface ConfiguredReportingInternal { minRepIntval: number, maxRepIntval: number, repChange: number, + manufacturerCode?: number | undefined, } interface ConfiguredReporting { @@ -112,7 +113,7 @@ class Endpoint extends Entity { get configuredReportings(): ConfiguredReporting[] { return this._configuredReportings.map((entry) => { - const cluster = Zcl.Utils.getCluster(entry.cluster, this.getDevice().manufacturerID); + const cluster = Zcl.Utils.getCluster(entry.cluster, entry.manufacturerCode); let attribute : Zcl.TsType.Attribute; if (cluster.hasAttribute(entry.attrId)) { @@ -762,7 +763,8 @@ class Endpoint extends Entity { } for (const e of payload) { - const match = this._configuredReportings.find(c => c.attrId === e.attrId && c.cluster === cluster.ID); + const match = this._configuredReportings.find(c => c.attrId === e.attrId && c.cluster === cluster.ID && + c.manufacturerCode == cluster.manufacturerCode); if (match) { this._configuredReportings.splice(this._configuredReportings.indexOf(match), 1); } @@ -773,6 +775,7 @@ class Endpoint extends Entity { this._configuredReportings.push({ cluster: cluster.ID, attrId: entry.attrId, minRepIntval: entry.minRepIntval, maxRepIntval: entry.maxRepIntval, repChange: entry.repChange, + manufacturerCode: options.manufacturerCode, }); } } diff --git a/test/controller.test.ts b/test/controller.test.ts index 473baa462f..e1ad409a10 100755 --- a/test/controller.test.ts +++ b/test/controller.test.ts @@ -2676,14 +2676,14 @@ describe('Controller', () => { expect(deepClone(call[3])).toStrictEqual({"Header":{"frameControl":{"reservedBits":0,"frameType":0,"direction":0,"disableDefaultResponse":true,"manufacturerSpecific":false},"transactionSequenceNumber":11,"manufacturerCode":null,"commandIdentifier":6},"Payload":[{"direction":0,"attrId":1,"dataType":32,"minRepIntval":1,"maxRepIntval":10,"repChange":1}],"Cluster":{"ID":1,"attributes":{"mainsVoltage":{"ID":0,"type":33,"name":"mainsVoltage"},"mainsFrequency":{"ID":1,"type":32,"name":"mainsFrequency"},"mainsAlarmMask":{"ID":16,"type":24,"name":"mainsAlarmMask"},"mainsVoltMinThres":{"ID":17,"type":33,"name":"mainsVoltMinThres"},"mainsVoltMaxThres":{"ID":18,"type":33,"name":"mainsVoltMaxThres"},"mainsVoltageDwellTripPoint":{"ID":19,"type":33,"name":"mainsVoltageDwellTripPoint"},"batteryVoltage":{"ID":32,"type":32,"name":"batteryVoltage"},"batteryPercentageRemaining":{"ID":33,"type":32,"name":"batteryPercentageRemaining"},"batteryManufacturer":{"ID":48,"type":66,"name":"batteryManufacturer"},"batterySize":{"ID":49,"type":48,"name":"batterySize"},"batteryAHrRating":{"ID":50,"type":33,"name":"batteryAHrRating"},"batteryQuantity":{"ID":51,"type":32,"name":"batteryQuantity"},"batteryRatedVoltage":{"ID":52,"type":32,"name":"batteryRatedVoltage"},"batteryAlarmMask":{"ID":53,"type":24,"name":"batteryAlarmMask"},"batteryVoltMinThres":{"ID":54,"type":32,"name":"batteryVoltMinThres"},"batteryVoltThres1":{"ID":55,"type":32,"name":"batteryVoltThres1"},"batteryVoltThres2":{"ID":56,"type":32,"name":"batteryVoltThres2"},"batteryVoltThres3":{"ID":57,"type":32,"name":"batteryVoltThres3"},"batteryPercentMinThres":{"ID":58,"type":32,"name":"batteryPercentMinThres"},"batteryPercentThres1":{"ID":59,"type":32,"name":"batteryPercentThres1"},"batteryPercentThres2":{"ID":60,"type":32,"name":"batteryPercentThres2"},"batteryPercentThres3":{"ID":61,"type":32,"name":"batteryPercentThres3"},"batteryAlarmState":{"ID":62,"type":27,"name":"batteryAlarmState"}},"name":"genPowerCfg","commands":{},"commandsResponse":{}},"Command":{"ID":6,"name":"configReport","parameters":[{"name":"direction","type":32},{"name":"attrId","type":33},{"name":"dataType","type":32,"conditions":[{"type":"directionEquals","value":0}]},{"name":"minRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"maxRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"repChange","type":1000,"conditions":[{"type":"directionEquals","value":0},{"type":"dataTypeValueTypeEquals","value":"ANALOG"}]},{"name":"timeout","type":33,"conditions":[{"type":"directionEquals","value":1}]}],"response":7}}); }); - it('Endpoint configure reporting for manufacturer specific cluster', async () => { + it('Endpoint configure reporting for manufacturer specific cluster with cluster ID collision', async () => { await controller.start(); await mockAdapterEvents['deviceJoined']({networkAddress: 129, ieeeAddr: '0x129'}); const device = controller.getDeviceByIeeeAddr('0x129'); const endpoint = device.getEndpoint(1); mocksendZclFrameToEndpoint.mockClear(); - await endpoint.configureReporting('manuSpecificSamsungAccelerometer', [{ - attribute: 'acceleration', + await endpoint.configureReporting('manuSpecificUbisysHeatingRegulatorThermostat', [{ + attribute: 'classBTemperatureOffset', minimumReportInterval: 1, maximumReportInterval: 10, reportableChange: 1, @@ -2693,7 +2693,20 @@ describe('Controller', () => { expect(call[0]).toBe('0x129'); expect(call[1]).toBe(129); expect(call[2]).toBe(1) - expect(deepClone(call[3])).toStrictEqual({"Header":{"frameControl":{"reservedBits":0,"frameType":0,"direction":0,"disableDefaultResponse":true,"manufacturerSpecific":true},"transactionSequenceNumber":11,"manufacturerCode":4362,"commandIdentifier":6},"Payload":[{"direction":0,"attrId":16,"dataType":24,"minRepIntval":1,"maxRepIntval":10,"repChange":1}],"Cluster":{"ID":64514,"attributes":{"motion_threshold_multiplier":{"ID":0,"type":32,"name":"motion_threshold_multiplier"},"motion_threshold":{"ID":2,"type":33,"name":"motion_threshold"},"acceleration":{"ID":16,"type":24,"name":"acceleration"},"x_axis":{"ID":18,"type":41,"name":"x_axis"},"y_axis":{"ID":19,"type":41,"name":"y_axis"},"z_axis":{"ID":20,"type":41,"name":"z_axis"}},"manufacturerCode":4362,"name":"manuSpecificSamsungAccelerometer","commands":{},"commandsResponse":{}},"Command":{"ID":6,"name":"configReport","parameters":[{"name":"direction","type":32},{"name":"attrId","type":33},{"name":"dataType","type":32,"conditions":[{"type":"directionEquals","value":0}]},{"name":"minRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"maxRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"repChange","type":1000,"conditions":[{"type":"directionEquals","value":0},{"type":"dataTypeValueTypeEquals","value":"ANALOG"}]},{"name":"timeout","type":33,"conditions":[{"type":"directionEquals","value":1}]}],"response":7}}); + expect(deepClone(call[3])).toStrictEqual({"Header":{"frameControl":{"reservedBits":0,"frameType":0,"direction":0,"disableDefaultResponse":true,"manufacturerSpecific":true},"transactionSequenceNumber":11,"manufacturerCode":4338,"commandIdentifier":6},"Payload":[{"direction":0,"attrId":0,"dataType":40,"minRepIntval":1,"maxRepIntval":10,"repChange":1}],"Cluster":{"ID":513,"attributes":{"classBTemperatureOffset":{"ID":0,"type":40,"name":"classBTemperatureOffset"},"returnFlowTemperatureWeight":{"ID":1,"type":40,"name":"returnFlowTemperatureWeight"},"rawOutdoorTemperature":{"ID":2,"type":76,"name":"rawOutdoorTemperature"},"rawLocalTemperatureA":{"ID":3,"type":76,"name":"rawLocalTemperatureA"},"rawLocalTemperatureB":{"ID":4,"type":76,"name":"rawLocalTemperatureB"},"rawForwardFlowTemperature":{"ID":5,"type":76,"name":"rawForwardFlowTemperature"},"rawReturnFlowTemperature":{"ID":6,"type":76,"name":"rawReturnFlowTemperature"},"installedExtensions":{"ID":7,"type":31,"name":"installedExtensions"}},"manufacturerCode":4338,"name":"manuSpecificUbisysHeatingRegulatorThermostat","commands":{},"commandsResponse":{}},"Command":{"ID":6,"name":"configReport","parameters":[{"name":"direction","type":32},{"name":"attrId","type":33},{"name":"dataType","type":32,"conditions":[{"type":"directionEquals","value":0}]},{"name":"minRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"maxRepIntval","type":33,"conditions":[{"type":"directionEquals","value":0}]},{"name":"repChange","type":1000,"conditions":[{"type":"directionEquals","value":0},{"type":"dataTypeValueTypeEquals","value":"ANALOG"}]},{"name":"timeout","type":33,"conditions":[{"type":"directionEquals","value":1}]}],"response":7}}); + + await endpoint.configureReporting('hvacThermostat', [{ + attribute: 'localTemp', + minimumReportInterval: 1, + maximumReportInterval: 10, + reportableChange: 1, + }]) + + expect(endpoint.configuredReportings.length).toBe(2); + expect(endpoint.configuredReportings[0].attribute.name).toBe('classBTemperatureOffset'); + expect(endpoint.configuredReportings[0].cluster.name).toBe('manuSpecificUbisysHeatingRegulatorThermostat'); + expect(endpoint.configuredReportings[1].attribute.name).toBe('localTemp'); + expect(endpoint.configuredReportings[1].cluster.name).toBe('hvacThermostat'); }); it('Endpoint configure reporting for manufacturer specific attribute', async () => { @@ -2708,13 +2721,13 @@ describe('Controller', () => { minimumReportInterval: 1, maximumReportInterval: 10, reportableChange: 1, - }]) + }], {manufacturerCode: 0x1221}) const call = mocksendZclFrameToEndpoint.mock.calls[0]; expect(call[0]).toBe('0x129'); expect(call[1]).toBe(129); expect(call[2]).toBe(1) - expect({...deepClone(call[3]), Cluster: {}}).toStrictEqual({"Cluster":{},"Command":{"ID":6,"name":"configReport","parameters":[{"name":"direction","type":32},{"name":"attrId","type":33},{"conditions":[{"type":"directionEquals","value":0}],"name":"dataType","type":32},{"conditions":[{"type":"directionEquals","value":0}],"name":"minRepIntval","type":33},{"conditions":[{"type":"directionEquals","value":0}],"name":"maxRepIntval","type":33},{"conditions":[{"type":"directionEquals","value":0},{"type":"dataTypeValueTypeEquals","value":"ANALOG"}],"name":"repChange","type":1000},{"conditions":[{"type":"directionEquals","value":1}],"name":"timeout","type":33}],"response":7},"Header":{"commandIdentifier":6,"frameControl":{"direction":0,"disableDefaultResponse":true,"frameType":0,"manufacturerSpecific":false,"reservedBits":0},"manufacturerCode":null,"transactionSequenceNumber":11},"Payload":[{"attrId":16384,"dataType":48,"direction":0,"maxRepIntval":10,"minRepIntval":1,"repChange":1}]}); + expect({...deepClone(call[3]), Cluster: {}}).toStrictEqual({"Cluster":{},"Command":{"ID":6,"name":"configReport","parameters":[{"name":"direction","type":32},{"name":"attrId","type":33},{"conditions":[{"type":"directionEquals","value":0}],"name":"dataType","type":32},{"conditions":[{"type":"directionEquals","value":0}],"name":"minRepIntval","type":33},{"conditions":[{"type":"directionEquals","value":0}],"name":"maxRepIntval","type":33},{"conditions":[{"type":"directionEquals","value":0},{"type":"dataTypeValueTypeEquals","value":"ANALOG"}],"name":"repChange","type":1000},{"conditions":[{"type":"directionEquals","value":1}],"name":"timeout","type":33}],"response":7},"Header":{"commandIdentifier":6,"frameControl":{"direction":0,"disableDefaultResponse":true,"frameType":0,"manufacturerSpecific":true,"reservedBits":0},"manufacturerCode":4641,"transactionSequenceNumber":11},"Payload":[{"attrId":16384,"dataType":48,"direction":0,"maxRepIntval":10,"minRepIntval":1,"repChange":1}]}); expect(endpoint.configuredReportings.length).toBe(1); expect({...endpoint.configuredReportings[0], cluster: undefined}).toStrictEqual({"attribute":{"ID":16384,"type":48,"manufacturerCode":4641,"name":"viessmannWindowOpenInternal"},"minimumReportInterval":1,"maximumReportInterval":10,"reportableChange":1, "cluster": undefined});