Skip to content

Commit

Permalink
fix: Fix incorrect configured reporting cluster returned when cluster…
Browse files Browse the repository at this point in the history
… is manufacturer specific (#748)

* fix: Fix incorrect configured reporting cluster returned when cluster is manufacturer specific #717

* updates
  • Loading branch information
Koenkk authored Aug 24, 2023
1 parent 9856d83 commit bff9d4d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
7 changes: 5 additions & 2 deletions src/controller/model/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ interface ConfiguredReportingInternal {
minRepIntval: number,
maxRepIntval: number,
repChange: number,
manufacturerCode?: number | undefined,
}

interface ConfiguredReporting {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
}
Expand All @@ -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,
});
}
}
Expand Down
25 changes: 19 additions & 6 deletions test/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 () => {
Expand All @@ -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});
Expand Down

0 comments on commit bff9d4d

Please sign in to comment.