@willieee802/zigbee-herdsman 0.49.3 → 0.50.0

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 (211) hide show
  1. package/.github/dependabot.yml +0 -3
  2. package/.github/workflows/ci.yml +1 -2
  3. package/.github/workflows/release-please.yml +1 -1
  4. package/.github/workflows/typedoc.yaml +3 -3
  5. package/.release-please-manifest.json +1 -1
  6. package/CHANGELOG.md +143 -0
  7. package/biome.json +1 -1
  8. package/dist/adapter/adapter.d.ts +14 -1
  9. package/dist/adapter/adapter.d.ts.map +1 -1
  10. package/dist/adapter/adapter.js +17 -0
  11. package/dist/adapter/adapter.js.map +1 -1
  12. package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
  13. package/dist/adapter/adapterDiscovery.js.map +1 -1
  14. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
  15. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  16. package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
  17. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  18. package/dist/adapter/deconz/driver/constants.d.ts +1 -1
  19. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  20. package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
  21. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  22. package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
  23. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  24. package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
  25. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
  26. package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
  27. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
  28. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
  29. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  30. package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
  31. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  32. package/dist/adapter/ezsp/driver/index.d.ts +1 -1
  33. package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
  34. package/dist/adapter/ezsp/driver/index.js +1 -1
  35. package/dist/adapter/ezsp/driver/index.js.map +1 -1
  36. package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
  37. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  38. package/dist/adapter/ezsp/driver/types/index.js +3 -3
  39. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  40. package/dist/adapter/serialPort.d.ts.map +1 -1
  41. package/dist/adapter/serialPort.js +7 -0
  42. package/dist/adapter/serialPort.js.map +1 -1
  43. package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
  44. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
  45. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
  46. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
  47. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  48. package/dist/adapter/z-stack/adapter/manager.js +12 -2
  49. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  50. package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
  51. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
  52. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  53. package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
  54. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  55. package/dist/adapter/z-stack/constants/index.d.ts +1 -1
  56. package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
  57. package/dist/adapter/z-stack/constants/index.js +1 -1
  58. package/dist/adapter/z-stack/constants/index.js.map +1 -1
  59. package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
  60. package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
  61. package/dist/adapter/z-stack/unpi/constants.js +1 -1
  62. package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
  63. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
  64. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  65. package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
  66. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  67. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  68. package/dist/adapter/zboss/driver.js +8 -1
  69. package/dist/adapter/zboss/driver.js.map +1 -1
  70. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  71. package/dist/adapter/zboss/uart.js +14 -2
  72. package/dist/adapter/zboss/uart.js.map +1 -1
  73. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
  74. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  75. package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
  76. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  77. package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
  78. package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
  79. package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
  80. package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
  81. package/dist/controller/controller.d.ts.map +1 -1
  82. package/dist/controller/controller.js +10 -2
  83. package/dist/controller/controller.js.map +1 -1
  84. package/dist/controller/greenPower.d.ts.map +1 -1
  85. package/dist/controller/greenPower.js +15 -9
  86. package/dist/controller/greenPower.js.map +1 -1
  87. package/dist/controller/helpers/ota.d.ts +4 -4
  88. package/dist/controller/helpers/ota.d.ts.map +1 -1
  89. package/dist/controller/helpers/ota.js +28 -9
  90. package/dist/controller/helpers/ota.js.map +1 -1
  91. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  92. package/dist/controller/helpers/zclFrameConverter.js +17 -16
  93. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  94. package/dist/controller/model/device.d.ts +14 -4
  95. package/dist/controller/model/device.d.ts.map +1 -1
  96. package/dist/controller/model/device.js +167 -85
  97. package/dist/controller/model/device.js.map +1 -1
  98. package/dist/controller/model/endpoint.d.ts +7 -3
  99. package/dist/controller/model/endpoint.d.ts.map +1 -1
  100. package/dist/controller/model/endpoint.js +34 -21
  101. package/dist/controller/model/endpoint.js.map +1 -1
  102. package/dist/controller/model/group.d.ts +0 -1
  103. package/dist/controller/model/group.d.ts.map +1 -1
  104. package/dist/controller/model/group.js +14 -19
  105. package/dist/controller/model/group.js.map +1 -1
  106. package/dist/controller/touchlink.js +3 -3
  107. package/dist/controller/touchlink.js.map +1 -1
  108. package/dist/utils/timeService.js +2 -2
  109. package/dist/utils/timeService.js.map +1 -1
  110. package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
  111. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  112. package/dist/zspec/zcl/buffaloZcl.js +198 -96
  113. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  114. package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
  115. package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
  116. package/dist/zspec/zcl/definition/cluster.js +2699 -2808
  117. package/dist/zspec/zcl/definition/cluster.js.map +1 -1
  118. package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
  119. package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
  120. package/dist/zspec/zcl/definition/enums.d.ts +0 -1
  121. package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
  122. package/dist/zspec/zcl/definition/enums.js +0 -1
  123. package/dist/zspec/zcl/definition/enums.js.map +1 -1
  124. package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
  125. package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
  126. package/dist/zspec/zcl/definition/foundation.js +552 -207
  127. package/dist/zspec/zcl/definition/foundation.js.map +1 -1
  128. package/dist/zspec/zcl/definition/status.d.ts +21 -10
  129. package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
  130. package/dist/zspec/zcl/definition/status.js +11 -0
  131. package/dist/zspec/zcl/definition/status.js.map +1 -1
  132. package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
  133. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  134. package/dist/zspec/zcl/utils.d.ts +7 -4
  135. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  136. package/dist/zspec/zcl/utils.js +133 -240
  137. package/dist/zspec/zcl/utils.js.map +1 -1
  138. package/dist/zspec/zcl/zclFrame.d.ts +4 -4
  139. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  140. package/dist/zspec/zcl/zclFrame.js +19 -103
  141. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  142. package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
  143. package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
  144. package/dist/zspec/zcl/zclStatusError.js +2 -2
  145. package/dist/zspec/zcl/zclStatusError.js.map +1 -1
  146. package/package.json +1 -1
  147. package/scripts/clusters-typegen.ts +44 -139
  148. package/src/adapter/adapter.ts +38 -3
  149. package/src/adapter/adapterDiscovery.ts +2 -1
  150. package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
  151. package/src/adapter/deconz/driver/constants.ts +1 -1
  152. package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
  153. package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
  154. package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
  155. package/src/adapter/ezsp/driver/index.ts +1 -1
  156. package/src/adapter/ezsp/driver/types/index.ts +99 -99
  157. package/src/adapter/serialPort.ts +9 -0
  158. package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
  159. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
  160. package/src/adapter/z-stack/adapter/manager.ts +16 -2
  161. package/src/adapter/z-stack/adapter/tstype.ts +1 -0
  162. package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
  163. package/src/adapter/z-stack/constants/index.ts +1 -1
  164. package/src/adapter/z-stack/unpi/constants.ts +1 -1
  165. package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
  166. package/src/adapter/zboss/driver.ts +8 -1
  167. package/src/adapter/zboss/uart.ts +14 -1
  168. package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
  169. package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
  170. package/src/controller/controller.ts +12 -2
  171. package/src/controller/greenPower.ts +16 -9
  172. package/src/controller/helpers/ota.ts +37 -11
  173. package/src/controller/helpers/zclFrameConverter.ts +20 -17
  174. package/src/controller/model/device.ts +204 -97
  175. package/src/controller/model/endpoint.ts +36 -24
  176. package/src/controller/model/group.ts +14 -20
  177. package/src/controller/touchlink.ts +3 -3
  178. package/src/utils/timeService.ts +2 -2
  179. package/src/zspec/zcl/buffaloZcl.ts +226 -100
  180. package/src/zspec/zcl/definition/cluster.ts +2713 -2822
  181. package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
  182. package/src/zspec/zcl/definition/enums.ts +0 -1
  183. package/src/zspec/zcl/definition/foundation.ts +703 -216
  184. package/src/zspec/zcl/definition/status.ts +22 -11
  185. package/src/zspec/zcl/definition/tstype.ts +59 -58
  186. package/src/zspec/zcl/utils.ts +137 -264
  187. package/src/zspec/zcl/zclFrame.ts +25 -130
  188. package/src/zspec/zcl/zclStatusError.ts +2 -2
  189. package/test/adapter/ember/emberAdapter.test.ts +191 -4
  190. package/test/adapter/ezsp/uart.test.ts +10 -10
  191. package/test/adapter/z-stack/adapter.test.ts +88 -32
  192. package/test/adapter/zoh/zohAdapter.test.ts +4 -4
  193. package/test/controller.test.ts +822 -248
  194. package/test/device-ota.test.ts +141 -16
  195. package/test/device.test.ts +731 -0
  196. package/test/requests.bench.ts +2 -0
  197. package/test/zcl.test.ts +70 -95
  198. package/test/zspec/zcl/buffalo.test.ts +251 -11
  199. package/test/zspec/zcl/foundation.test.ts +990 -0
  200. package/test/zspec/zcl/frame.test.ts +84 -69
  201. package/test/zspec/zcl/utils.test.ts +105 -81
  202. package/tsconfig.json +0 -1
  203. package/scripts/check-clusters-changes.ts +0 -328
  204. package/scripts/clusters-changes.log +0 -584
  205. package/scripts/utils.ts +0 -88
  206. package/scripts/zap-update-clusters-report.json +0 -303
  207. package/scripts/zap-update-clusters.ts +0 -1520
  208. package/scripts/zap-update-types.ts +0 -707
  209. package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
  210. package/scripts/zap-xml-clusters-overrides.ts +0 -400
  211. package/scripts/zap-xml-types.ts +0 -146
