zigbee-herdsman 4.5.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  4. package/dist/controller/helpers/zclFrameConverter.js +2 -14
  5. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  6. package/dist/controller/model/device.js +3 -5
  7. package/dist/controller/model/device.js.map +1 -1
  8. package/dist/controller/model/endpoint.d.ts +1 -1
  9. package/dist/controller/model/endpoint.d.ts.map +1 -1
  10. package/dist/controller/model/endpoint.js +67 -43
  11. package/dist/controller/model/endpoint.js.map +1 -1
  12. package/dist/controller/model/group.d.ts.map +1 -1
  13. package/dist/controller/model/group.js +28 -17
  14. package/dist/controller/model/group.js.map +1 -1
  15. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  16. package/dist/zspec/zcl/buffaloZcl.js +5 -5
  17. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  18. package/dist/zspec/zcl/definition/tstype.d.ts +1 -2
  19. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  20. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  21. package/dist/zspec/zcl/utils.js +8 -30
  22. package/dist/zspec/zcl/utils.js.map +1 -1
  23. package/dist/zspec/zcl/zclFrame.d.ts +1 -1
  24. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  25. package/dist/zspec/zcl/zclFrame.js +8 -6
  26. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/controller/helpers/zclFrameConverter.ts +4 -12
  29. package/src/controller/model/device.ts +5 -5
  30. package/src/controller/model/endpoint.ts +86 -49
  31. package/src/controller/model/group.ts +33 -18
  32. package/src/zspec/zcl/buffaloZcl.ts +6 -4
  33. package/src/zspec/zcl/definition/tstype.ts +1 -2
  34. package/src/zspec/zcl/utils.ts +8 -35
  35. package/src/zspec/zcl/zclFrame.ts +10 -8
  36. package/test/controller.test.ts +352 -1360
  37. package/test/requests.bench.ts +5 -0
  38. package/test/zcl.test.ts +11 -15
  39. package/test/zspec/zcl/frame.test.ts +25 -25
  40. package/test/zspec/zcl/utils.test.ts +6 -14
@@ -107,6 +107,11 @@ const BASIC_RESP = Zcl.Frame.create(
107
107
  ).toBuffer();
108
108
 