@@ -0,0 +1,990 @@
1
+ import {describe, expect, it} from "vitest";
2
+ import * as Zcl from "../../../src/zspec/zcl";
3
+
4
+ describe("Foundation", () => {
5
+ it.each([
6
+ ["read", {a: 1}],
7
+ ["readRsp", {a: 1}],
8
+ ["write", {a: 1}],
9
+ ["writeUndiv", {a: 1}],
10
+ ["writeRsp", {a: 1}],
11
+ ["writeNoRsp", {a: 1}],
12
+ ["configReport", {a: 1}],
13
+ ["configReportRsp", {a: 1}],
14
+ ["readReportConfig", {a: 1}],
15
+ ["readReportConfigRsp", {a: 1}],
16
+ ["report", {a: 1}],
17
+ ["defaultRsp", [{a: 1}]],
18
+ ["discover", [{a: 1}]],
19
+ ["discoverRsp", [{a: 1}]],
20
+ ["readStructured", {a: 1}],
21
+ ["writeStructured", {a: 1}],
22
+ ["writeStructuredRsp", {a: 1}],
23
+ ["discoverCommands", [{a: 1}]],
24
+ ["discoverCommandsRsp", [{a: 1}]],
25
+ ["discoverCommandsGen", [{a: 1}]],
26
+ ["discoverCommandsGenRsp", [{a: 1}]],
27
+ ["discoverExt", [{a: 1}]],
28
+ ["discoverExtRsp", [{a: 1}]],
29
+ ])("throws on invalid payload type when writing %s", (cmd, payload) => {
30
+ const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 10, cmd, "genBasic", payload, {});
31
+
32
+ expect(() => {
33
+ frame.toBuffer();
34
+ }).toThrow(new Zcl.StatusError(Zcl.Status.MALFORMED_COMMAND));
35
+ });
36
+
37
+ describe("read", () => {
38
+ const READ_REQ_FRAME = Zcl.Frame.create(
39
+ Zcl.FrameType.GLOBAL,
40
+ Zcl.Direction.CLIENT_TO_SERVER,
41
+ true,
42
+ undefined,
43
+ 10,
44
+ "read",
45
+ "genBasic",
46
+ [{attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID}, {attrId: Zcl.Clusters.genBasic.attributes.modelId.ID}],
47
+ {},
48
+ );
49
+
50
+ it("parses & writes", () => {
51
+ const rawFrame = READ_REQ_FRAME.toBuffer();
52
+
53
+ expect(rawFrame).toStrictEqual(Buffer.from([0x10, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00]));
54
+
55
+ const frame = Zcl.Frame.fromBuffer(READ_REQ_FRAME.cluster.ID, READ_REQ_FRAME.header, rawFrame, {});
56
+
57
+ expect(frame).toMatchObject({
58
+ header: READ_REQ_FRAME.header,
59
+ payload: READ_REQ_FRAME.payload,
60
+ cluster: {name: "genBasic"},
61
+ });
62
+ });
63
+ });
64
+
65
+ describe("readRsp", () => {
66
+ const READ_RSP_FRAME = Zcl.Frame.create(
67
+ Zcl.FrameType.GLOBAL,
68
+ Zcl.Direction.SERVER_TO_CLIENT,
69
+ true,
70
+ undefined,
71
+ 10,
72
+ "readRsp",
73
+ "genBasic",
74
+ [
75
+ {
76
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
77
+ status: Zcl.Status.SUCCESS,
78
+ dataType: Zcl.Clusters.genBasic.attributes.zclVersion.type,
79
+ attrData: 8,
80
+ },
81
+ {
82
+ attrId: Zcl.Clusters.genBasic.attributes.manufacturerName.ID,
83
+ status: Zcl.Status.SUCCESS,
84
+ dataType: Zcl.Clusters.genBasic.attributes.manufacturerName.type,
85
+ attrData: "efgh",
86
+ },
87
+ ],
88
+ {},
89
+ );
90
+
91
+ it("parses & writes", () => {
92
+ const rawFrame = READ_RSP_FRAME.toBuffer();
93
+
94
+ expect(rawFrame).toStrictEqual(
95
+ Buffer.from([0x18, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x20, 0x08, 0x04, 0x00, 0x00, 0x42, 0x04, 0x65, 0x66, 0x67, 0x68]),
96
+ );
97
+
98
+ const frame = Zcl.Frame.fromBuffer(READ_RSP_FRAME.cluster.ID, READ_RSP_FRAME.header, rawFrame, {});
99
+
100
+ expect(frame).toMatchObject({
101
+ header: READ_RSP_FRAME.header,
102
+ payload: READ_RSP_FRAME.payload,
103
+ cluster: {name: "genBasic"},
104
+ });
105
+ });
106
+
107
+ it("[WORKAROUND] parses CHAR_STR as MI_STRUCT for attribute 0xff01", () => {
108
+ const rawFrame = Buffer.from([
109
+ 0x18, 0x0a, 0x01, 0x01, 0xff, 0x00, 0x42, 34, 1, 33, 213, 12, 3, 40, 33, 4, 33, 168, 19, 5, 33, 43, 0, 6, 36, 0, 0, 5, 0, 0, 8, 33, 4,
110
+ 2, 10, 33, 0, 0, 100, 16, 0,
111
+ ]);
112
+
113
+ const frame = Zcl.Frame.fromBuffer(0x0000, Zcl.Header.fromBuffer(rawFrame), rawFrame, {});
114
+
115
+ expect(frame).toMatchObject({
116
+ payload: [
117
+ {
118
+ attrId: 0xff01,
119
+ status: Zcl.Status.SUCCESS,
120
+ dataType: Zcl.DataType.CHAR_STR,
121
+ attrData: {"1": 3285, "3": 33, "4": 5032, "5": 43, "6": 327680, "8": 516, "10": 0, "100": 0},
122
+ },
123
+ ],
124
+ cluster: {name: "genBasic"},
125
+ });
126
+ });
127
+ });
128
+
129
+ describe("write", () => {
130
+ const WRITE_FRAME = Zcl.Frame.create(
131
+ Zcl.FrameType.GLOBAL,
132
+ Zcl.Direction.SERVER_TO_CLIENT,
133
+ true,
134
+ undefined,
135
+ 10,
136
+ "write",
137
+ "genOnOff",
138
+ [
139
+ {attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.onTime.type, attrData: 8},
140
+ {attrId: Zcl.Clusters.genOnOff.attributes.offWaitTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.offWaitTime.type, attrData: 4},
141
+ ],
142
+ {},
143
+ );
144
+
145
+ it("parses & writes", () => {
146
+ const rawFrame = WRITE_FRAME.toBuffer();
147
+
148
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x02, 0x01, 0x40, 0x21, 0x08, 0x00, 0x02, 0x40, 0x21, 0x04, 0x00]));
149
+
150
+ const frame = Zcl.Frame.fromBuffer(WRITE_FRAME.cluster.ID, WRITE_FRAME.header, rawFrame, {});
151
+
152
+ expect(frame).toMatchObject({
153
+ header: WRITE_FRAME.header,
154
+ payload: WRITE_FRAME.payload,
155
+ cluster: {name: "genOnOff"},
156
+ });
157
+ });
158
+ });
159
+
160
+ describe("writeUndiv", () => {
161
+ const WRITE_UNDIV_FRAME = Zcl.Frame.create(
162
+ Zcl.FrameType.GLOBAL,
163
+ Zcl.Direction.SERVER_TO_CLIENT,
164
+ true,
165
+ undefined,
166
+ 10,
167
+ "writeUndiv",
168
+ "genOnOff",
169
+ [
170
+ {attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.onTime.type, attrData: 8},
171
+ {attrId: Zcl.Clusters.genOnOff.attributes.offWaitTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.offWaitTime.type, attrData: 4},
172
+ ],
173
+ {},
174
+ );
175
+
176
+ it("parses & writes", () => {
177
+ const rawFrame = WRITE_UNDIV_FRAME.toBuffer();
178
+
179
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x03, 0x01, 0x40, 0x21, 0x08, 0x00, 0x02, 0x40, 0x21, 0x04, 0x00]));
180
+
181
+ const frame = Zcl.Frame.fromBuffer(WRITE_UNDIV_FRAME.cluster.ID, WRITE_UNDIV_FRAME.header, rawFrame, {});
182
+
183
+ expect(frame).toMatchObject({
184
+ header: WRITE_UNDIV_FRAME.header,
185
+ payload: WRITE_UNDIV_FRAME.payload,
186
+ cluster: {name: "genOnOff"},
187
+ });
188
+ });
189
+ });
190
+
191
+ describe("writeRsp", () => {
192
+ const WRITE_RSP_FRAME = Zcl.Frame.create(
193
+ Zcl.FrameType.GLOBAL,
194
+ Zcl.Direction.SERVER_TO_CLIENT,
195
+ true,
196
+ undefined,
197
+ 10,
198
+ "writeRsp",
199
+ "genOnOff",
200
+ [
201
+ {status: Zcl.Status.UNSUPPORTED_ATTRIBUTE, attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID},
202
+ {status: Zcl.Status.NOT_AUTHORIZED, attrId: Zcl.Clusters.genOnOff.attributes.offWaitTime.ID},
203
+ ],
204
+ {},
205
+ );
206
+
207
+ it("parses & writes", () => {
208
+ const rawFrame = WRITE_RSP_FRAME.toBuffer();
209
+
210
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x04, 0x86, 0x01, 0x40, 0x7e, 0x02, 0x40]));
211
+
212
+ const frame = Zcl.Frame.fromBuffer(WRITE_RSP_FRAME.cluster.ID, WRITE_RSP_FRAME.header, rawFrame, {});
213
+
214
+ expect(frame).toMatchObject({
215
+ header: WRITE_RSP_FRAME.header,
216
+ payload: WRITE_RSP_FRAME.payload,
217
+ cluster: {name: "genOnOff"},
218
+ });
219
+ });
220
+
221
+ it("handles SUCCESS payload", () => {
222
+ const WRITE_RSP_SUCCESS_FRAME = Zcl.Frame.create(
223
+ Zcl.FrameType.GLOBAL,
224
+ Zcl.Direction.SERVER_TO_CLIENT,
225
+ true,
226
+ undefined,
227
+ 10,
228
+ "writeRsp",
229
+ "genOnOff",
230
+ [{status: Zcl.Status.SUCCESS}],
231
+ {},
232
+ );
233
+ const rawFrame = WRITE_RSP_SUCCESS_FRAME.toBuffer();
234
+
235
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x04, 0x00]));
236
+
237
+ const frame = Zcl.Frame.fromBuffer(WRITE_RSP_SUCCESS_FRAME.cluster.ID, WRITE_RSP_SUCCESS_FRAME.header, rawFrame, {});
238
+
239
+ expect(frame).toMatchObject({
240
+ header: WRITE_RSP_SUCCESS_FRAME.header,
241
+ payload: WRITE_RSP_SUCCESS_FRAME.payload,
242
+ cluster: {name: "genOnOff"},
243
+ });
244
+ });
245
+ });
246
+
247
+ describe("writeNoRsp", () => {
248
+ const WRITE_NO_RSP_FRAME = Zcl.Frame.create(
249
+ Zcl.FrameType.GLOBAL,
250
+ Zcl.Direction.SERVER_TO_CLIENT,
251
+ true,
252
+ undefined,
253
+ 10,
254
+ "writeNoRsp",
255
+ "genOnOff",
256
+ [
257
+ {attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.onTime.type, attrData: 8},
258
+ {attrId: Zcl.Clusters.genOnOff.attributes.offWaitTime.ID, dataType: Zcl.Clusters.genOnOff.attributes.offWaitTime.type, attrData: 4},
259
+ ],
260
+ {},
261
+ );
262
+
263
+ it("parses & writes", () => {
264
+ const rawFrame = WRITE_NO_RSP_FRAME.toBuffer();
265
+
266
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x05, 0x01, 0x40, 0x21, 0x08, 0x00, 0x02, 0x40, 0x21, 0x04, 0x00]));
267
+
268
+ const frame = Zcl.Frame.fromBuffer(WRITE_NO_RSP_FRAME.cluster.ID, WRITE_NO_RSP_FRAME.header, rawFrame, {});
269
+
270
+ expect(frame).toMatchObject({
271
+ header: WRITE_NO_RSP_FRAME.header,
272
+ payload: WRITE_NO_RSP_FRAME.payload,
273
+ cluster: {name: "genOnOff"},
274
+ });
275
+ });
276
+ });
277
+
278
+ describe("configReport", () => {
279
+ const CONFIG_REPORT_FRAME = Zcl.Frame.create(
280
+ Zcl.FrameType.GLOBAL,
281
+ Zcl.Direction.SERVER_TO_CLIENT,
282
+ true,
283
+ undefined,
284
+ 10,
285
+ "configReport",
286
+ "genOnOff",
287
+ [
288
+ {
289
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
290
+ attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID,
291
+ dataType: Zcl.Clusters.genOnOff.attributes.onTime.type,
292
+ minRepIntval: 300,
293
+ maxRepIntval: 4000,
294
+ repChange: 3,
295
+ },
296
+ {
297
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
298
+ attrId: Zcl.Clusters.genOnOff.attributes.onOff.ID,
299
+ dataType: Zcl.Clusters.genOnOff.attributes.onOff.type,
300
+ minRepIntval: 250,
301
+ maxRepIntval: 5290,
302
+ },
303
+ {
304
+ direction: Zcl.Direction.SERVER_TO_CLIENT,
305
+ attrId: Zcl.Clusters.genOnOff.attributes.startUpOnOff.ID,
306
+ timeout: 3000,
307
+ },
308
+ ],
309
+ {},
310
+ );
311
+
312
+ it("parses & writes", () => {
313
+ const rawFrame = CONFIG_REPORT_FRAME.toBuffer();
314
+
315
+ expect(rawFrame).toStrictEqual(
316
+ Buffer.from([
317
+ 0x18, 0x0a, 0x06, 0x00, 0x01, 0x40, 0x21, 0x2c, 0x01, 0xa0, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfa, 0x00, 0xaa, 0x14,
318
+ 0x01, 0x03, 0x40, 0xb8, 0x0b,
319
+ ]),
320
+ );
321
+
322
+ const frame = Zcl.Frame.fromBuffer(CONFIG_REPORT_FRAME.cluster.ID, CONFIG_REPORT_FRAME.header, rawFrame, {});
323
+
324
+ expect(frame).toMatchObject({
325
+ header: CONFIG_REPORT_FRAME.header,
326
+ payload: CONFIG_REPORT_FRAME.payload,
327
+ cluster: {name: "genOnOff"},
328
+ });
329
+ });
330
+ });
331
+
332
+ describe("configReportRsp", () => {
333
+ const CONFIG_REPORT_RSP_FRAME = Zcl.Frame.create(
334
+ Zcl.FrameType.GLOBAL,
335
+ Zcl.Direction.SERVER_TO_CLIENT,
336
+ true,
337
+ undefined,
338
+ 10,
339
+ "configReportRsp",
340
+ "genOnOff",
341
+ [
342
+ {
343
+ status: Zcl.Status.UNSUPPORTED_ATTRIBUTE,
344
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
345
+ attrId: Zcl.Clusters.genOnOff.attributes.onTime.ID,
346
+ },
347
+ {
348
+ status: Zcl.Status.NOT_AUTHORIZED,
349
+ direction: Zcl.Direction.SERVER_TO_CLIENT,
350
+ attrId: Zcl.Clusters.genOnOff.attributes.offWaitTime.ID,
351
+ },
352
+ ],
353
+ {},
354
+ );
355
+
356
+ it("parses & writes", () => {
357
+ const rawFrame = CONFIG_REPORT_RSP_FRAME.toBuffer();
358
+
359
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x07, 0x86, 0x00, 0x01, 0x40, 0x7e, 0x01, 0x02, 0x40]));
360
+
361
+ const frame = Zcl.Frame.fromBuffer(CONFIG_REPORT_RSP_FRAME.cluster.ID, CONFIG_REPORT_RSP_FRAME.header, rawFrame, {});
362
+
363
+ expect(frame).toMatchObject({
364
+ header: CONFIG_REPORT_RSP_FRAME.header,
365
+ payload: CONFIG_REPORT_RSP_FRAME.payload,
366
+ cluster: {name: "genOnOff"},
367
+ });
368
+ });
369
+
370
+ it("handles SUCCESS payload", () => {
371
+ const CONFIG_REPORT_RSP_SUCCESS_FRAME = Zcl.Frame.create(
372
+ Zcl.FrameType.GLOBAL,
373
+ Zcl.Direction.SERVER_TO_CLIENT,
374
+ true,
375
+ undefined,
376
+ 10,
377
+ "configReportRsp",
378
+ "genOnOff",
379
+ [{status: Zcl.Status.SUCCESS}],
380
+ {},
381
+ );
382
+ const rawFrame = CONFIG_REPORT_RSP_SUCCESS_FRAME.toBuffer();
383
+
384
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x07, 0x00]));
385
+
386
+ const frame = Zcl.Frame.fromBuffer(CONFIG_REPORT_RSP_SUCCESS_FRAME.cluster.ID, CONFIG_REPORT_RSP_SUCCESS_FRAME.header, rawFrame, {});
387
+
388
+ expect(frame).toMatchObject({
389
+ header: CONFIG_REPORT_RSP_SUCCESS_FRAME.header,
390
+ payload: CONFIG_REPORT_RSP_SUCCESS_FRAME.payload,
391
+ cluster: {name: "genOnOff"},
392
+ });
393
+ });
394
+ });
395
+
396
+ describe("readReportConfig", () => {
397
+ const READ_REPORT_CONFIG_FRAME = Zcl.Frame.create(
398
+ Zcl.FrameType.GLOBAL,
399
+ Zcl.Direction.CLIENT_TO_SERVER,
400
+ true,
401
+ undefined,
402
+ 10,
403
+ "readReportConfig",
404
+ "genBasic",
405
+ [
406
+ {direction: Zcl.Direction.CLIENT_TO_SERVER, attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID},
407
+ {direction: Zcl.Direction.SERVER_TO_CLIENT, attrId: Zcl.Clusters.genBasic.attributes.modelId.ID},
408
+ ],
409
+ {},
410
+ );
411
+
412
+ it("parses & writes", () => {
413
+ const rawFrame = READ_REPORT_CONFIG_FRAME.toBuffer();
414
+
415
+ expect(rawFrame).toStrictEqual(Buffer.from([0x10, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00]));
416
+
417
+ const frame = Zcl.Frame.fromBuffer(READ_REPORT_CONFIG_FRAME.cluster.ID, READ_REPORT_CONFIG_FRAME.header, rawFrame, {});
418
+
419
+ expect(frame).toMatchObject({
420
+ header: READ_REPORT_CONFIG_FRAME.header,
421
+ payload: READ_REPORT_CONFIG_FRAME.payload,
422
+ cluster: {name: "genBasic"},
423
+ });
424
+ });
425
+ });
426
+
427
+ describe("readReportConfigRsp", () => {
428
+ const READ_REPORT_CONFIG_RSP_FRAME = Zcl.Frame.create(
429
+ Zcl.FrameType.GLOBAL,
430
+ Zcl.Direction.CLIENT_TO_SERVER,
431
+ true,
432
+ undefined,
433
+ 10,
434
+ "readReportConfigRsp",
435
+ "genBasic",
436
+ [
437
+ {
438
+ status: Zcl.Status.SUCCESS,
439
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
440
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
441
+ dataType: Zcl.Clusters.genBasic.attributes.zclVersion.type,
442
+ minRepIntval: 10,
443
+ maxRepIntval: 100,
444
+ repChange: 60,
445
+ },
446
+ {
447
+ status: Zcl.Status.NOT_AUTHORIZED,
448
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
449
+ attrId: Zcl.Clusters.genBasic.attributes.modelId.ID,
450
+ },
451
+ {
452
+ status: Zcl.Status.SUCCESS,
453
+ direction: Zcl.Direction.CLIENT_TO_SERVER,
454
+ attrId: Zcl.Clusters.genBasic.attributes.powerSource.ID,
455
+ dataType: Zcl.Clusters.genBasic.attributes.powerSource.type,
456
+ minRepIntval: 3500,
457
+ maxRepIntval: 45000,
458
+ },
459
+ {
460
+ status: Zcl.Status.SUCCESS,
461
+ direction: Zcl.Direction.SERVER_TO_CLIENT,
462
+ attrId: Zcl.Clusters.genBasic.attributes.alarmMask.ID,
463
+ timeout: 4500,
464
+ },
465
+ {
466
+ status: Zcl.Status.UNSUPPORTED_ATTRIBUTE,
467
+ direction: Zcl.Direction.SERVER_TO_CLIENT,
468
+ attrId: Zcl.Clusters.genBasic.attributes.physicalEnv.ID,
469
+ },
470
+ ],
471
+ {},
472
+ );
473
+
474
+ it("parses & writes", () => {
475
+ const rawFrame = READ_REPORT_CONFIG_RSP_FRAME.toBuffer();
476
+
477
+ expect(rawFrame).toStrictEqual(
478
+ Buffer.from([
479
+ 0x10, 0x0a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a, 0x00, 0x64, 0x00, 0x3c, 0x7e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00,
480
+ 0x30, 0xac, 0x0d, 0xc8, 0xaf, 0x00, 0x01, 0x13, 0x00, 0x94, 0x11, 0x86, 0x01, 0x11, 0x00,
481
+ ]),
482
+ );
483
+
484
+ const frame = Zcl.Frame.fromBuffer(READ_REPORT_CONFIG_RSP_FRAME.cluster.ID, READ_REPORT_CONFIG_RSP_FRAME.header, rawFrame, {});
485
+
486
+ expect(frame).toMatchObject({
487
+ header: READ_REPORT_CONFIG_RSP_FRAME.header,
488
+ payload: READ_REPORT_CONFIG_RSP_FRAME.payload,
489
+ cluster: {name: "genBasic"},
490
+ });
491
+ });
492
+ });
493
+
494
+ describe("report", () => {
495
+ const REPORT_FRAME = Zcl.Frame.create(
496
+ Zcl.FrameType.GLOBAL,
497
+ Zcl.Direction.SERVER_TO_CLIENT,
498
+ true,
499
+ undefined,
500
+ 10,
501
+ "report",
502
+ "genBasic",
503
+ [
504
+ {
505
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
506
+ dataType: Zcl.Clusters.genBasic.attributes.zclVersion.type,
507
+ attrData: 8,
508
+ },
509
+ {
510
+ attrId: Zcl.Clusters.genBasic.attributes.manufacturerName.ID,
511
+ dataType: Zcl.Clusters.genBasic.attributes.manufacturerName.type,
512
+ attrData: "efgh",
513
+ },
514
+ ],
515
+ {},
516
+ );
517
+
518
+ it("parses & writes", () => {
519
+ const rawFrame = REPORT_FRAME.toBuffer();
520
+
521
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x0a, 0x00, 0x00, 0x20, 0x08, 0x04, 0x00, 0x42, 0x04, 0x65, 0x66, 0x67, 0x68]));
522
+
523
+ const frame = Zcl.Frame.fromBuffer(REPORT_FRAME.cluster.ID, REPORT_FRAME.header, rawFrame, {});
524
+
525
+ expect(frame).toMatchObject({
526
+ header: REPORT_FRAME.header,
527
+ payload: REPORT_FRAME.payload,
528
+ cluster: {name: "genBasic"},
529
+ });
530
+ });
531
+
532
+ it("[WORKAROUND] parses CHAR_STR as MI_STRUCT for attribute 0xff01", () => {
533
+ const rawFrame = Buffer.from([
534
+ 0x18, 0x0a, 0x01, 0x01, 0xff, 0x00, 0x42, 34, 1, 33, 213, 12, 3, 40, 33, 4, 33, 168, 19, 5, 33, 43, 0, 6, 36, 0, 0, 5, 0, 0, 8, 33, 4,
535
+ 2, 10, 33, 0, 0, 100, 16, 0,
536
+ ]);
537
+
538
+ const frame = Zcl.Frame.fromBuffer(0x0000, Zcl.Header.fromBuffer(rawFrame), rawFrame, {});
539
+
540
+ expect(frame).toMatchObject({
541
+ payload: [
542
+ {
543
+ attrId: 0xff01,
544
+ dataType: Zcl.DataType.CHAR_STR,
545
+ attrData: {"1": 3285, "3": 33, "4": 5032, "5": 43, "6": 327680, "8": 516, "10": 0, "100": 0},
546
+ },
547
+ ],
548
+ cluster: {name: "genBasic"},
549
+ });
550
+ });
551
+ });
552
+
553
+ describe("defaultRsp", () => {
554
+ const DEFAULT_RSP_FRAME = Zcl.Frame.create(
555
+ Zcl.FrameType.GLOBAL,
556
+ Zcl.Direction.SERVER_TO_CLIENT,
557
+ true,
558
+ undefined,
559
+ 10,
560
+ "defaultRsp",
561
+ "genBasic",
562
+ {
563
+ cmdId: Zcl.Clusters.genBasic.commands.resetFactDefault.ID,
564
+ statusCode: Zcl.Status.SUCCESS,
565
+ },
566
+ {},
567
+ );
568
+
569
+ it("parses & writes", () => {
570
+ const rawFrame = DEFAULT_RSP_FRAME.toBuffer();
571
+
572
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x0b, 0x00, 0x00]));
573
+
574
+ const frame = Zcl.Frame.fromBuffer(DEFAULT_RSP_FRAME.cluster.ID, DEFAULT_RSP_FRAME.header, rawFrame, {});
575
+
576
+ expect(frame).toMatchObject({
577
+ header: DEFAULT_RSP_FRAME.header,
578
+ payload: DEFAULT_RSP_FRAME.payload,
579
+ cluster: {name: "genBasic"},
580
+ });
581
+ });
582
+ });
583
+
584
+ describe("discover", () => {
585
+ const DISCOVER_FRAME = Zcl.Frame.create(
586
+ Zcl.FrameType.GLOBAL,
587
+ Zcl.Direction.SERVER_TO_CLIENT,
588
+ true,
589
+ undefined,
590
+ 10,
591
+ "discover",
592
+ "genBasic",
593
+ {
594
+ startAttrId: 0x0012,
595
+ maxAttrIds: 8,
596
+ },
597
+ {},
598
+ );
599
+
600
+ it("parses & writes", () => {
601
+ const rawFrame = DISCOVER_FRAME.toBuffer();
602
+
603
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x0c, 0x12, 0x00, 0x08]));
604
+
605
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_FRAME.cluster.ID, DISCOVER_FRAME.header, rawFrame, {});
606
+
607
+ expect(frame).toMatchObject({
608
+ header: DISCOVER_FRAME.header,
609
+ payload: DISCOVER_FRAME.payload,
610
+ cluster: {name: "genBasic"},
611
+ });
612
+ });
613
+ });
614
+
615
+ describe("discoverRsp", () => {
616
+ const DISCOVER_RSP_FRAME = Zcl.Frame.create(
617
+ Zcl.FrameType.GLOBAL,
618
+ Zcl.Direction.SERVER_TO_CLIENT,
619
+ true,
620
+ undefined,
621
+ 10,
622
+ "discoverRsp",
623
+ "genOnOff",
624
+ {
625
+ discComplete: 1,
626
+ attrInfos: [
627
+ {attrId: Zcl.Clusters.genOnOff.attributes.onOff.ID, dataType: Zcl.Clusters.genOnOff.attributes.onOff.type},
628
+ {attrId: Zcl.Clusters.genOnOff.attributes.globalSceneCtrl.ID, dataType: Zcl.Clusters.genOnOff.attributes.globalSceneCtrl.type},
629
+ ],
630
+ },
631
+ {},
632
+ );
633
+
634
+ it("parses & writes", () => {
635
+ const rawFrame = DISCOVER_RSP_FRAME.toBuffer();
636
+
637
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x0d, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x10]));
638
+
639
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_RSP_FRAME.cluster.ID, DISCOVER_RSP_FRAME.header, rawFrame, {});
640
+
641
+ expect(frame).toMatchObject({
642
+ header: DISCOVER_RSP_FRAME.header,
643
+ payload: DISCOVER_RSP_FRAME.payload,
644
+ cluster: {name: "genOnOff"},
645
+ });
646
+ });
647
+ });
648
+
649
+ describe("readStructured", () => {
650
+ const READ_STRUCTURED_FRAME = Zcl.Frame.create(
651
+ Zcl.FrameType.GLOBAL,
652
+ Zcl.Direction.CLIENT_TO_SERVER,
653
+ true,
654
+ undefined,
655
+ 10,
656
+ "readStructured",
657
+ "genBasic",
658
+ [
659
+ {
660
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
661
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
662
+ },
663
+ {
664
+ attrId: Zcl.Clusters.genBasic.attributes.modelId.ID,
665
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
666
+ },
667
+ ],
668
+ {},
669
+ );
670
+
671
+ it("parses & writes", () => {
672
+ const rawFrame = READ_STRUCTURED_FRAME.toBuffer();
673
+
674
+ expect(rawFrame).toStrictEqual(Buffer.from([0x10, 0x0a, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00]));
675
+
676
+ const frame = Zcl.Frame.fromBuffer(READ_STRUCTURED_FRAME.cluster.ID, READ_STRUCTURED_FRAME.header, rawFrame, {});
677
+
678
+ expect(frame).toMatchObject({
679
+ header: READ_STRUCTURED_FRAME.header,
680
+ payload: READ_STRUCTURED_FRAME.payload,
681
+ cluster: {name: "genBasic"},
682
+ });
683
+ });
684
+ });
685
+
686
+ describe("writeStructured", () => {
687
+ const WRITE_STRUCTURED_FRAME = Zcl.Frame.create(
688
+ Zcl.FrameType.GLOBAL,
689
+ Zcl.Direction.CLIENT_TO_SERVER,
690
+ true,
691
+ undefined,
692
+ 10,
693
+ "writeStructured",
694
+ "genBasic",
695
+ [
696
+ {
697
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
698
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
699
+ dataType: Zcl.Clusters.genBasic.attributes.zclVersion.type,
700
+ elementData: 0x08,
701
+ },
702
+ {
703
+ attrId: Zcl.Clusters.genBasic.attributes.modelId.ID,
704
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
705
+ dataType: Zcl.Clusters.genBasic.attributes.modelId.type,
706
+ elementData: "abcd",
707
+ },
708
+ ],
709
+ {},
710
+ );
711
+
712
+ it("parses & writes", () => {
713
+ const rawFrame = WRITE_STRUCTURED_FRAME.toBuffer();
714
+
715
+ expect(rawFrame).toStrictEqual(
716
+ Buffer.from([0x10, 0x0a, 0x0f, 0x00, 0x00, 0x00, 0x20, 0x08, 0x05, 0x00, 0x00, 0x42, 0x04, 0x61, 0x62, 0x63, 0x64]),
717
+ );
718
+
719
+ const frame = Zcl.Frame.fromBuffer(WRITE_STRUCTURED_FRAME.cluster.ID, WRITE_STRUCTURED_FRAME.header, rawFrame, {});
720
+
721
+ expect(frame).toMatchObject({
722
+ header: WRITE_STRUCTURED_FRAME.header,
723
+ payload: WRITE_STRUCTURED_FRAME.payload,
724
+ cluster: {name: "genBasic"},
725
+ });
726
+ });
727
+ });
728
+
729
+ describe("writeStructuredRsp", () => {
730
+ const WRITE_STRUCTURED_RSP_FRAME = Zcl.Frame.create(
731
+ Zcl.FrameType.GLOBAL,
732
+ Zcl.Direction.CLIENT_TO_SERVER,
733
+ true,
734
+ undefined,
735
+ 10,
736
+ "writeStructuredRsp",
737
+ "genBasic",
738
+ [
739
+ {
740
+ status: Zcl.Status.UNSUPPORTED_ATTRIBUTE,
741
+ attrId: Zcl.Clusters.genBasic.attributes.zclVersion.ID,
742
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
743
+ },
744
+ {
745
+ status: Zcl.Status.NOT_AUTHORIZED,
746
+ attrId: Zcl.Clusters.genBasic.attributes.modelId.ID,
747
+ selector: {indicatorType: Zcl.StructuredIndicatorType.Whole},
748
+ },
749
+ ],
750
+ {},
751
+ );
752
+
753
+ it("parses & writes", () => {
754
+ const rawFrame = WRITE_STRUCTURED_RSP_FRAME.toBuffer();
755
+
756
+ expect(rawFrame).toStrictEqual(Buffer.from([0x10, 0x0a, 0x10, 0x86, 0x00, 0x00, 0x00, 0x7e, 0x05, 0x00, 0x00]));
757
+
758
+ const frame = Zcl.Frame.fromBuffer(WRITE_STRUCTURED_RSP_FRAME.cluster.ID, WRITE_STRUCTURED_RSP_FRAME.header, rawFrame, {});
759
+
760
+ expect(frame).toMatchObject({
761
+ header: WRITE_STRUCTURED_RSP_FRAME.header,
762
+ payload: WRITE_STRUCTURED_RSP_FRAME.payload,
763
+ cluster: {name: "genBasic"},
764
+ });
765
+ });
766
+
767
+ it("handles SUCCESS payload", () => {
768
+ const WRITE_STRUCTURED_RSP_SUCCESS_FRAME = Zcl.Frame.create(
769
+ Zcl.FrameType.GLOBAL,
770
+ Zcl.Direction.SERVER_TO_CLIENT,
771
+ true,
772
+ undefined,
773
+ 10,
774
+ "writeStructuredRsp",
775
+ "genOnOff",
776
+ [{status: Zcl.Status.SUCCESS}],
777
+ {},
778
+ );
779
+ const rawFrame = WRITE_STRUCTURED_RSP_SUCCESS_FRAME.toBuffer();
780
+
781
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x10, 0x00]));
782
+
783
+ const frame = Zcl.Frame.fromBuffer(
784
+ WRITE_STRUCTURED_RSP_SUCCESS_FRAME.cluster.ID,
785
+ WRITE_STRUCTURED_RSP_SUCCESS_FRAME.header,
786
+ rawFrame,
787
+ {},
788
+ );
789
+
790
+ expect(frame).toMatchObject({
791
+ header: WRITE_STRUCTURED_RSP_SUCCESS_FRAME.header,
792
+ payload: WRITE_STRUCTURED_RSP_SUCCESS_FRAME.payload,
793
+ cluster: {name: "genOnOff"},
794
+ });
795
+ });
796
+ });
797
+
798
+ describe("discoverCommands", () => {
799
+ const DISCOVER_COMMANDS_FRAME = Zcl.Frame.create(
800
+ Zcl.FrameType.GLOBAL,
801
+ Zcl.Direction.SERVER_TO_CLIENT,
802
+ true,
803
+ undefined,
804
+ 10,
805
+ "discoverCommands",
806
+ "genOnOff",
807
+ {
808
+ startCmdId: 0x0010,
809
+ maxCmdIds: 3,
810
+ },
811
+ {},
812
+ );
813
+
814
+ it("parses & writes", () => {
815
+ const rawFrame = DISCOVER_COMMANDS_FRAME.toBuffer();
816
+
817
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x11, 0x10, 0x03]));
818
+
819
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_COMMANDS_FRAME.cluster.ID, DISCOVER_COMMANDS_FRAME.header, rawFrame, {});
820
+
821
+ expect(frame).toMatchObject({
822
+ header: DISCOVER_COMMANDS_FRAME.header,
823
+ payload: DISCOVER_COMMANDS_FRAME.payload,
824
+ cluster: {name: "genOnOff"},
825
+ });
826
+ });
827
+ });
828
+
829
+ describe("discoverCommandsRsp", () => {
830
+ const DISCOVER_COMMANDS_RSP_FRAME = Zcl.Frame.create(
831
+ Zcl.FrameType.GLOBAL,
832
+ Zcl.Direction.SERVER_TO_CLIENT,
833
+ true,
834
+ undefined,
835
+ 10,
836
+ "discoverCommandsRsp",
837
+ "genOnOff",
838
+ {
839
+ discComplete: 1,
840
+ commandIds: [Zcl.Clusters.genOnOff.commands.off.ID, Zcl.Clusters.genOnOff.commands.on.ID],
841
+ },
842
+ {},
843
+ );
844
+
845
+ it("parses & writes", () => {
846
+ const rawFrame = DISCOVER_COMMANDS_RSP_FRAME.toBuffer();
847
+
848
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x12, 0x01, 0x00, 0x01]));
849
+
850
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_COMMANDS_RSP_FRAME.cluster.ID, DISCOVER_COMMANDS_RSP_FRAME.header, rawFrame, {});
851
+
852
+ expect(frame).toMatchObject({
853
+ header: DISCOVER_COMMANDS_RSP_FRAME.header,
854
+ payload: DISCOVER_COMMANDS_RSP_FRAME.payload,
855
+ cluster: {name: "genOnOff"},
856
+ });
857
+ });
858
+ });
859
+
860
+ describe("discoverCommandsGen", () => {
861
+ const DISCOVER_COMMANDS_GEN_FRAME = Zcl.Frame.create(
862
+ Zcl.FrameType.GLOBAL,
863
+ Zcl.Direction.SERVER_TO_CLIENT,
864
+ true,
865
+ undefined,
866
+ 10,
867
+ "discoverCommandsGen",
868
+ "genOnOff",
869
+ {
870
+ startCmdId: 0x0010,
871
+ maxCmdIds: 3,
872
+ },
873
+ {},
874
+ );
875
+
876
+ it("parses & writes", () => {
877
+ const rawFrame = DISCOVER_COMMANDS_GEN_FRAME.toBuffer();
878
+
879
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x13, 0x10, 0x03]));
880
+
881
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_COMMANDS_GEN_FRAME.cluster.ID, DISCOVER_COMMANDS_GEN_FRAME.header, rawFrame, {});
882
+
883
+ expect(frame).toMatchObject({
884
+ header: DISCOVER_COMMANDS_GEN_FRAME.header,
885
+ payload: DISCOVER_COMMANDS_GEN_FRAME.payload,
886
+ cluster: {name: "genOnOff"},
887
+ });
888
+ });
889
+ });
890
+
891
+ describe("discoverCommandsGenRsp", () => {
892
+ const DISCOVER_COMMANDS_GEN_RSP_FRAME = Zcl.Frame.create(
893
+ Zcl.FrameType.GLOBAL,
894
+ Zcl.Direction.SERVER_TO_CLIENT,
895
+ true,
896
+ undefined,
897
+ 10,
898
+ "discoverCommandsGenRsp",
899
+ "genOnOff",
900
+ {
901
+ discComplete: 1,
902
+ commandIds: [Zcl.Clusters.genOnOff.commands.off.ID, Zcl.Clusters.genOnOff.commands.on.ID],
903
+ },
904
+ {},
905
+ );
906
+
907
+ it("parses & writes", () => {
908
+ const rawFrame = DISCOVER_COMMANDS_GEN_RSP_FRAME.toBuffer();
909
+
910
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x14, 0x01, 0x00, 0x01]));
911
+
912
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_COMMANDS_GEN_RSP_FRAME.cluster.ID, DISCOVER_COMMANDS_GEN_RSP_FRAME.header, rawFrame, {});
913
+
914
+ expect(frame).toMatchObject({
915
+ header: DISCOVER_COMMANDS_GEN_RSP_FRAME.header,
916
+ payload: DISCOVER_COMMANDS_GEN_RSP_FRAME.payload,
917
+ cluster: {name: "genOnOff"},
918
+ });
919
+ });
920
+ });
921
+
922
+ describe("discoverExt", () => {
923
+ const DISCOVER_EXT_FRAME = Zcl.Frame.create(
924
+ Zcl.FrameType.GLOBAL,
925
+ Zcl.Direction.SERVER_TO_CLIENT,
926
+ true,
927
+ undefined,
928
+ 10,
929
+ "discoverExt",
930
+ "genBasic",
931
+ {
932
+ startAttrId: 0x0012,
933
+ maxAttrIds: 8,
934
+ },
935
+ {},
936
+ );
937
+
938
+ it("parses & writes", () => {
939
+ const rawFrame = DISCOVER_EXT_FRAME.toBuffer();
940
+
941
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x15, 0x12, 0x00, 0x08]));
942
+
943
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_EXT_FRAME.cluster.ID, DISCOVER_EXT_FRAME.header, rawFrame, {});
944
+
945
+ expect(frame).toMatchObject({
946
+ header: DISCOVER_EXT_FRAME.header,
947
+ payload: DISCOVER_EXT_FRAME.payload,
948
+ cluster: {name: "genBasic"},
949
+ });
950
+ });
951
+ });
952
+
953
+ describe("discoverExtRsp", () => {
954
+ const DISCOVER_EXT_RSP_FRAME = Zcl.Frame.create(
955
+ Zcl.FrameType.GLOBAL,
956
+ Zcl.Direction.SERVER_TO_CLIENT,
957
+ true,
958
+ undefined,
959
+ 10,
960
+ "discoverExtRsp",
961
+ "genOnOff",
962
+ {
963
+ discComplete: 1,
964
+ attrInfos: [
965
+ {attrId: Zcl.Clusters.genOnOff.attributes.onOff.ID, dataType: Zcl.Clusters.genOnOff.attributes.onOff.type, access: 1},
966
+ {
967
+ attrId: Zcl.Clusters.genOnOff.attributes.globalSceneCtrl.ID,
968
+ dataType: Zcl.Clusters.genOnOff.attributes.globalSceneCtrl.type,
969
+ access: 2,
970
+ },
971
+ ],
972
+ },
973
+ {},
974
+ );
975
+
976
+ it("parses & writes", () => {
977
+ const rawFrame = DISCOVER_EXT_RSP_FRAME.toBuffer();
978
+
979
+ expect(rawFrame).toStrictEqual(Buffer.from([0x18, 0x0a, 0x16, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x40, 0x10, 0x02]));
980
+
981
+ const frame = Zcl.Frame.fromBuffer(DISCOVER_EXT_RSP_FRAME.cluster.ID, DISCOVER_EXT_RSP_FRAME.header, rawFrame, {});
982
+
983
+ expect(frame).toMatchObject({
984
+ header: DISCOVER_EXT_RSP_FRAME.header,
985
+ payload: DISCOVER_EXT_RSP_FRAME.payload,
986
+ cluster: {name: "genOnOff"},
987
+ });
988
+ });
989
+ });
990
+ });