109
109
  describe("Requests", () => {
110
+ beforeEach(() => {
111
+ sendZclFrameToEndpointResponse = undefined;
112
+ sendZdoResponse = undefined;
113
+ });
114
+
110
115
  bench(
111
116
  "device lqi",
112
117
  async () => {
package/test/zcl.test.ts CHANGED
@@ -20,8 +20,6 @@ describe("Zcl", () => {
20
20
  // @ts-expect-error testing
21
21
  delete cluster1.getCommand;
22
22
  // @ts-expect-error testing
23
- delete cluster1.hasAttribute;
24
- // @ts-expect-error testing
25
23
  delete cluster1.getCommandResponse;
26
24
  const cluster2 = Zcl.Utils.getCluster("genBasic", undefined, {});
27
25
  // @ts-expect-error testing
@@ -29,8 +27,6 @@ describe("Zcl", () => {
29
27
  // @ts-expect-error testing
30
28
  delete cluster2.getCommand;
31
29
  // @ts-expect-error testing
32
- delete cluster2.hasAttribute;
33
- // @ts-expect-error testing
34
30
  delete cluster2.getCommandResponse;
35
31
  expect(cluster1).toStrictEqual(cluster2);
36
32
  });
@@ -43,10 +39,10 @@ describe("Zcl", () => {
43
39
 
44
40
  it("Cluster has attribute", () => {
45
41
  const cluster = Zcl.Utils.getCluster(0, undefined, {});
46
- expect(cluster.hasAttribute("zclVersion")).toBeTruthy();
47
- expect(cluster.hasAttribute("NOTEXISTING")).toBeFalsy();
48
- expect(cluster.hasAttribute(0)).toBeTruthy();
49
- expect(cluster.hasAttribute(910293)).toBeFalsy();
42
+ expect(cluster.getAttribute("zclVersion")).not.toBeUndefined();
43
+ expect(cluster.getAttribute("NOTEXISTING")).toBeUndefined();
44
+ expect(cluster.getAttribute(0)).not.toBeUndefined();
45
+ expect(cluster.getAttribute(910293)).toBeUndefined();
50
46
  });
51
47
 
52
48
  it("Get specific command by name", () => {
@@ -1917,26 +1913,26 @@ describe("Zcl", () => {
1917
1913
 
1918
1914
  it("Zcl utils get cluster attributes manufacturerCode wrong", () => {
1919
1915
  const cluster = Zcl.Utils.getCluster("closuresWindowCovering", 123, {});
1920
- expect(() => cluster.getAttribute(0x1000)).toThrow("Cluster 'closuresWindowCovering' has no attribute '4096'");
1916
+ expect(cluster.getAttribute(0x1000)).toBeUndefined();
1921
1917
  });
1922
1918
 
1923
1919
  it("Zcl utils get command", () => {
1924
1920
  const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
1925
1921
  const command = cluster.getCommand(0);
1926
- expect(command.name).toEqual("off");
1927
- expect(cluster.getCommand("off")).toEqual(command);
1922
+ expect(command.name).toStrictEqual("off");
1923
+ expect(cluster.getCommand("off")).toStrictEqual(command);
1928
1924
  });
1929
1925
 
1930
1926
  it("Zcl utils get attribute", () => {
1931
1927
  const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
1932
- const command = cluster.getAttribute(16385);
1933
- expect(command.name).toEqual("onTime");
1934
- expect(cluster.getAttribute("onTime")).toEqual(command);
1928
+ const attribute = cluster.getAttribute(16385);
1929
+ expect(attribute?.name).toStrictEqual("onTime");
1930
+ expect(cluster.getAttribute("onTime")).toStrictEqual(attribute);
1935
1931
  });
1936
1932
 
1937
1933
  it("Zcl utils get attribute non-existing", () => {
1938
1934
  const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
1939
- expect(() => cluster.getAttribute("notExisting")).toThrow("Cluster 'genOnOff' has no attribute 'notExisting'");
1935
+ expect(cluster.getAttribute("notExisting")).toBeUndefined();
1940
1936
  });
1941
1937
 
1942
1938
  it("Zcl utils get command non-existing", () => {
@@ -280,13 +280,13 @@ const MANUF_SPE_FRAME_STRING = `{"header":{"frameControl":{"reservedBits":0,"fra
280
280
  describe("ZCL Frame", () => {
281
281
  describe("Validates Parameter Condition", () => {
282
282
  it("STATUS_EQUAL", () => {
283
- expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 0}, null)).toBeTruthy();
284
- expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 1}, null)).toBeFalsy();
283
+ expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 0}, undefined)).toBeTruthy();
284
+ expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 1}, undefined)).toBeFalsy();
285
285
  });
286
286
 
287
287
  it("STATUS_NOT_EQUAL", () => {
288
- expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 1}, null)).toBeTruthy();
289
- expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 0}, null)).toBeFalsy();
288
+ expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 1}, undefined)).toBeTruthy();
289
+ expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 0}, undefined)).toBeFalsy();
290
290
  });
291
291
 
292
292
  it("MINIMUM_REMAINING_BUFFER_BYTES", () => {
@@ -296,34 +296,34 @@ describe("ZCL Frame", () => {
296
296
 
297
297
  it("DIRECTION_EQUAL", () => {
298
298
  expect(
299
- Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.CLIENT_TO_SERVER}, null),
299
+ Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.CLIENT_TO_SERVER}, undefined),
300
300
  ).toBeTruthy();
301
301
  expect(
302
- Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.SERVER_TO_CLIENT}, null),
302
+ Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.SERVER_TO_CLIENT}, undefined),
303
303
  ).toBeFalsy();
304
304
  expect(
305
- Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.SERVER_TO_CLIENT}, null),
305
+ Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.SERVER_TO_CLIENT}, undefined),
306
306
  ).toBeTruthy();
307
307
  expect(
308
- Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.CLIENT_TO_SERVER}, null),
308
+ Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.CLIENT_TO_SERVER}, undefined),
309
309
  ).toBeFalsy();
310
310
  });
311
311
 
312
312
  it("BITMASK_SET", () => {
313
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4000}, null)).toBeTruthy();
314
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4150}, null)).toBeTruthy();
315
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x0400}, null)).toBeFalsy();
316
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x1400}, null)).toBeFalsy();
313
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4000}, undefined)).toBeTruthy();
314
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4150}, undefined)).toBeTruthy();
315
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x0400}, undefined)).toBeFalsy();
316
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x1400}, undefined)).toBeFalsy();
317
317
  });
318
318
 
319
319
  it("BITFIELD_ENUM", () => {
320
320
  // {param:'options', offset: 0, size: 3, value: 0b000}
321
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b000}, null)).toBeTruthy();
322
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1000}, null)).toBeTruthy();
323
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b001}, null)).toBeFalsy();
324
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b011}, null)).toBeFalsy();
325
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b100}, null)).toBeFalsy();
326
- expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1010}, null)).toBeFalsy();
321
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b000}, undefined)).toBeTruthy();
322
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1000}, undefined)).toBeTruthy();
323
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b001}, undefined)).toBeFalsy();
324
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b011}, undefined)).toBeFalsy();
325
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b100}, undefined)).toBeFalsy();
326
+ expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1010}, undefined)).toBeFalsy();
327
327
  });
328
328
 
329
329
  it("multiple including DATA_TYPE_CLASS_EQUAL", () => {
@@ -331,41 +331,41 @@ describe("ZCL Frame", () => {
331
331
  Zcl.Frame.conditionsValid(
332
332
  Zcl.Foundation.configReport.parameters[5],
333
333
  {direction: Zcl.Direction.CLIENT_TO_SERVER, dataType: Zcl.DataType.UINT8},
334
- null,
334
+ undefined,
335
335
  ),
336
336
  ).toBeTruthy();
337
337
  expect(
338
338
  Zcl.Frame.conditionsValid(
339
339
  Zcl.Foundation.configReport.parameters[5],
340
340
  {direction: Zcl.Direction.CLIENT_TO_SERVER, dataType: Zcl.DataType.DATA8},
341
- null,
341
+ undefined,
342
342
  ),
343
343
  ).toBeFalsy();
344
344
  expect(
345
345
  Zcl.Frame.conditionsValid(
346
346
  Zcl.Foundation.configReport.parameters[5],
347
347
  {direction: Zcl.Direction.SERVER_TO_CLIENT, dataType: Zcl.DataType.UINT8},
348
- null,
348
+ undefined,
349
349
  ),
350
350
  ).toBeFalsy();
351
351
  expect(
352
352
  Zcl.Frame.conditionsValid(
353
353
  Zcl.Foundation.configReport.parameters[5],
354
354
  {direction: Zcl.Direction.SERVER_TO_CLIENT, dataType: Zcl.DataType.DATA8},
355
- null,
355
+ undefined,
356
356
  ),
357
357
  ).toBeFalsy();
358
358
  });
359
359
 
360
360
  it("FIELD_EQUAL", () => {
361
361
  expect(
362
- Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 1}, null),
362
+ Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 1}, undefined),
363
363
  ).toBeTruthy();
364
364
  expect(
365
- Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 0}, null),
365
+ Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 0}, undefined),
366
366
  ).toBeFalsy();
367
367
  expect(
368
- Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 3}, null),
368
+ Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 3}, undefined),
369
369
  ).toBeFalsy();
370
370
  });
371
371
  });
@@ -116,7 +116,6 @@ describe("ZCL Utils", () => {
116
116
  expect(cluster.getAttribute).toBeInstanceOf(Function);
117
117
  expect(cluster.getCommand).toBeInstanceOf(Function);
118
118
  expect(cluster.getCommandResponse).toBeInstanceOf(Function);
119
- expect(cluster.hasAttribute).toBeInstanceOf(Function);
120
119
  });
121
120
 
122
121
  it("Creates empty cluster when getting by invalid ID", () => {
@@ -130,7 +129,6 @@ describe("ZCL Utils", () => {
130
129
  expect(cluster.getAttribute).toBeInstanceOf(Function);
131
130
  expect(cluster.getCommand).toBeInstanceOf(Function);
132
131
  expect(cluster.getCommandResponse).toBeInstanceOf(Function);
133
- expect(cluster.hasAttribute).toBeInstanceOf(Function);
134
132
  });
135
133
 
136
134
  it("Throws when getting invalid cluster name", () => {
@@ -173,25 +171,19 @@ describe("ZCL Utils", () => {
173
171
  ])("Gets and checks cluster attribute %s", (_name, payload, expected) => {
174
172
  const cluster = Zcl.Utils.getCluster(expected.cluster.ID, payload.manufacturerCode, payload.customClusters);
175
173
  const attribute = cluster.getAttribute(payload.key);
176
- expect(cluster.hasAttribute(payload.key)).toBeTruthy();
174
+ expect(attribute).not.toBeUndefined();
177
175
  expect(attribute).toStrictEqual(cluster.attributes[expected.name]);
178
176
  });
179
177
 
180
- it("Throws when getting invalid attribute", () => {
178
+ it("Returns undefined when getting invalid attribute", () => {
181
179
  const cluster = Zcl.Utils.getCluster(Zcl.Clusters.genAlarms.ID, undefined, {});
182
- expect(() => {
183
- cluster.getAttribute("abcd");
184
- }).toThrow();
185
- expect(() => {
186
- cluster.getAttribute(99999);
187
- }).toThrow();
180
+ expect(cluster.getAttribute("abcd")).toBeUndefined();
181
+ expect(cluster.getAttribute(99999)).toBeUndefined();
188
182
  });
189
183
 
190
- it("Throws when getting attribute with invalid manufacturer code", () => {
184
+ it("Returns undefined when getting attribute with invalid manufacturer code", () => {
191
185
  const cluster = Zcl.Utils.getCluster(Zcl.Clusters.haDiagnostic.ID, 123, {});
192
- expect(() => {
193
- cluster.getAttribute(Zcl.Clusters.haDiagnostic.attributes.danfossSystemStatusCode.ID);
194
- }).toThrow();
186
+ expect(cluster.getAttribute(Zcl.Clusters.haDiagnostic.attributes.danfossSystemStatusCode.ID)).toBeUndefined();
195
187
  });
196
188
 
197
189
  it.each([