zigbee-herdsman 6.0.1 → 6.0.3

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 (260) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/adapter/ezsp/driver/uart.js +1 -1
  3. package/dist/adapter/ezsp/driver/uart.js.map +1 -1
  4. package/dist/adapter/z-stack/adapter/zStackAdapter.js +4 -4
  5. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  6. package/dist/adapter/zigate/adapter/zigateAdapter.js +4 -4
  7. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  8. package/dist/controller/model/device.d.ts.map +1 -1
  9. package/dist/controller/model/device.js +1 -0
  10. package/dist/controller/model/device.js.map +1 -1
  11. package/package.json +14 -6
  12. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  13. package/.github/dependabot.yml +0 -22
  14. package/.github/workflows/ci.yml +0 -64
  15. package/.github/workflows/release-please.yml +0 -18
  16. package/.github/workflows/stale.yml +0 -20
  17. package/.github/workflows/typedoc.yaml +0 -47
  18. package/.release-please-manifest.json +0 -3
  19. package/.vscode/extensions.json +0 -3
  20. package/.vscode/settings.json +0 -11
  21. package/biome.json +0 -98
  22. package/examples/join-and-log.js +0 -24
  23. package/release-please-config.json +0 -9
  24. package/src/adapter/adapter.ts +0 -189
  25. package/src/adapter/adapterDiscovery.ts +0 -666
  26. package/src/adapter/const.ts +0 -12
  27. package/src/adapter/deconz/adapter/deconzAdapter.ts +0 -877
  28. package/src/adapter/deconz/driver/constants.ts +0 -246
  29. package/src/adapter/deconz/driver/driver.ts +0 -1540
  30. package/src/adapter/deconz/driver/frame.ts +0 -11
  31. package/src/adapter/deconz/driver/frameParser.ts +0 -753
  32. package/src/adapter/deconz/driver/parser.ts +0 -45
  33. package/src/adapter/deconz/driver/writer.ts +0 -22
  34. package/src/adapter/deconz/types.d.ts +0 -13
  35. package/src/adapter/ember/adapter/emberAdapter.ts +0 -2265
  36. package/src/adapter/ember/adapter/endpoints.ts +0 -86
  37. package/src/adapter/ember/adapter/oneWaitress.ts +0 -324
  38. package/src/adapter/ember/adapter/tokensManager.ts +0 -782
  39. package/src/adapter/ember/consts.ts +0 -178
  40. package/src/adapter/ember/enums.ts +0 -1746
  41. package/src/adapter/ember/ezsp/buffalo.ts +0 -1392
  42. package/src/adapter/ember/ezsp/consts.ts +0 -148
  43. package/src/adapter/ember/ezsp/enums.ts +0 -1114
  44. package/src/adapter/ember/ezsp/ezsp.ts +0 -9061
  45. package/src/adapter/ember/ezspError.ts +0 -10
  46. package/src/adapter/ember/types.ts +0 -866
  47. package/src/adapter/ember/uart/ash.ts +0 -1960
  48. package/src/adapter/ember/uart/consts.ts +0 -109
  49. package/src/adapter/ember/uart/enums.ts +0 -192
  50. package/src/adapter/ember/uart/parser.ts +0 -48
  51. package/src/adapter/ember/uart/queues.ts +0 -247
  52. package/src/adapter/ember/uart/writer.ts +0 -53
  53. package/src/adapter/ember/utils/initters.ts +0 -58
  54. package/src/adapter/ember/utils/math.ts +0 -73
  55. package/src/adapter/events.ts +0 -21
  56. package/src/adapter/ezsp/adapter/backup.ts +0 -109
  57. package/src/adapter/ezsp/adapter/ezspAdapter.ts +0 -614
  58. package/src/adapter/ezsp/driver/commands.ts +0 -2497
  59. package/src/adapter/ezsp/driver/consts.ts +0 -11
  60. package/src/adapter/ezsp/driver/driver.ts +0 -1002
  61. package/src/adapter/ezsp/driver/ezsp.ts +0 -802
  62. package/src/adapter/ezsp/driver/frame.ts +0 -101
  63. package/src/adapter/ezsp/driver/index.ts +0 -4
  64. package/src/adapter/ezsp/driver/multicast.ts +0 -78
  65. package/src/adapter/ezsp/driver/parser.ts +0 -81
  66. package/src/adapter/ezsp/driver/types/basic.ts +0 -201
  67. package/src/adapter/ezsp/driver/types/index.ts +0 -239
  68. package/src/adapter/ezsp/driver/types/named.ts +0 -2330
  69. package/src/adapter/ezsp/driver/types/struct.ts +0 -844
  70. package/src/adapter/ezsp/driver/uart.ts +0 -460
  71. package/src/adapter/ezsp/driver/utils/crc16ccitt.ts +0 -44
  72. package/src/adapter/ezsp/driver/utils/index.ts +0 -32
  73. package/src/adapter/ezsp/driver/writer.ts +0 -64
  74. package/src/adapter/index.ts +0 -3
  75. package/src/adapter/serialPort.ts +0 -58
  76. package/src/adapter/socketPortUtils.ts +0 -16
  77. package/src/adapter/tstype.ts +0 -78
  78. package/src/adapter/z-stack/adapter/adapter-backup.ts +0 -519
  79. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +0 -457
  80. package/src/adapter/z-stack/adapter/endpoints.ts +0 -57
  81. package/src/adapter/z-stack/adapter/manager.ts +0 -543
  82. package/src/adapter/z-stack/adapter/tstype.ts +0 -6
  83. package/src/adapter/z-stack/adapter/zStackAdapter.ts +0 -1190
  84. package/src/adapter/z-stack/constants/af.ts +0 -27
  85. package/src/adapter/z-stack/constants/common.ts +0 -285
  86. package/src/adapter/z-stack/constants/dbg.ts +0 -23
  87. package/src/adapter/z-stack/constants/index.ts +0 -11
  88. package/src/adapter/z-stack/constants/mac.ts +0 -128
  89. package/src/adapter/z-stack/constants/sapi.ts +0 -25
  90. package/src/adapter/z-stack/constants/sys.ts +0 -72
  91. package/src/adapter/z-stack/constants/util.ts +0 -82
  92. package/src/adapter/z-stack/constants/utils.ts +0 -14
  93. package/src/adapter/z-stack/constants/zdo.ts +0 -103
  94. package/src/adapter/z-stack/models/startup-options.ts +0 -13
  95. package/src/adapter/z-stack/structs/entries/address-manager-entry.ts +0 -44
  96. package/src/adapter/z-stack/structs/entries/address-manager-table.ts +0 -19
  97. package/src/adapter/z-stack/structs/entries/aps-link-key-data-entry.ts +0 -12
  98. package/src/adapter/z-stack/structs/entries/aps-link-key-data-table.ts +0 -21
  99. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-entry.ts +0 -19
  100. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-table.ts +0 -21
  101. package/src/adapter/z-stack/structs/entries/channel-list.ts +0 -8
  102. package/src/adapter/z-stack/structs/entries/has-configured.ts +0 -16
  103. package/src/adapter/z-stack/structs/entries/index.ts +0 -16
  104. package/src/adapter/z-stack/structs/entries/nib.ts +0 -66
  105. package/src/adapter/z-stack/structs/entries/nwk-key-descriptor.ts +0 -15
  106. package/src/adapter/z-stack/structs/entries/nwk-key.ts +0 -13
  107. package/src/adapter/z-stack/structs/entries/nwk-pan-id.ts +0 -8
  108. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.ts +0 -20
  109. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.ts +0 -19
  110. package/src/adapter/z-stack/structs/entries/security-manager-entry.ts +0 -33
  111. package/src/adapter/z-stack/structs/entries/security-manager-table.ts +0 -22
  112. package/src/adapter/z-stack/structs/index.ts +0 -4
  113. package/src/adapter/z-stack/structs/serializable-memory-object.ts +0 -14
  114. package/src/adapter/z-stack/structs/struct.ts +0 -367
  115. package/src/adapter/z-stack/structs/table.ts +0 -198
  116. package/src/adapter/z-stack/unpi/constants.ts +0 -33
  117. package/src/adapter/z-stack/unpi/frame.ts +0 -62
  118. package/src/adapter/z-stack/unpi/index.ts +0 -4
  119. package/src/adapter/z-stack/unpi/parser.ts +0 -56
  120. package/src/adapter/z-stack/unpi/writer.ts +0 -21
  121. package/src/adapter/z-stack/utils/channel-list.ts +0 -40
  122. package/src/adapter/z-stack/utils/index.ts +0 -2
  123. package/src/adapter/z-stack/utils/network-options.ts +0 -26
  124. package/src/adapter/z-stack/znp/buffaloZnp.ts +0 -175
  125. package/src/adapter/z-stack/znp/definition.ts +0 -2713
  126. package/src/adapter/z-stack/znp/index.ts +0 -2
  127. package/src/adapter/z-stack/znp/parameterType.ts +0 -22
  128. package/src/adapter/z-stack/znp/tstype.ts +0 -44
  129. package/src/adapter/z-stack/znp/utils.ts +0 -10
  130. package/src/adapter/z-stack/znp/znp.ts +0 -342
  131. package/src/adapter/z-stack/znp/zpiObject.ts +0 -148
  132. package/src/adapter/zboss/adapter/zbossAdapter.ts +0 -526
  133. package/src/adapter/zboss/commands.ts +0 -1184
  134. package/src/adapter/zboss/consts.ts +0 -9
  135. package/src/adapter/zboss/driver.ts +0 -422
  136. package/src/adapter/zboss/enums.ts +0 -360
  137. package/src/adapter/zboss/frame.ts +0 -227
  138. package/src/adapter/zboss/reader.ts +0 -65
  139. package/src/adapter/zboss/types.ts +0 -0
  140. package/src/adapter/zboss/uart.ts +0 -428
  141. package/src/adapter/zboss/utils.ts +0 -58
  142. package/src/adapter/zboss/writer.ts +0 -49
  143. package/src/adapter/zigate/adapter/patchZdoBuffaloBE.ts +0 -27
  144. package/src/adapter/zigate/adapter/zigateAdapter.ts +0 -618
  145. package/src/adapter/zigate/driver/LICENSE +0 -17
  146. package/src/adapter/zigate/driver/buffaloZiGate.ts +0 -212
  147. package/src/adapter/zigate/driver/commandType.ts +0 -418
  148. package/src/adapter/zigate/driver/constants.ts +0 -150
  149. package/src/adapter/zigate/driver/frame.ts +0 -197
  150. package/src/adapter/zigate/driver/messageType.ts +0 -287
  151. package/src/adapter/zigate/driver/parameterType.ts +0 -32
  152. package/src/adapter/zigate/driver/ziGateObject.ts +0 -146
  153. package/src/adapter/zigate/driver/zigate.ts +0 -423
  154. package/src/adapter/zoh/adapter/utils.ts +0 -27
  155. package/src/adapter/zoh/adapter/zohAdapter.ts +0 -838
  156. package/src/buffalo/buffalo.ts +0 -342
  157. package/src/buffalo/index.ts +0 -1
  158. package/src/controller/controller.ts +0 -1022
  159. package/src/controller/database.ts +0 -124
  160. package/src/controller/events.ts +0 -52
  161. package/src/controller/greenPower.ts +0 -603
  162. package/src/controller/helpers/index.ts +0 -1
  163. package/src/controller/helpers/installCodes.ts +0 -107
  164. package/src/controller/helpers/request.ts +0 -96
  165. package/src/controller/helpers/requestQueue.ts +0 -125
  166. package/src/controller/helpers/zclFrameConverter.ts +0 -47
  167. package/src/controller/helpers/zclTransactionSequenceNumber.ts +0 -19
  168. package/src/controller/index.ts +0 -6
  169. package/src/controller/model/device.ts +0 -1248
  170. package/src/controller/model/endpoint.ts +0 -1105
  171. package/src/controller/model/entity.ts +0 -23
  172. package/src/controller/model/group.ts +0 -424
  173. package/src/controller/model/index.ts +0 -5
  174. package/src/controller/model/zigbeeEntity.ts +0 -30
  175. package/src/controller/touchlink.ts +0 -189
  176. package/src/controller/tstype.ts +0 -274
  177. package/src/index.ts +0 -12
  178. package/src/models/backup-storage-legacy.ts +0 -48
  179. package/src/models/backup-storage-unified.ts +0 -47
  180. package/src/models/backup.ts +0 -37
  181. package/src/models/index.ts +0 -5
  182. package/src/models/network-options.ts +0 -11
  183. package/src/utils/backup.ts +0 -152
  184. package/src/utils/index.ts +0 -5
  185. package/src/utils/logger.ts +0 -20
  186. package/src/utils/patchBigIntSerialization.ts +0 -8
  187. package/src/utils/queue.ts +0 -76
  188. package/src/utils/types.d.ts +0 -3
  189. package/src/utils/utils.ts +0 -19
  190. package/src/utils/wait.ts +0 -5
  191. package/src/utils/waitress.ts +0 -96
  192. package/src/zspec/consts.ts +0 -84
  193. package/src/zspec/enums.ts +0 -22
  194. package/src/zspec/index.ts +0 -3
  195. package/src/zspec/tstypes.ts +0 -18
  196. package/src/zspec/utils.ts +0 -247
  197. package/src/zspec/zcl/buffaloZcl.ts +0 -1220
  198. package/src/zspec/zcl/definition/cluster.ts +0 -5915
  199. package/src/zspec/zcl/definition/clusters-typegen.ts +0 -588
  200. package/src/zspec/zcl/definition/clusters-types.ts +0 -7331
  201. package/src/zspec/zcl/definition/consts.ts +0 -24
  202. package/src/zspec/zcl/definition/enums.ts +0 -203
  203. package/src/zspec/zcl/definition/foundation.ts +0 -329
  204. package/src/zspec/zcl/definition/manufacturerCode.ts +0 -729
  205. package/src/zspec/zcl/definition/status.ts +0 -69
  206. package/src/zspec/zcl/definition/tstype.ts +0 -377
  207. package/src/zspec/zcl/index.ts +0 -11
  208. package/src/zspec/zcl/utils.ts +0 -321
  209. package/src/zspec/zcl/zclFrame.ts +0 -356
  210. package/src/zspec/zcl/zclHeader.ts +0 -102
  211. package/src/zspec/zcl/zclStatusError.ts +0 -10
  212. package/src/zspec/zdo/buffaloZdo.ts +0 -2336
  213. package/src/zspec/zdo/definition/clusters.ts +0 -722
  214. package/src/zspec/zdo/definition/consts.ts +0 -16
  215. package/src/zspec/zdo/definition/enums.ts +0 -99
  216. package/src/zspec/zdo/definition/status.ts +0 -105
  217. package/src/zspec/zdo/definition/tstypes.ts +0 -1062
  218. package/src/zspec/zdo/index.ts +0 -7
  219. package/src/zspec/zdo/utils.ts +0 -76
  220. package/src/zspec/zdo/zdoStatusError.ts +0 -10
  221. package/test/adapter/adapter.test.ts +0 -1062
  222. package/test/adapter/ember/ash.test.ts +0 -337
  223. package/test/adapter/ember/consts.ts +0 -131
  224. package/test/adapter/ember/emberAdapter.test.ts +0 -3449
  225. package/test/adapter/ember/ezsp.test.ts +0 -385
  226. package/test/adapter/ember/ezspBuffalo.test.ts +0 -93
  227. package/test/adapter/ember/ezspError.test.ts +0 -12
  228. package/test/adapter/ember/math.test.ts +0 -206
  229. package/test/adapter/ezsp/frame.test.ts +0 -30
  230. package/test/adapter/ezsp/uart.test.ts +0 -181
  231. package/test/adapter/z-stack/adapter.test.ts +0 -3984
  232. package/test/adapter/z-stack/constants.test.ts +0 -33
  233. package/test/adapter/z-stack/structs.test.ts +0 -115
  234. package/test/adapter/z-stack/unpi.test.ts +0 -213
  235. package/test/adapter/z-stack/znp.test.ts +0 -1284
  236. package/test/adapter/zboss/fixZdoResponse.test.ts +0 -179
  237. package/test/adapter/zigate/patchZdoBuffaloBE.test.ts +0 -81
  238. package/test/adapter/zigate/zdo.test.ts +0 -187
  239. package/test/adapter/zoh/utils.test.ts +0 -36
  240. package/test/adapter/zoh/zohAdapter.test.ts +0 -1307
  241. package/test/buffalo.test.ts +0 -431
  242. package/test/controller.bench.ts +0 -193
  243. package/test/controller.test.ts +0 -8702
  244. package/test/greenpower.test.ts +0 -1408
  245. package/test/mockAdapters.ts +0 -65
  246. package/test/mockDevices.ts +0 -598
  247. package/test/requests.bench.ts +0 -206
  248. package/test/testUtils.ts +0 -20
  249. package/test/tsconfig.json +0 -9
  250. package/test/utils/math.ts +0 -19
  251. package/test/utils.test.ts +0 -279
  252. package/test/vitest.config.mts +0 -27
  253. package/test/zcl.test.ts +0 -2831
  254. package/test/zspec/utils.test.ts +0 -68
  255. package/test/zspec/zcl/buffalo.test.ts +0 -1374
  256. package/test/zspec/zcl/frame.test.ts +0 -960
  257. package/test/zspec/zcl/utils.test.ts +0 -273
  258. package/test/zspec/zdo/buffalo.test.ts +0 -1850
  259. package/test/zspec/zdo/utils.test.ts +0 -241
  260. package/tsconfig.json +0 -24
@@ -1,3984 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import equals from "fast-deep-equal/es6";
4
- import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
5
- import type {ZclPayload} from "../../../src/adapter/events";
6
- import {ZnpVersion} from "../../../src/adapter/z-stack/adapter/tstype";
7
- import {ZStackAdapter} from "../../../src/adapter/z-stack/adapter/zStackAdapter";
8
- import * as Constants from "../../../src/adapter/z-stack/constants";
9
- import {AddressMode, DevStates, NvItemsIds, NvSystemIds, type ZnpCommandStatus} from "../../../src/adapter/z-stack/constants/common";
10
- import * as Structs from "../../../src/adapter/z-stack/structs";
11
- import {Subsystem, Type} from "../../../src/adapter/z-stack/unpi/constants";
12
- import {Znp, type ZpiObject} from "../../../src/adapter/z-stack/znp";
13
- import Definition from "../../../src/adapter/z-stack/znp/definition";
14
- import type {ZpiObjectPayload} from "../../../src/adapter/z-stack/znp/tstype";
15
- import type {UnifiedBackupStorage} from "../../../src/models";
16
- import {setLogger} from "../../../src/utils/logger";
17
- import * as ZSpec from "../../../src/zspec";
18
- import {BroadcastAddress} from "../../../src/zspec/enums";
19
- import * as Zcl from "../../../src/zspec/zcl";
20
- import * as Zdo from "../../../src/zspec/zdo";
21
- import type {
22
- ActiveEndpointsResponse,
23
- EndDeviceAnnounce,
24
- LQITableResponse,
25
- NetworkAddressResponse,
26
- NodeDescriptorResponse,
27
- RoutingTableResponse,
28
- SimpleDescriptorResponse,
29
- } from "../../../src/zspec/zdo/definition/tstypes";
30
-
31
- const DUMMY_NODE_DESC_RSP_CAPABILITIES = {
32
- allocateAddress: 0,
33
- alternatePANCoordinator: 0,
34
- deviceType: 2,
35
- powerSource: 0,
36
- reserved1: 0,
37
- reserved2: 0,
38
- rxOnWhenIdle: 0,
39
- securityCapability: 0,
40
- };
41
-
42
- const mockLogger = {
43
- debug: vi.fn(),
44
- info: vi.fn(),
45
- warning: vi.fn(),
46
- error: vi.fn(),
47
- };
48
- const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
49
- const mockSetTimeout = () => {
50
- return vi.spyOn(globalThis, "setTimeout").mockImplementation(
51
- // @ts-expect-error mock
52
- (cb) => cb(),
53
- );
54
- };
55
-
56
- vi.mock("../../../src/utils/wait", () => ({
57
- wait: vi.fn(() => {
58
- return new Promise<void>((resolve) => resolve());
59
- }),
60
- }));
61
-
62
- const waitForResult = (payloadOrPromise: Promise<unknown> | ZpiObjectPayload, id?: number) => {
63
- id = id || 1;
64
- if (payloadOrPromise instanceof Promise) {
65
- return {
66
- start: () => {
67
- return {promise: payloadOrPromise, ID: id};
68
- },
69
- ID: id,
70
- };
71
- }
72
-
73
- return {
74
- start: () => {
75
- return {promise: new Promise((r) => r(payloadOrPromise)), ID: id};
76
- },
77
- ID: id,
78
- };
79
- };
80
-
81
- const networkOptions = {
82
- panID: 123,
83
- extendedPanID: [0x00, 0x12, 0x4b, 0x00, 0x09, 0xd6, 0x9f, 0x77],
84
- channelList: [21],
85
- networkKey: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
86
- networkKeyDistribute: false,
87
- };
88
-
89
- const networkOptionsDefaultExtendedPanId = {
90
- panID: 123,
91
- extendedPanID: [0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd],
92
- channelList: [21],
93
- networkKey: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
94
- networkKeyDistribute: false,
95
- };
96
-
97
- const networkOptionsMismatched = {
98
- panID: 124,
99
- extendedPanID: [0x00, 0x12, 0x4b, 0x00, 0x09, 0xd6, 0x9f, 0x77],
100
- channelList: [21],
101
- networkKey: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
102
- networkKeyDistribute: false,
103
- };
104
-
105
- const networkOptionsInvalidPanId = {
106
- panID: 65535,
107
- extendedPanID: [0x00, 0x12, 0x4b, 0x00, 0x09, 0xd6, 0x9f, 0x77],
108
- channelList: [21],
109
- networkKey: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
110
- networkKeyDistribute: false,
111
- };
112
-
113
- const serialPortOptions = {
114
- baudRate: 800,
115
- rtscts: false,
116
- path: "dummy",
117
- };
118
-
119
- const backupMatchingConfig = {
120
- metadata: {
121
- format: "zigpy/open-coordinator-backup",
122
- version: 1,
123
- source: "zigbee-herdsman@0.13.65",
124
- internal: {
125
- date: "2021-03-03T19:15:40.524Z",
126
- znpVersion: 2,
127
- },
128
- },
129
- stack_specific: {
130
- zstack: {
131
- tclk_seed: "928a2c479e72a9a53e3b5133fc55021f",
132
- },
133
- },
134
- coordinator_ieee: "00124b0009d80ba7",
135
- pan_id: "007b",
136
- extended_pan_id: "00124b0009d69f77",
137
- nwk_update_id: 0,
138
- security_level: 5,
139
- channel: 21,
140
- channel_mask: [21],
141
- network_key: {
142
- key: "01030507090b0d0f00020406080a0c0d",
143
- sequence_number: 0,
144
- frame_counter: 16754,
145
- },
146
- devices: [
147
- {
148
- nwk_address: "ddf6",
149
- ieee_address: "00124b002226ef87",
150
- },
151
- {
152
- nwk_address: "c2dc",
153
- ieee_address: "04cf8cdf3c79455f",
154
- link_key: {
155
- key: "0e768569dd935d8e7302e74e7629f13f",
156
- rx_counter: 0,
157
- tx_counter: 275,
158
- },
159
- },
160
- {
161
- nwk_address: "740a",
162
- ieee_address: "680ae2fffeae5647",
163
- link_key: {
164
- key: "7c079d02aae015facd7ae9608d4baf56",
165
- rx_counter: 0,
166
- tx_counter: 275,
167
- },
168
- },
169
- {
170
- nwk_address: "19fa",
171
- ieee_address: "00158d00024fa79b",
172
- link_key: {
173
- key: "cea550908aa1529ee90eea3c3bdc26fc",
174
- rx_counter: 0,
175
- tx_counter: 44,
176
- },
177
- },
178
- {
179
- nwk_address: "6182",
180
- ieee_address: "00158d00024f4518",
181
- link_key: {
182
- key: "267e1e31fcd8171f8acf63459effbca5",
183
- rx_counter: 0,
184
- tx_counter: 44,
185
- },
186
- },
187
- {
188
- nwk_address: "4285",
189
- ieee_address: "00158d00024f810d",
190
- is_child: false,
191
- link_key: {
192
- key: "55ba1e31fcd8171f9f0b63459effbca5",
193
- rx_counter: 0,
194
- tx_counter: 44,
195
- },
196
- },
197
- {
198
- // "nwk_address": "4286", commented because `nwk_address` is optional in the backup
199
- ieee_address: "00158d00024f810e",
200
- is_child: true,
201
- link_key: {
202
- key: "55ba1e31fcd8171fee0b63459effeea5",
203
- rx_counter: 24,
204
- tx_counter: 91,
205
- },
206
- },
207
- ],
208
- };
209
-
210
- const backupMatchingConfig12 = {
211
- metadata: {
212
- format: "zigpy/open-coordinator-backup",
213
- version: 1,
214
- source: "zigbee-herdsman@0.13.65",
215
- internal: {
216
- date: "2021-03-03T19:15:40.524Z",
217
- znpVersion: 0,
218
- },
219
- },
220
- stack_specific: {
221
- zstack: {},
222
- },
223
- coordinator_ieee: "00124b0009d80ba7",
224
- pan_id: "007b",
225
- extended_pan_id: "00124b0009d69f77",
226
- nwk_update_id: 0,
227
- security_level: 5,
228
- channel: 21,
229
- channel_mask: [21],
230
- network_key: {
231
- key: "01030507090b0d0f00020406080a0c0d",
232
- sequence_number: 0,
233
- frame_counter: 0,
234
- },
235
- devices: [
236
- {
237
- nwk_address: "ddf6",
238
- ieee_address: "00124b002226ef87",
239
- },
240
- ],
241
- };
242
-
243
- const backupNotMatchingConfig = {
244
- metadata: {
245
- format: "zigpy/open-coordinator-backup",
246
- version: 1,
247
- source: "zigbee-herdsman@0.13.65",
248
- internal: {
249
- date: "2021-03-03T19:15:40.524Z",
250
- znpVersion: 2,
251
- },
252
- },
253
- stack_specific: {
254
- zstack: {
255
- tclk_seed: "928a2c479e72a9a53e3b5133fc55021f",
256
- },
257
- },
258
- coordinator_ieee: "00124b0009d80ba7",
259
- pan_id: "007c",
260
- extended_pan_id: "00124b0009d69f77",
261
- nwk_update_id: 0,
262
- security_level: 5,
263
- channel: 21,
264
- channel_mask: [21],
265
- network_key: {
266
- key: "01030507090b0d0f00020406080a0c0d",
267
- sequence_number: 0,
268
- frame_counter: 16754,
269
- },
270
- devices: [
271
- {
272
- nwk_address: "ddf6",
273
- ieee_address: "00124b002226ef87",
274
- },
275
- {
276
- nwk_address: "c2dc",
277
- ieee_address: "04cf8cdf3c79455f",
278
- link_key: {
279
- key: "0e768569dd935d8e7302e74e7629f13f",
280
- rx_counter: 0,
281
- tx_counter: 275,
282
- },
283
- },
284
- {
285
- nwk_address: "740a",
286
- ieee_address: "680ae2fffeae5647",
287
- link_key: {
288
- key: "7c079d02aae015facd7ae9608d4baf56",
289
- rx_counter: 0,
290
- tx_counter: 275,
291
- },
292
- },
293
- {
294
- nwk_address: "19fa",
295
- ieee_address: "00158d00024fa79b",
296
- link_key: {
297
- key: "cea550908aa1529ee90eea3c3bdc26fc",
298
- rx_counter: 0,
299
- tx_counter: 44,
300
- },
301
- },
302
- {
303
- nwk_address: "6182",
304
- ieee_address: "00158d00024f4518",
305
- link_key: {
306
- key: "267e1e31fcd8171f8acf63459effbca5",
307
- rx_counter: 0,
308
- tx_counter: 44,
309
- },
310
- },
311
- {
312
- nwk_address: "4285",
313
- ieee_address: "00158d00024f810d",
314
- link_key: {
315
- key: "55ba1e31fcd8171f9f0b63459effbca5",
316
- rx_counter: 0,
317
- tx_counter: 44,
318
- },
319
- },
320
- ],
321
- };
322
-
323
- const legacyBackup = {
324
- adapterType: "zStack",
325
- time: "Thu, 04 Mar 2021 10:55:12 GMT",
326
- meta: {
327
- product: 2,
328
- },
329
- data: {
330
- ZCD_NV_EXTADDR: {
331
- id: 1,
332
- offset: 0,
333
- osal: true,
334
- product: -1,
335
- value: [167, 11, 216, 9, 0, 75, 18, 0],
336
- len: 8,
337
- },
338
- ZCD_NV_NIB: {
339
- id: 33,
340
- offset: 0,
341
- osal: true,
342
- product: -1,
343
- value: [
344
- 145, 5, 2, 16, 20, 16, 0, 20, 0, 0, 0, 1, 5, 1, 143, 7, 0, 2, 5, 30, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 8, 0, 0, 32, 0,
345
- 15, 15, 4, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 119, 159, 214, 9, 0, 75, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
346
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 3, 0, 1, 120, 10, 1, 0, 0, 146, 235, 0,
347
- ],
348
- len: 110,
349
- },
350
- ZCD_NV_PANID: {
351
- id: 131,
352
- offset: 0,
353
- osal: true,
354
- product: -1,
355
- value: [123, 0],
356
- len: 2,
357
- },
358
- ZCD_NV_EXTENDED_PAN_ID: {
359
- id: 45,
360
- offset: 0,
361
- osal: true,
362
- product: -1,
363
- value: [221, 221, 221, 221, 221, 221, 221, 221],
364
- len: 8,
365
- },
366
- ZCD_NV_NWK_ACTIVE_KEY_INFO: {
367
- id: 58,
368
- offset: 0,
369
- osal: true,
370
- product: -1,
371
- value: [0, 1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
372
- len: 17,
373
- },
374
- ZCD_NV_NWK_ALTERN_KEY_INFO: {
375
- id: 59,
376
- offset: 0,
377
- osal: true,
378
- product: -1,
379
- value: [0, 1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
380
- len: 17,
381
- },
382
- ZCD_NV_APS_USE_EXT_PANID: {
383
- id: 71,
384
- offset: 0,
385
- osal: true,
386
- product: -1,
387
- value: [0, 0, 0, 0, 0, 0, 0, 0],
388
- len: 8,
389
- },
390
- ZCD_NV_PRECFGKEY: {
391
- id: 98,
392
- offset: 0,
393
- osal: true,
394
- product: -1,
395
- value: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13],
396
- len: 16,
397
- },
398
- ZCD_NV_PRECFGKEY_ENABLE: {
399
- id: 99,
400
- offset: 0,
401
- osal: true,
402
- product: -1,
403
- value: [0],
404
- len: 1,
405
- },
406
- ZCD_NV_CHANLIST: {
407
- id: 132,
408
- offset: 0,
409
- osal: true,
410
- product: -1,
411
- value: [0, 20, 0, 0],
412
- len: 4,
413
- },
414
- ZCD_NV_LEGACY_TCLK_TABLE_START: {
415
- id: 273,
416
- product: 2,
417
- offset: 0,
418
- osal: true,
419
- value: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0],
420
- len: 19,
421
- },
422
- ZCD_NV_LEGACY_NWK_SEC_MATERIAL_TABLE_START: {
423
- id: 117,
424
- product: 2,
425
- offset: 0,
426
- osal: true,
427
- value: [83, 144, 14, 0, 134, 114, 56, 25, 0, 75, 18, 0],
428
- len: 12,
429
- },
430
- },
431
- };
432
-
433
- class ZnpRequestMockBuilder {
434
- // biome-ignore lint/suspicious/noExplicitAny: API
435
- public responders: {subsystem: Subsystem; command: string; exec: (payload: any, handler?: ZnpRequestMockBuilder) => any}[] = [];
436
- public nvItems: {id: NvItemsIds; value?: Buffer}[] = [];
437
- public nvExtendedItems: {sysId: NvSystemIds; id: NvItemsIds; subId: number; value?: Buffer}[] = [];
438
-
439
- constructor() {
440
- const handleOsalNvRead = (payload, handler) => {
441
- if (payload.offset !== undefined && payload.offset !== 0) {
442
- throw new Error("osalNvLength offset not supported");
443
- }
444
- const item = handler.nvItems.find((e) => e.id === payload.id);
445
- return {payload: {status: item?.value ? 0 : 1, value: item?.value ? item.value : undefined}};
446
- };
447
- this.handle(Subsystem.SYS, "osalNvRead", handleOsalNvRead);
448
- this.handle(Subsystem.SYS, "osalNvReadExt", handleOsalNvRead);
449
-
450
- const handleOsalNvWrite = (payload, handler) => {
451
- if (payload.offset !== undefined && payload.offset !== 0) {
452
- throw new Error("osalNvLength offset not supported");
453
- }
454
- const item = handler.nvItems.find((e) => e.id === payload.id);
455
- if (item) {
456
- item.value = payload.value;
457
- return {payload: {status: 0}};
458
- }
459
-
460
- return {payload: {status: 1}};
461
- };
462
- this.handle(Subsystem.SYS, "osalNvWrite", handleOsalNvWrite);
463
- this.handle(Subsystem.SYS, "osalNvWriteExt", handleOsalNvWrite);
464
-
465
- this.handle(Subsystem.SYS, "osalNvItemInit", (payload, handler) => {
466
- let item = handler.nvItems.find((e) => e.id === payload.id);
467
- if (item) {
468
- if (item.value && item.value.length !== payload.len) {
469
- return {payload: {status: 0x0a}};
470
- }
471
- return {payload: {status: 0x00}};
472
- }
473
-
474
- item = {
475
- id: payload.id,
476
- value: payload.initvalue || null,
477
- };
478
- handler.nvItems.push(item);
479
- return {payload: {status: 0x09}};
480
- });
481
- this.handle(Subsystem.SYS, "osalNvLength", (payload, handler) => {
482
- if (payload.offset !== undefined && payload.offset !== 0) {
483
- throw new Error("osalNvLength offset not supported");
484
- }
485
- const item = handler.nvItems.find((e) => e.id === payload.id);
486
- return {payload: {length: item?.value ? item.value.length : 0}};
487
- });
488
- this.handle(Subsystem.SYS, "osalNvDelete", (payload, handler) => {
489
- const item = handler.nvItems.find((e) => e.id === payload.id);
490
- if (item) {
491
- if (item.value && item.value.length !== payload.len) {
492
- return {payload: {status: 0x0a}};
493
- }
494
- const itemIndex = handler.nvItems.indexOf(item);
495
- handler.nvItems.splice(itemIndex, 1);
496
- return {payload: {status: 0x00}};
497
- }
498
-
499
- return {payload: {status: 0x09}};
500
- });
501
-
502
- this.handle(Subsystem.SYS, "nvRead", (payload, handler: ZnpRequestMockBuilder) => {
503
- if (payload.offset !== undefined && payload.offset !== 0) {
504
- throw new Error("nvRead offset not supported");
505
- }
506
- const item = handler.nvExtendedItems.find((e) => e.sysId === payload.sysid && e.id === payload.itemid && e.subId === payload.subid);
507
- return {
508
- payload: {
509
- status: item?.value ? 0 : 1,
510
- value: item?.value ? item.value : undefined,
511
- len: item?.value?.length || undefined,
512
- },
513
- };
514
- });
515
-
516
- this.handle(Subsystem.SYS, "nvWrite", (payload, handler: ZnpRequestMockBuilder) => {
517
- if (payload.offset !== undefined && payload.offset !== 0) {
518
- throw new Error("nwWrite offset not supported");
519
- }
520
- const item = handler.nvExtendedItems.find((e) => e.sysId === payload.sysid && e.id === payload.itemid && e.subId === payload.subid);
521
- if (item) {
522
- item.value = payload.value;
523
- return {payload: {status: 0}};
524
- }
525
-
526
- return {payload: {status: 1}};
527
- });
528
-
529
- this.handle(Subsystem.SYS, "nvCreate", (payload, handler: ZnpRequestMockBuilder) => {
530
- let item = handler.nvExtendedItems.find((e) => e.sysId === payload.sysid && e.id === payload.itemid && e.subId === payload.subid);
531
- if (item) {
532
- if (item.value && item.value.length !== payload.len) {
533
- return {payload: {status: 0x0a}};
534
- }
535
- return {payload: {status: 0x00}};
536
- }
537
-
538
- item = {
539
- sysId: payload.sysid,
540
- id: payload.itemid,
541
- subId: payload.subid,
542
- value: null,
543
- };
544
- handler.nvExtendedItems.push(item);
545
- return {payload: {status: 0x09}};
546
- });
547
- this.handle(Subsystem.SYS, "nvLength", (payload, handler) => {
548
- if (payload.offset !== undefined && payload.offset !== 0) {
549
- throw new Error("nvLength offset not supported");
550
- }
551
- const item = handler.nvExtendedItems.find((e) => e.sysId === payload.sysid && e.id === payload.itemid && e.subId === payload.subid);
552
- return {payload: {len: item?.value ? item.value.length : 0}};
553
- });
554
- this.handle(Subsystem.SYS, "nvDelete", (payload, handler) => {
555
- const item = handler.nvExtendedItems.find((e) => e.sysId === payload.sysid && e.id === payload.itemid && e.subId === payload.subid);
556
- if (item) {
557
- if (item.value && item.value.length !== payload.len) {
558
- return {payload: {status: 0x0a}};
559
- }
560
- const itemIndex = handler.nvItems.indexOf(item);
561
- handler.nvItems.splice(itemIndex, 1);
562
- return {payload: {status: 0x00}};
563
- }
564
-
565
- return {payload: {status: 0x09}};
566
- });
567
- }
568
-
569
- // biome-ignore lint/suspicious/noExplicitAny: API
570
- public handle(subsystem: Subsystem, command: string, exec?: (payload: any, handler?: ZnpRequestMockBuilder) => any) {
571
- const index = this.responders.findIndex((r) => r.subsystem === subsystem && r.command === command);
572
- if (index > -1) {
573
- this.responders.splice(index, 1);
574
- }
575
- this.responders.push({subsystem, command, exec: exec || (() => ({}))});
576
- return this;
577
- }
578
-
579
- public nv(id: NvItemsIds, value?: Buffer) {
580
- const index = this.nvItems.findIndex((e) => e.id === id);
581
- if (index > -1) {
582
- this.nvItems.splice(index, 1);
583
- }
584
- if (value) {
585
- this.nvItems.push({id, value: value || null});
586
- }
587
- return this;
588
- }
589
-
590
- public nvExtended(sysId: NvSystemIds, id: NvItemsIds, subId: number, value?: Buffer) {
591
- const index = this.nvExtendedItems.findIndex((e) => e.sysId === sysId && e.id === id && e.subId === subId);
592
- if (index > -1) {
593
- this.nvExtendedItems.splice(index, 1);
594
- }
595
- if (value) {
596
- this.nvExtendedItems.push({sysId, id, subId, value: value || null});
597
- }
598
- return this;
599
- }
600
-
601
- // biome-ignore lint/suspicious/noExplicitAny: API
602
- public execute(message: {subsystem: Subsystem; command: string; payload: any}) {
603
- const responder = this.responders.find((r) => r.subsystem === message.subsystem && r.command === message.command);
604
- if (!responder) {
605
- const msg = `Not implemented - ${Subsystem[message.subsystem]} - ${message.command} - ${JSON.stringify(message.payload)}`;
606
- console.log(msg);
607
- throw new Error(msg);
608
- }
609
- const response = responder.exec(message.payload, this);
610
- return response;
611
- }
612
-
613
- public clone(): ZnpRequestMockBuilder {
614
- const newBuilder = new ZnpRequestMockBuilder();
615
- newBuilder.responders = this.responders.map((responder) => ({...responder}));
616
- newBuilder.nvItems = this.nvItems.map((item) => ({...item, value: Buffer.from(item.value)}));
617
- newBuilder.nvExtendedItems = this.nvExtendedItems.map((item) => ({...item, value: Buffer.from(item.value)}));
618
- return newBuilder;
619
- }
620
- }
621
-
622
- const baseZnpRequestMock = new ZnpRequestMockBuilder()
623
- .handle(Subsystem.SYS, "version", (payload) => (equals(payload, {}) ? {payload: {product: ZnpVersion.ZStack30x, revision: 20201026}} : undefined))
624
- .handle(Subsystem.SYS, "ping", () => ({}))
625
- .handle(Subsystem.SYS, "resetReq", () => ({}))
626
- .handle(Subsystem.SYS, "getExtAddr", () => ({payload: {extaddress: "0x00124b0009d69f77"}}))
627
- .handle(Subsystem.SYS, "stackTune", () => ({}))
628
- .handle(Subsystem.ZDO, "extFindGroup", () => ({payload: {status: 0}}))
629
- .handle(Subsystem.ZDO, "extAddGroup", () => ({payload: {status: 0}}))
630
- .handle(Subsystem.UTIL, "getDeviceInfo", () => ({payload: {devicestate: 0x00, ieeeaddr: "0x00124b0009d80ba7"}}))
631
- .handle(Subsystem.ZDO, "activeEpReq", () => ({}))
632
- .handle(Subsystem.ZDO, "simpleDescReq", () => ({}))
633
- .handle(Subsystem.ZDO, "mgmtPermitJoinReq", () => ({}))
634
- .handle(Subsystem.ZDO, "nodeDescReq", () => ({}))
635
- .handle(Subsystem.ZDO, "bindReq", () => ({}))
636
- .handle(Subsystem.ZDO, "unbindReq", () => ({}))
637
- .handle(Subsystem.ZDO, "mgmtLeaveReq", () => ({}))
638
- .handle(Subsystem.ZDO, "mgmtLqiReq", () => ({}))
639
- .handle(Subsystem.ZDO, "mgmtRtgReq", () => ({}))
640
- .handle(Subsystem.ZDO, "mgmtNwkUpdateReq", () => ({}))
641
- .handle(Subsystem.AF, "interPanCtl", () => ({}))
642
- .handle(Subsystem.ZDO, "extRouteDisc", () => ({}))
643
- .handle(Subsystem.ZDO, "nwkAddrReq", () => ({}))
644
- .handle(Subsystem.UTIL, "assocRemove", () => ({payload: {}}))
645
- .handle(Subsystem.UTIL, "assocGetWithAddress", () => ({payload: {noderelation: assocGetWithAddressNodeRelation}}))
646
- .handle(Subsystem.UTIL, "assocAdd", () => ({payload: {}}))
647
- .handle(Subsystem.UTIL, "ledControl", () => ({}))
648
- .handle(Subsystem.APP_CNF, "bdbAddInstallCode", () => ({}))
649
- .handle(Subsystem.AF, "register", () => ({}))
650
- .handle(Subsystem.AF, "dataRequest", () => {
651
- if (dataRequestCode !== 0) {
652
- throw new Error(`Data request failed with code '${dataRequestCode}'`);
653
- }
654
- return {};
655
- })
656
- .handle(Subsystem.AF, "dataRequestExt", () => {
657
- if (dataRequestExtCode !== 0) {
658
- throw new Error(`Data request failed with code '${dataRequestExtCode}'`);
659
- }
660
- return {};
661
- })
662
- .handle(Subsystem.SYS, "resetReq", () => ({}))
663
- .handle(Subsystem.APP_CNF, "bdbSetChannel", () => ({}))
664
- .handle(Subsystem.APP_CNF, "bdbStartCommissioning", (_, handler) => {
665
- const nibIndex = handler.nvItems.findIndex((e) => e.id === NvItemsIds.NIB);
666
- if (nibIndex > -1) {
667
- handler.nvItems.splice(nibIndex, 1);
668
- }
669
- handler.nvItems.push({
670
- id: NvItemsIds.NIB,
671
- value: Buffer.from(
672
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000007b000800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
673
- "hex",
674
- ),
675
- });
676
- return {};
677
- })
678
- .handle(Subsystem.ZDO, "extNwkInfo", (_, handler) => {
679
- const nib = Structs.nib(handler.nvItems.find((item) => item.id === NvItemsIds.NIB).value);
680
- return {payload: {panid: nib.nwkPanId, extendedpanid: `0x${nib.extendedPANID.toString("hex")}`, channel: nib.nwkLogicalChannel}};
681
- })
682
- .handle(Subsystem.ZDO, "startupFromApp", () => ({}))
683
- .nv(NvItemsIds.CHANLIST, Buffer.from([0, 8, 0, 0]))
684
- .nv(NvItemsIds.PRECFGKEY, Buffer.alloc(16, 0))
685
- .nv(NvItemsIds.PRECFGKEYS_ENABLE, Buffer.from([0]))
686
- .nv(NvItemsIds.NWKKEY, Buffer.alloc(24, 0))
687
- .nv(NvItemsIds.NWK_ACTIVE_KEY_INFO, Buffer.from("000000000000000000000000000000000000", "hex"))
688
- .nv(NvItemsIds.NWK_ALTERN_KEY_INFO, Buffer.from("000000000000000000000000000000000000", "hex"))
689
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x00]))
690
- .nv(
691
- NvItemsIds.NIB,
692
- Buffer.from(
693
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000000bcd0800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
694
- "hex",
695
- ),
696
- );
697
-
698
- const empty3UnalignedRequestMock = baseZnpRequestMock
699
- .clone()
700
- .handle(Subsystem.APP_CNF, "bdbStartCommissioning", (_, handler) => {
701
- const nibIndex = handler.nvItems.findIndex((e) => e.id === NvItemsIds.NIB);
702
- if (nibIndex > -1) {
703
- handler.nvItems.splice(nibIndex, 1);
704
- }
705
- handler.nvItems.push({
706
- id: NvItemsIds.NIB,
707
- value: Buffer.from(
708
- "fb050279147900640000000105018f0700020d1e000015000000000000000000007b0008000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a010000060200",
709
- "hex",
710
- ),
711
- });
712
- return {};
713
- })
714
- .nv(NvItemsIds.NWKKEY, Buffer.alloc(21, 0))
715
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x00]))
716
- .nv(
717
- NvItemsIds.NIB,
718
- Buffer.from(
719
- "fb050279147900640000000105018f0700020d1e00001500000000000000000000ffff08000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a010000060200",
720
- "hex",
721
- ),
722
- )
723
- .nv(
724
- NvItemsIds.ADDRMGR,
725
- Buffer.from(
726
- "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
727
- "hex",
728
- ),
729
- )
730
- .nv(
731
- NvItemsIds.APS_LINK_KEY_TABLE,
732
- Buffer.from(
733
- "0000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000feff000000",
734
- "hex",
735
- ),
736
- );
737
- for (let i = 0; i < 4; i++) {
738
- empty3UnalignedRequestMock.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + i, Buffer.from("000000000000000000000000", "hex"));
739
- }
740
- for (let i = 0; i < 16; i++) {
741
- empty3UnalignedRequestMock.nv(NvItemsIds.LEGACY_TCLK_TABLE_START + i, Buffer.from("00000000000000000000000000000000000000", "hex"));
742
- }
743
- for (let i = 0; i < 16; i++) {
744
- empty3UnalignedRequestMock.nv(NvItemsIds.APS_LINK_KEY_DATA_START + i, Buffer.from("000000000000000000000000000000000000000000000000", "hex"));
745
- }
746
-
747
- const empty3AlignedRequestMock = baseZnpRequestMock
748
- .clone()
749
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x00]))
750
- .nv(
751
- NvItemsIds.NIB,
752
- Buffer.from(
753
- "fb050279147900640000000105018f000700020d1e000000150000000000000000000000ffff0800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
754
- "hex",
755
- ),
756
- )
757
- .nv(
758
- NvItemsIds.ADDRMGR,
759
- Buffer.from(
760
- "00ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff00000000000000000000",
761
- "hex",
762
- ),
763
- )
764
- .nv(
765
- NvItemsIds.APS_LINK_KEY_TABLE,
766
- Buffer.from(
767
- "0000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000",
768
- "hex",
769
- ),
770
- );
771
- for (let i = 0; i < 4; i++) {
772
- empty3AlignedRequestMock.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + i, Buffer.from("000000000000000000000000", "hex"));
773
- }
774
- for (let i = 0; i < 16; i++) {
775
- empty3AlignedRequestMock.nv(NvItemsIds.LEGACY_TCLK_TABLE_START + i, Buffer.from("0000000000000000000000000000000000000000", "hex"));
776
- }
777
- for (let i = 0; i < 16; i++) {
778
- empty3AlignedRequestMock.nv(NvItemsIds.APS_LINK_KEY_DATA_START + i, Buffer.from("000000000000000000000000000000000000000000000000", "hex"));
779
- }
780
-
781
- const commissioned3AlignedRequestMock = empty3AlignedRequestMock
782
- .clone()
783
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x55]))
784
- .nv(NvItemsIds.PRECFGKEY, Buffer.from("01030507090b0d0f00020406080a0c0d", "hex"))
785
- .nv(NvItemsIds.NWK_ACTIVE_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
786
- .nv(NvItemsIds.NWK_ALTERN_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
787
- .nv(
788
- NvItemsIds.NIB,
789
- Buffer.from(
790
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000007b000800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
791
- "hex",
792
- ),
793
- )
794
- .nv(
795
- NvItemsIds.ADDRMGR,
796
- Buffer.from(
797
- "01ff4f3a080000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff0000000000000000000000ff00000000000000000000",
798
- "hex",
799
- ),
800
- );
801
-
802
- const commissioned3AlignedConfigMistmachRequestMock = commissioned3AlignedRequestMock
803
- .clone()
804
- .nv(NvItemsIds.NWK_ACTIVE_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
805
- .nv(NvItemsIds.NWK_ALTERN_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
806
- .nv(
807
- NvItemsIds.NIB,
808
- Buffer.from(
809
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000007e000800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
810
- "hex",
811
- ),
812
- );
813
-
814
- const empty3x0AlignedRequestMock = baseZnpRequestMock
815
- .clone()
816
- .handle(Subsystem.SYS, "version", (payload) => (equals(payload, {}) ? {payload: {product: ZnpVersion.ZStack3x0, revision: 20210430}} : undefined))
817
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x00]))
818
- .nv(
819
- NvItemsIds.NIB,
820
- Buffer.from(
821
- "fb050279147900640000000105018f000700020d1e000000150000000000000000000000ffff0800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
822
- "hex",
823
- ),
824
- )
825
- .nv(
826
- NvItemsIds.APS_LINK_KEY_TABLE,
827
- Buffer.from(
828
- "0000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000feff00000000",
829
- "hex",
830
- ),
831
- );
832
- for (let i = 0; i < 16; i++) {
833
- empty3x0AlignedRequestMock.nvExtended(NvSystemIds.ZSTACK, NvItemsIds.ZCD_NV_EX_ADDRMGR, i, Buffer.from("00ff00000000000000000000", "hex"));
834
- }
835
- for (let i = 0; i < 4; i++) {
836
- empty3x0AlignedRequestMock.nvExtended(
837
- NvSystemIds.ZSTACK,
838
- NvItemsIds.EX_NWK_SEC_MATERIAL_TABLE,
839
- i,
840
- Buffer.from("000000000000000000000000", "hex"),
841
- );
842
- }
843
- for (let i = 0; i < 16; i++) {
844
- empty3x0AlignedRequestMock.nvExtended(
845
- NvSystemIds.ZSTACK,
846
- NvItemsIds.EX_TCLK_TABLE,
847
- i,
848
- Buffer.from("0000000000000000000000000000000000000000", "hex"),
849
- );
850
- }
851
- for (let i = 0; i < 16; i++) {
852
- empty3x0AlignedRequestMock.nvExtended(
853
- NvSystemIds.ZSTACK,
854
- NvItemsIds.ZCD_NV_EX_APS_KEY_DATA_TABLE,
855
- i,
856
- Buffer.from("000000000000000000000000000000000000000000000000", "hex"),
857
- );
858
- }
859
-
860
- const commissioned3x0AlignedRequestMock = empty3x0AlignedRequestMock
861
- .clone()
862
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK3, Buffer.from([0x55]))
863
- .nv(NvItemsIds.PRECFGKEY, Buffer.from("01030507090b0d0f00020406080a0c0d", "hex"))
864
- .nv(NvItemsIds.NWK_ACTIVE_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
865
- .nv(NvItemsIds.NWK_ALTERN_KEY_INFO, Buffer.from("0001030507090b0d0f00020406080a0c0d00", "hex"))
866
- .nv(
867
- NvItemsIds.NIB,
868
- Buffer.from(
869
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000007b000800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
870
- "hex",
871
- ),
872
- )
873
- .nvExtended(NvSystemIds.ZSTACK, NvItemsIds.ZCD_NV_EX_ADDRMGR, 0, Buffer.from("01ff4f3a0800000000000000", "hex"));
874
-
875
- const empty12UnalignedRequestMock = baseZnpRequestMock
876
- .clone()
877
- .handle(Subsystem.SYS, "version", (payload) => (equals(payload, {}) ? {payload: {product: ZnpVersion.ZStack12}} : undefined))
878
- .handle(Subsystem.SAPI, "readConfiguration", (payload, handler) => {
879
- if (payload.configid !== NvItemsIds.PRECFGKEY) {
880
- throw new Error("Only pre-configured key should be read/written using SAPI layer");
881
- }
882
- const item = handler.nvItems.find((item) => item.id === payload.configid);
883
- if (item) {
884
- return {payload: {status: 0, configid: item.id, len: item.value?.length || 0, value: item.value}};
885
- }
886
- return {payload: {status: 1}};
887
- })
888
- .handle(Subsystem.SAPI, "writeConfiguration", (payload, handler) => {
889
- if (payload.configid !== NvItemsIds.PRECFGKEY) {
890
- throw new Error("Only pre-configured key should be read/written using SAPI layer");
891
- }
892
- const item = handler.nvItems.find((item) => item.id === payload.configid);
893
- if (item) {
894
- item.value = payload.value;
895
- } else {
896
- handler.nvItems.push({id: payload.configid, value: payload.value});
897
- }
898
- handler.nv(
899
- NvItemsIds.NIB,
900
- Buffer.from(
901
- "fb050279147900640000000105018f0700020d1e000015000000000000000000007b0008000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a010000060200",
902
- "hex",
903
- ),
904
- );
905
- return {payload: {status: 0}};
906
- })
907
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK1, Buffer.from([0x00]));
908
-
909
- const commissioned12UnalignedRequestMock = empty12UnalignedRequestMock
910
- .clone()
911
- .nv(NvItemsIds.ZNP_HAS_CONFIGURED_ZSTACK1, Buffer.from([0x55]))
912
- .nv(NvItemsIds.PRECFGKEY, Buffer.from("01030507090b0d0f00020406080a0c0d", "hex"))
913
- .nv(
914
- NvItemsIds.NIB,
915
- Buffer.from(
916
- "fb050279147900640000000105018f0700020d1e000015000000000000000000007b0008000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a010000060200",
917
- "hex",
918
- ),
919
- );
920
-
921
- const commissioned12UnalignedMismatchRequestMock = commissioned12UnalignedRequestMock
922
- .clone()
923
- .nv(NvItemsIds.PRECFGKEY, Buffer.from("aabb0507090b0d0f00020406080a0c0d", "hex"));
924
-
925
- const mockZnpRequest = vi
926
- .fn()
927
- .mockReturnValue(new Promise((resolve) => resolve({payload: {}})))
928
- .mockImplementation(
929
- // biome-ignore lint/suspicious/noExplicitAny: API
930
- (subsystem: Subsystem, command: string, payload: any, _expectedStatus: ZnpCommandStatus) =>
931
- new Promise((resolve) => resolve(baseZnpRequestMock.execute({subsystem, command, payload}))),
932
- );
933
- const mockZnpRequestZdo = vi.fn();
934
- const mockZnpWaitFor = vi.fn();
935
- const mockZnpOpen = vi.fn();
936
- const mockZnpClose = vi.fn();
937
- const mockQueueExecute = vi.fn().mockImplementation(async (func) => await func());
938
- const mocks = [mockZnpOpen, mockZnpRequest, mockZnpClose];
939
-
940
- const mockZnpRequestWith = (builder: ZnpRequestMockBuilder) => {
941
- builder = builder.clone();
942
- mockZnpRequest.mockImplementation(
943
- // biome-ignore lint/suspicious/noExplicitAny: API
944
- (subsystem: Subsystem, command: string, payload: any, _expectedStatus: ZnpCommandStatus) =>
945
- new Promise((resolve) => resolve(builder.execute({subsystem, command, payload}))),
946
- );
947
- };
948
-
949
- const mockZnpWaitForDefault = () => {
950
- mockZnpWaitFor.mockImplementation((type, subsystem, command, target, transid, state, timeout) => {
951
- const missing = () => {
952
- const msg = `Not implemented - ${Type[type]} - ${Subsystem[subsystem]} - ${command} - ${target} - ${transid} - ${state} - ${timeout}`;
953
- console.log(msg);
954
- throw new Error(msg);
955
- };
956
-
957
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "activeEpRsp") {
958
- return waitForResult(
959
- mockZdoZpiObject<ActiveEndpointsResponse>("activeEpRsp", target, [
960
- Zdo.Status.SUCCESS,
961
- {
962
- nwkAddress: 0,
963
- endpointList: [],
964
- },
965
- ]),
966
- );
967
- }
968
-
969
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtPermitJoinRsp") {
970
- return waitForResult(mockZdoZpiObject("mgmtPermitJoinRsp", target, [Zdo.Status.SUCCESS, undefined]));
971
- }
972
-
973
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "stateChangeInd") {
974
- return waitForResult({payload: {state: 9}});
975
- }
976
-
977
- missing();
978
- });
979
- };
980
-
981
- const mockZnpWaitForStateChangeIndTimeout = () => {
982
- mockZnpWaitFor.mockImplementation((type, subsystem, command, target, transid, state, timeout) => {
983
- const missing = () => {
984
- const msg = `Not implemented - ${Type[type]} - ${Subsystem[subsystem]} - ${command} - ${target} - ${transid} - ${state} - ${timeout}`;
985
- console.log(msg);
986
- throw new Error(msg);
987
- };
988
-
989
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "activeEpRsp") {
990
- return waitForResult(
991
- mockZdoZpiObject<ActiveEndpointsResponse>("activeEpRsp", target, [
992
- Zdo.Status.SUCCESS,
993
- {
994
- nwkAddress: 0,
995
- endpointList: [],
996
- },
997
- ]),
998
- );
999
- }
1000
-
1001
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "stateChangeInd") {
1002
- return;
1003
- }
1004
-
1005
- missing();
1006
- });
1007
- };
1008
-
1009
- let bindStatusResponse = 0;
1010
-
1011
- const mockZdoZpiObject = <T>(commandName: string, srcaddr: number | undefined, payload: [Zdo.Status, T | undefined]): ZpiObject => {
1012
- const subsystem = Subsystem.ZDO;
1013
- const command = Definition[subsystem].find((c) => c.name === commandName)!;
1014
- return {
1015
- type: Type.AREQ,
1016
- subsystem,
1017
- command,
1018
- payload: {srcaddr, zdo: payload},
1019
- };
1020
- };
1021
-
1022
- const mockZpiObject = (type: Type, subsystem: Subsystem, commandName: string, payload: {[s: string]: unknown}) => {
1023
- const command = Definition[subsystem].find((c) => c.name === commandName);
1024
- return {type, subsystem, payload, command};
1025
- };
1026
-
1027
- const basicMocks = () => {
1028
- mockZnpRequestWith(commissioned3x0AlignedRequestMock);
1029
- mockZnpWaitFor.mockImplementation((type, subsystem, command, target, transid, state, timeout) => {
1030
- const missing = () => {
1031
- const msg = `Not implemented - ${Type[type]} - ${Subsystem[subsystem]} - ${command} - ${target} - ${transid} - ${state} - ${timeout}`;
1032
- console.log(msg);
1033
- throw new Error(msg);
1034
- };
1035
-
1036
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "activeEpRsp") {
1037
- return waitForResult(
1038
- mockZdoZpiObject<ActiveEndpointsResponse>("activeEpRsp", target, [
1039
- Zdo.Status.SUCCESS,
1040
- {
1041
- nwkAddress: 0,
1042
- endpointList: [1, 2, 3, 4, 5, 6, 8, 10, 11, 110, 12, 13, 47, 242],
1043
- },
1044
- ]),
1045
- );
1046
- }
1047
-
1048
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "stateChangeInd") {
1049
- return waitForResult({payload: {}});
1050
- }
1051
-
1052
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtPermitJoinRsp") {
1053
- return waitForResult(mockZdoZpiObject("mgmtPermitJoinRsp", target, [Zdo.Status.SUCCESS, undefined]));
1054
- }
1055
-
1056
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "simpleDescRsp") {
1057
- let responsePayload: SimpleDescriptorResponse;
1058
- if (simpleDescriptorEndpoint === 1) {
1059
- responsePayload = {
1060
- length: 1, // bogus
1061
- endpoint: 1,
1062
- profileId: 123,
1063
- deviceId: 5,
1064
- inClusterList: [1],
1065
- outClusterList: [2],
1066
- nwkAddress: target,
1067
- deviceVersion: 0,
1068
- };
1069
- } else if (simpleDescriptorEndpoint === 99) {
1070
- responsePayload = {
1071
- length: 1, // bogus
1072
- endpoint: 99,
1073
- profileId: 123,
1074
- deviceId: 5,
1075
- inClusterList: [1],
1076
- outClusterList: [2],
1077
- nwkAddress: target,
1078
- deviceVersion: 0,
1079
- };
1080
- } else {
1081
- responsePayload = {
1082
- length: 1, // bogus
1083
- endpoint: simpleDescriptorEndpoint,
1084
- profileId: 124,
1085
- deviceId: 7,
1086
- inClusterList: [8],
1087
- outClusterList: [9],
1088
- nwkAddress: target,
1089
- deviceVersion: 0,
1090
- };
1091
- }
1092
-
1093
- return waitForResult(mockZdoZpiObject<SimpleDescriptorResponse>("simpleDescRsp", target, [Zdo.Status.SUCCESS, responsePayload]));
1094
- }
1095
-
1096
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "nodeDescRsp") {
1097
- if (nodeDescRspErrorOnce) {
1098
- nodeDescRspErrorOnce = false;
1099
- return {
1100
- start: () => {
1101
- return {
1102
- promise: new Promise((_resolve, reject) => {
1103
- reject("timeout after xx");
1104
- }),
1105
- };
1106
- },
1107
- ID: 89,
1108
- };
1109
- }
1110
-
1111
- return waitForResult(
1112
- mockZdoZpiObject<NodeDescriptorResponse>("nodeDescRsp", target, [
1113
- Zdo.Status.SUCCESS,
1114
- {
1115
- manufacturerCode: target * 2,
1116
- apsFlags: 0,
1117
- capabilities: DUMMY_NODE_DESC_RSP_CAPABILITIES,
1118
- deprecated1: 0,
1119
- fragmentationSupported: true,
1120
- frequencyBand: 0,
1121
- logicalType: target - 1,
1122
- maxBufSize: 0,
1123
- maxIncTxSize: 0,
1124
- maxOutTxSize: 0,
1125
- nwkAddress: target,
1126
- serverMask: {
1127
- backupTrustCenter: 0,
1128
- deprecated1: 0,
1129
- deprecated2: 0,
1130
- deprecated3: 0,
1131
- deprecated4: 0,
1132
- networkManager: 0,
1133
- primaryTrustCenter: 0,
1134
- reserved1: 0,
1135
- reserved2: 0,
1136
- stackComplianceRevision: 0,
1137
- },
1138
- tlvs: [],
1139
- },
1140
- ]),
1141
- );
1142
- }
1143
-
1144
- if (type === Type.AREQ && subsystem === Subsystem.AF && command === "dataConfirm") {
1145
- const status = dataConfirmCode;
1146
- if (dataConfirmCodeReset) {
1147
- dataConfirmCode = 0;
1148
- }
1149
-
1150
- if (status === 9999) {
1151
- return {
1152
- start: () => {
1153
- return {
1154
- promise: new Promise((_resolve, reject) => {
1155
- reject("timeout after xx");
1156
- }),
1157
- };
1158
- },
1159
- ID: 99,
1160
- };
1161
- }
1162
-
1163
- return waitForResult({payload: {status}}, 99);
1164
- }
1165
-
1166
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtLqiRsp" && target === 203) {
1167
- const defaults = {deviceType: 0, extendedPanId: [0], permitJoining: 0, reserved1: 0, reserved2: 0, rxOnWhenIdle: 0};
1168
-
1169
- if (lastStartIndex === 0) {
1170
- lastStartIndex += 2;
1171
- return waitForResult(
1172
- mockZdoZpiObject<LQITableResponse>("mgmtLqiRsp", target, [
1173
- Zdo.Status.SUCCESS,
1174
- {
1175
- neighborTableEntries: 5,
1176
- startIndex: 0,
1177
- entryList: [
1178
- {lqi: 10, nwkAddress: 2, eui64: "0x3", relationship: 3, depth: 1, ...defaults},
1179
- {lqi: 15, nwkAddress: 3, eui64: "0x4", relationship: 2, depth: 5, ...defaults},
1180
- ],
1181
- },
1182
- ]),
1183
- );
1184
- }
1185
-
1186
- if (lastStartIndex === 2) {
1187
- lastStartIndex += 2;
1188
- return waitForResult(
1189
- mockZdoZpiObject<LQITableResponse>("mgmtLqiRsp", target, [
1190
- Zdo.Status.SUCCESS,
1191
- {
1192
- neighborTableEntries: 5,
1193
- startIndex: 0,
1194
- entryList: [
1195
- {lqi: 10, nwkAddress: 5, eui64: "0x6", relationship: 3, depth: 1, ...defaults},
1196
- {lqi: 15, nwkAddress: 7, eui64: "0x8", relationship: 2, depth: 5, ...defaults},
1197
- ],
1198
- },
1199
- ]),
1200
- );
1201
- }
1202
-
1203
- if (lastStartIndex === 4) {
1204
- return waitForResult(
1205
- mockZdoZpiObject<LQITableResponse>("mgmtLqiRsp", target, [
1206
- Zdo.Status.SUCCESS,
1207
- {
1208
- neighborTableEntries: 5,
1209
- startIndex: 0,
1210
- entryList: [{lqi: 10, nwkAddress: 9, eui64: "0x10", relationship: 3, depth: 1, ...defaults}],
1211
- },
1212
- ]),
1213
- );
1214
- }
1215
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtLqiRsp" && target === 204) {
1216
- return waitForResult(mockZdoZpiObject<LQITableResponse>("mgmtLqiRsp", target, [Zdo.Status.NOT_AUTHORIZED, undefined]));
1217
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtRtgRsp" && target === 205) {
1218
- const defaultEntryList = {
1219
- manyToOne: 0,
1220
- memoryConstrained: 0,
1221
- reserved1: 0,
1222
- routeRecordRequired: 0,
1223
- status: Zdo.RoutingTableStatus[0] as keyof typeof Zdo.RoutingTableStatus,
1224
- };
1225
- if (lastStartIndex === 0) {
1226
- lastStartIndex += 2;
1227
- return waitForResult(
1228
- mockZdoZpiObject<RoutingTableResponse>("mgmtRtgRsp", target, [
1229
- Zdo.Status.SUCCESS,
1230
- {
1231
- startIndex: 0,
1232
- routingTableEntries: 5,
1233
- entryList: [
1234
- {destinationAddress: 10, nextHopAddress: 3, ...defaultEntryList},
1235
- {destinationAddress: 11, nextHopAddress: 3, ...defaultEntryList},
1236
- ],
1237
- },
1238
- ]),
1239
- );
1240
- }
1241
-
1242
- if (lastStartIndex === 2) {
1243
- lastStartIndex += 2;
1244
- return waitForResult(
1245
- mockZdoZpiObject<RoutingTableResponse>("mgmtRtgRsp", target, [
1246
- Zdo.Status.SUCCESS,
1247
- {
1248
- startIndex: 0,
1249
- routingTableEntries: 5,
1250
- entryList: [
1251
- {destinationAddress: 12, nextHopAddress: 3, ...defaultEntryList},
1252
- {destinationAddress: 13, nextHopAddress: 3, ...defaultEntryList},
1253
- ],
1254
- },
1255
- ]),
1256
- );
1257
- }
1258
-
1259
- if (lastStartIndex === 4) {
1260
- return waitForResult(
1261
- mockZdoZpiObject<RoutingTableResponse>("mgmtRtgRsp", target, [
1262
- Zdo.Status.SUCCESS,
1263
- {
1264
- startIndex: 0,
1265
- routingTableEntries: 5,
1266
- entryList: [{destinationAddress: 14, nextHopAddress: 3, ...defaultEntryList}],
1267
- },
1268
- ]),
1269
- );
1270
- }
1271
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtRtgRsp" && target === 206) {
1272
- return waitForResult(mockZdoZpiObject<RoutingTableResponse>("mgmtRtgRsp", target, [Zdo.Status.INSUFFICIENT_SPACE, undefined]));
1273
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "bindRsp" && target === 301) {
1274
- return waitForResult(mockZdoZpiObject("bindRsp", target, [bindStatusResponse, undefined]));
1275
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "unbindRsp" && target === 301) {
1276
- return waitForResult(mockZdoZpiObject("unbindRsp", target, [bindStatusResponse, undefined]));
1277
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "mgmtLeaveRsp" && target === 401) {
1278
- return waitForResult(mockZdoZpiObject("mgmtLeaveRsp", target, [Zdo.Status.SUCCESS, undefined]));
1279
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "nwkAddrRsp" && target === "0x03") {
1280
- return waitForResult(
1281
- mockZdoZpiObject<NetworkAddressResponse>("nwkAddrRsp", target, [
1282
- Zdo.Status.SUCCESS,
1283
- {
1284
- nwkAddress: 3,
1285
- eui64: "0x03",
1286
- assocDevList: [],
1287
- startIndex: 0,
1288
- },
1289
- ]),
1290
- );
1291
- } else if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "nwkAddrRsp" && target === "0x02") {
1292
- return waitForResult(
1293
- mockZdoZpiObject<NetworkAddressResponse>("nwkAddrRsp", target, [
1294
- Zdo.Status.SUCCESS,
1295
- {
1296
- nwkAddress: 2,
1297
- eui64: "0x02",
1298
- assocDevList: [],
1299
- startIndex: 0,
1300
- },
1301
- ]),
1302
- );
1303
- } else {
1304
- missing();
1305
- }
1306
- });
1307
- };
1308
-
1309
- const touchlinkScanRequest = Zcl.Frame.create(
1310
- Zcl.FrameType.SPECIFIC,
1311
- Zcl.Direction.CLIENT_TO_SERVER,
1312
- false,
1313
- undefined,
1314
- 12,
1315
- "scanRequest",
1316
- Zcl.Utils.getCluster("touchlink", undefined, {}).ID,
1317
- {transactionID: 1, zigbeeInformation: 4, touchlinkInformation: 18},
1318
- {},
1319
- );
1320
-
1321
- const touchlinkScanResponse = Zcl.Frame.create(
1322
- Zcl.FrameType.SPECIFIC,
1323
- Zcl.Direction.SERVER_TO_CLIENT,
1324
- false,
1325
- undefined,
1326
- 12,
1327
- "scanResponse",
1328
- Zcl.Utils.getCluster("touchlink", undefined, {}).ID,
1329
- {
1330
- transactionID: 1,
1331
- rssiCorrection: 10,
1332
- zigbeeInformation: 5,
1333
- touchlinkInformation: 6,
1334
- keyBitmask: 12,
1335
- responseID: 11,
1336
- extendedPanID: "0x0017210104d9cd33",
1337
- networkUpdateID: 1,
1338
- logicalChannel: 12,
1339
- panID: 13,
1340
- networkAddress: 5,
1341
- numberOfSubDevices: 10,
1342
- totalGroupIdentifiers: 5,
1343
- },
1344
- {},
1345
- );
1346
-
1347
- const touchlinkIdentifyRequest = Zcl.Frame.create(
1348
- Zcl.FrameType.SPECIFIC,
1349
- Zcl.Direction.CLIENT_TO_SERVER,
1350
- false,
1351
- undefined,
1352
- 12,
1353
- "identifyRequest",
1354
- Zcl.Utils.getCluster("touchlink", undefined, {}).ID,
1355
- {transactionID: 1, duration: 65535},
1356
- {},
1357
- );
1358
-
1359
- const getRandomArbitrary = (min, max) => {
1360
- return Math.random() * (max - min) + min;
1361
- };
1362
-
1363
- const getTempFile = () => {
1364
- const tempPath = path.resolve("temp");
1365
- if (!fs.existsSync(tempPath)) {
1366
- fs.mkdirSync(tempPath);
1367
- }
1368
- return path.join(tempPath, `temp_${getRandomArbitrary(1, 99999999)}`);
1369
- };
1370
-
1371
- let znpReceived;
1372
- let znpClose;
1373
- let dataConfirmCode = 0;
1374
- let dataConfirmCodeReset = false;
1375
- let nodeDescRspErrorOnce = false;
1376
- let dataRequestCode = 0;
1377
- let dataRequestExtCode = 0;
1378
- let lastStartIndex = 0;
1379
- let simpleDescriptorEndpoint = 0;
1380
- let assocGetWithAddressNodeRelation;
1381
-
1382
- vi.mock("../../../src/adapter/z-stack/znp/znp", () => ({
1383
- Znp: vi.fn(() => ({
1384
- on: (event, handler) => {
1385
- if (event === "received") {
1386
- znpReceived = handler;
1387
- } else if (event === "close") {
1388
- znpClose = handler;
1389
- }
1390
- },
1391
- open: mockZnpOpen,
1392
- request: mockZnpRequest,
1393
- requestZdo: mockZnpRequestZdo,
1394
- requestWithReply: mockZnpRequest,
1395
- waitFor: mockZnpWaitFor,
1396
- close: mockZnpClose,
1397
- })),
1398
- }));
1399
-
1400
- vi.mock("../../../src/utils/queue", () => ({
1401
- Queue: vi.fn(() => ({
1402
- execute: mockQueueExecute,
1403
- count: () => 1,
1404
- })),
1405
- }));
1406
-
1407
- const mocksClear = [mockLogger.debug, mockLogger.info, mockLogger.warning, mockLogger.error];
1408
-
1409
- describe("zstack-adapter", () => {
1410
- let adapter: ZStackAdapter;
1411
-
1412
- beforeAll(() => {
1413
- setLogger(mockLogger);
1414
- });
1415
-
1416
- afterAll(() => {
1417
- vi.useRealTimers();
1418
- });
1419
-
1420
- beforeEach(() => {
1421
- vi.useRealTimers();
1422
- vi.useFakeTimers();
1423
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {concurrent: 3});
1424
- mockZnpWaitForDefault();
1425
- for (const m of mocks) m.mockRestore();
1426
- for (const m of mocksClear) m.mockClear();
1427
- mockQueueExecute.mockClear();
1428
- mockZnpWaitFor.mockClear();
1429
- dataConfirmCode = 0;
1430
- dataRequestCode = 0;
1431
- dataRequestExtCode = 0;
1432
- bindStatusResponse = 0;
1433
- assocGetWithAddressNodeRelation = 1;
1434
- networkOptions.networkKeyDistribute = false;
1435
- dataConfirmCodeReset = false;
1436
- nodeDescRspErrorOnce = false;
1437
- lastStartIndex = 0;
1438
- simpleDescriptorEndpoint = 0;
1439
- });
1440
-
1441
- it("should commission network with 3.0.x adapter", async () => {
1442
- mockZnpRequestWith(empty3AlignedRequestMock);
1443
- const result = await adapter.start();
1444
- expect(result).toBe("reset");
1445
- });
1446
-
1447
- it("should commission network with 3.0.x adapter - auto concurrency", async () => {
1448
- mockZnpRequestWith(empty3AlignedRequestMock);
1449
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {});
1450
- const result = await adapter.start();
1451
- expect(result).toBe("reset");
1452
- });
1453
-
1454
- it("should commission network with 3.x.0 adapter - auto concurrency", async () => {
1455
- mockZnpRequestWith(empty3x0AlignedRequestMock);
1456
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {});
1457
- const result = await adapter.start();
1458
- expect(result).toBe("reset");
1459
- });
1460
-
1461
- it("should commission network with 3.0.x adapter - unaligned 8-bit", async () => {
1462
- mockZnpRequestWith(empty3UnalignedRequestMock);
1463
- const result = await adapter.start();
1464
- expect(result).toBe("reset");
1465
- });
1466
-
1467
- it("should commission network with 3.0.x adapter - default extended pan id", async () => {
1468
- mockZnpRequestWith(empty3AlignedRequestMock);
1469
- adapter = new ZStackAdapter(networkOptionsDefaultExtendedPanId, serialPortOptions, "backup.json", {concurrent: 3});
1470
- const result = await adapter.start();
1471
- expect(result).toBe("reset");
1472
- });
1473
-
1474
- it("should commission with 3.0.x adapter - empty, mismatched config/backup", async () => {
1475
- const backupFile = getTempFile();
1476
- fs.writeFileSync(backupFile, JSON.stringify(backupNotMatchingConfig), "utf8");
1477
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1478
- mockZnpRequestWith(empty3AlignedRequestMock);
1479
- const result = await adapter.start();
1480
- expect(result).toBe("reset");
1481
- });
1482
-
1483
- it("should commission with 3.0.x adapter - commissioned, mismatched adapter-config-backup", async () => {
1484
- const backupFile = getTempFile();
1485
- fs.writeFileSync(backupFile, JSON.stringify(backupNotMatchingConfig), "utf8");
1486
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1487
- mockZnpRequestWith(commissioned3AlignedConfigMistmachRequestMock);
1488
- const result = await adapter.start();
1489
- expect(result).toBe("reset");
1490
- });
1491
-
1492
- it("should fail to commission network with 3.0.x adapter with invalid pan id 65535", async () => {
1493
- mockZnpRequestWith(empty3AlignedRequestMock);
1494
- adapter = new ZStackAdapter(networkOptionsInvalidPanId, serialPortOptions, "backup.json", {concurrent: 3});
1495
- await expect(adapter.start()).rejects.toThrowError("network commissioning failed - cannot use pan id 65535");
1496
- });
1497
-
1498
- it("should fail to commission network with 3.0.x adapter when bdb commissioning times out", async () => {
1499
- mockZnpWaitForStateChangeIndTimeout();
1500
- mockZnpRequestWith(empty3AlignedRequestMock);
1501
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {concurrent: 3});
1502
- await expect(adapter.start()).rejects.toThrowError(
1503
- "network commissioning timed out - most likely network with the same panId or extendedPanId already exists nearby",
1504
- );
1505
- });
1506
-
1507
- it("should fail to commission network with 3.0.x adapter when nib fails to settle", async () => {
1508
- mockZnpRequestWith(empty3AlignedRequestMock.clone().handle(Subsystem.APP_CNF, "bdbStartCommissioning", () => ({})));
1509
- vi.setConfig({testTimeout: 35000});
1510
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {concurrent: 3});
1511
- const promise = adapter.start();
1512
- await expect(promise).rejects.toThrowError("network commissioning failed - timed out waiting for nib to settle");
1513
- });
1514
-
1515
- it("should fail to commission network with 3.0.x adapter when nib reports different pan id", async () => {
1516
- mockZnpRequestWith(
1517
- empty3AlignedRequestMock.clone().handle(Subsystem.APP_CNF, "bdbStartCommissioning", (_, handler) => {
1518
- const nibIndex = handler.nvItems.findIndex((e) => e.id === NvItemsIds.NIB);
1519
- if (nibIndex > -1) {
1520
- handler.nvItems.splice(nibIndex, 1);
1521
- }
1522
- handler.nvItems.push({
1523
- id: NvItemsIds.NIB,
1524
- value: Buffer.from(
1525
- "fb050279147900640000000105018f000700020d1e0000001500000000000000000000007c000800000020000f0f0400010000000100000000779fd609004b1200010000000000000000000000000000000000000000000000000000000000000000000000003c0c0001780a0100000006020000",
1526
- "hex",
1527
- ),
1528
- });
1529
- return {};
1530
- }),
1531
- );
1532
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {concurrent: 3});
1533
- const promise = adapter.start();
1534
- await expect(promise).rejects.toThrowError("network commissioning failed - panId collision detected (expected=123, actual=124)");
1535
- });
1536
-
1537
- it("should start network with 3.0.x adapter", async () => {
1538
- mockZnpRequestWith(commissioned3AlignedRequestMock);
1539
- const result = await adapter.start();
1540
- expect(result).toBe("resumed");
1541
- });
1542
-
1543
- it("should restore unified backup with 3.0.x adapter and create backup - empty", async () => {
1544
- const backupFile = getTempFile();
1545
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1546
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1547
- mockZnpRequestWith(empty3AlignedRequestMock);
1548
- const result = await adapter.start();
1549
- expect(result).toBe("restored");
1550
-
1551
- await adapter.backup([]);
1552
- });
1553
-
1554
- it("should restore unified backup with 3.0.x adapter and create backup - no tclk seed", async () => {
1555
- const backupFile = getTempFile();
1556
- const backup = JSON.parse(JSON.stringify(backupMatchingConfig));
1557
- delete backup.stack_specific.zstack;
1558
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1559
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1560
- mockZnpRequestWith(empty3AlignedRequestMock);
1561
- const result = await adapter.start();
1562
- expect(result).toBe("restored");
1563
-
1564
- await adapter.backup([]);
1565
- });
1566
-
1567
- it("should restore unified backup with 3.x.0 adapter and create backup - empty", async () => {
1568
- const backupFile = getTempFile();
1569
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1570
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1571
- mockZnpRequestWith(empty3x0AlignedRequestMock);
1572
- const result = await adapter.start();
1573
- expect(result).toBe("restored");
1574
-
1575
- await adapter.backup([]);
1576
- });
1577
-
1578
- it("should (recommission) restore unified backup with 1.2 adapter and create backup - empty", async () => {
1579
- const backupFile = getTempFile();
1580
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig12), "utf8");
1581
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 1});
1582
- mockZnpRequestWith(empty12UnalignedRequestMock);
1583
- const result = await adapter.start();
1584
- expect(result).toBe("restored");
1585
-
1586
- const backup = await adapter.backup([]);
1587
- expect(backup.networkKeyInfo.frameCounter).toBe(0);
1588
- });
1589
-
1590
- it("should create backup with 3.0.x adapter - default security material table entry", async () => {
1591
- const builder = commissioned3AlignedRequestMock.clone();
1592
- mockZnpRequestWith(builder);
1593
- const result = await adapter.start();
1594
- expect(result).toBe("resumed");
1595
- for (let i = 0; i < 4; i++) {
1596
- builder.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + i, Buffer.from("000000000000000000000000", "hex"));
1597
- }
1598
-
1599
- const secMaterialTableEntry = Structs.nwkSecMaterialDescriptorEntry();
1600
- secMaterialTableEntry.extendedPanID = Buffer.alloc(8, 0xff);
1601
- secMaterialTableEntry.FrameCounter = 2800;
1602
- builder.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + 0, secMaterialTableEntry.serialize("aligned"));
1603
- mockZnpRequestWith(builder);
1604
-
1605
- const backup = await adapter.backup([]);
1606
- expect(backup.networkKeyInfo.frameCounter).toBe(2800);
1607
- });
1608
-
1609
- it("should create backup with 3.0.x adapter - emnpty security material table", async () => {
1610
- const builder = commissioned3AlignedRequestMock.clone();
1611
- mockZnpRequestWith(builder);
1612
- const result = await adapter.start();
1613
- expect(result).toBe("resumed");
1614
- for (let i = 0; i < 4; i++) {
1615
- builder.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + i, Buffer.from("000000000000000000000000", "hex"));
1616
- }
1617
- mockZnpRequestWith(builder);
1618
-
1619
- const backup = await adapter.backup([]);
1620
- expect(backup.networkKeyInfo.frameCounter).toBe(1250);
1621
- });
1622
-
1623
- it("should create backup with 3.0.x adapter - security material table with generic record", async () => {
1624
- const builder = commissioned3AlignedRequestMock.clone();
1625
- mockZnpRequestWith(builder);
1626
- const result = await adapter.start();
1627
- expect(result).toBe("resumed");
1628
- for (let i = 0; i < 4; i++) {
1629
- builder.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + i, Buffer.from("000000000000000000000000", "hex"));
1630
- }
1631
- const genericEntry = Structs.nwkSecMaterialDescriptorEntry();
1632
- genericEntry.extendedPanID = Buffer.from("ffffffffffffffff", "hex");
1633
- genericEntry.FrameCounter = 8737;
1634
- builder.nv(NvItemsIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + 3, genericEntry.serialize("aligned"));
1635
- mockZnpRequestWith(builder);
1636
-
1637
- const backup = await adapter.backup([]);
1638
- expect(backup.networkKeyInfo.frameCounter).toBe(8737);
1639
- });
1640
-
1641
- it("should create backup with 1.2 adapter", async () => {
1642
- mockZnpRequestWith(commissioned12UnalignedRequestMock);
1643
- const result = await adapter.start();
1644
- expect(result).toBe("resumed");
1645
-
1646
- const backup = await adapter.backup([]);
1647
- expect(backup.networkKeyInfo.frameCounter).toBe(0);
1648
- });
1649
-
1650
- it("should keep missing devices in backup", async () => {
1651
- const backupFile = getTempFile();
1652
- const backupWithMissingDevice = JSON.parse(JSON.stringify(backupMatchingConfig));
1653
- backupWithMissingDevice.devices.push({
1654
- nwk_address: "20fa",
1655
- ieee_address: "00128d11124fa80b",
1656
- link_key: {
1657
- key: "bff550908aa1529ee90eea3c3bdc26fc",
1658
- rx_counter: 0,
1659
- tx_counter: 2,
1660
- },
1661
- });
1662
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1663
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1664
- mockZnpRequestWith(empty3AlignedRequestMock);
1665
- await adapter.start();
1666
- fs.writeFileSync(backupFile, JSON.stringify(backupWithMissingDevice), "utf8");
1667
- const devicesInDatabase = backupWithMissingDevice.devices.map((d) => ZSpec.Utils.eui64BEBufferToHex(d.ieee_address));
1668
- const backup = await adapter.backup(devicesInDatabase);
1669
- const missingDevice = backup.devices.find((d) => d.ieeeAddress.toString("hex") === "00128d11124fa80b");
1670
- expect(missingDevice).not.toBeNull();
1671
- expect(backupWithMissingDevice.devices.length).toBe(backup.devices.length);
1672
- expect(missingDevice?.linkKey?.key.toString("hex")).toBe("bff550908aa1529ee90eea3c3bdc26fc");
1673
- });
1674
-
1675
- it("should fail when backup file is corrupted - Coordinator backup is corrupted", async () => {
1676
- const backupFile = getTempFile();
1677
- fs.writeFileSync(backupFile, "{", "utf8");
1678
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1679
- mockZnpRequestWith(empty3AlignedRequestMock);
1680
- await expect(adapter.start()).rejects.toThrowError("Coordinator backup is corrupted");
1681
- });
1682
-
1683
- it("should fail to restore unified backup with 3.0.x adapter - invalid open coordinator backup version", async () => {
1684
- const backupFile = getTempFile();
1685
- let backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1686
- backupData = {
1687
- ...backupData,
1688
- metadata: {
1689
- ...backupData.metadata,
1690
- // biome-ignore lint/suspicious/noExplicitAny: mock
1691
- version: 99 as any,
1692
- },
1693
- };
1694
-
1695
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1696
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1697
- mockZnpRequestWith(empty3AlignedRequestMock);
1698
- await expect(adapter.start()).rejects.toThrowError("Unsupported open coordinator backup version (version=99)");
1699
- });
1700
-
1701
- it("should fail to restore (unified) backup with 3.0.x adapter - unsupported backup format", async () => {
1702
- const backupFile = getTempFile();
1703
- let backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1704
- backupData = {
1705
- ...backupData,
1706
- metadata: {
1707
- ...backupData.metadata,
1708
- version: undefined,
1709
- },
1710
- };
1711
-
1712
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1713
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1714
- mockZnpRequestWith(empty3AlignedRequestMock);
1715
- await expect(adapter.start()).rejects.toThrowError("Unknown backup format");
1716
- });
1717
-
1718
- it("should fail to restore unified backup with 3.0.x adapter - insufficient tclk table size", async () => {
1719
- const backupFile = getTempFile();
1720
- const backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1721
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1722
-
1723
- const builder = empty3AlignedRequestMock.clone();
1724
- for (let i = 0; i < 16; i++) {
1725
- builder.nv(NvItemsIds.LEGACY_TCLK_TABLE_START + i, null);
1726
- }
1727
- builder.nv(NvItemsIds.LEGACY_TCLK_TABLE_START + 0, Buffer.from("0000000000000000000000000000000000000000", "hex"));
1728
- mockZnpRequestWith(builder);
1729
-
1730
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1731
- await expect(adapter.start()).rejects.toThrowError("target adapter tclk table size insufficient (size=1)");
1732
- });
1733
-
1734
- it("should fail to restore unified backup with 3.0.x adapter - insufficient aps link key data table size", async () => {
1735
- const backupFile = getTempFile();
1736
- const backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1737
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1738
-
1739
- const builder = empty3AlignedRequestMock.clone();
1740
- for (let i = 0; i < 16; i++) {
1741
- builder.nv(NvItemsIds.APS_LINK_KEY_DATA_START + i, null);
1742
- }
1743
- builder.nv(NvItemsIds.APS_LINK_KEY_DATA_START + 0, Buffer.from("000000000000000000000000000000000000000000000000", "hex"));
1744
- mockZnpRequestWith(builder);
1745
-
1746
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1747
- await expect(adapter.start()).rejects.toThrowError("target adapter aps link key data table size insufficient (size=1)");
1748
- });
1749
-
1750
- it("should fail to restore unified backup with 3.0.x adapter - insufficient security manager table size", async () => {
1751
- const backupFile = getTempFile();
1752
- const backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1753
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1754
-
1755
- const builder = empty3AlignedRequestMock.clone();
1756
- builder.nv(NvItemsIds.APS_LINK_KEY_TABLE, Buffer.from("0000feff00000000", "hex"));
1757
- mockZnpRequestWith(builder);
1758
-
1759
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1760
- await expect(adapter.start()).rejects.toThrowError("target adapter security manager table size insufficient (size=1)");
1761
- });
1762
-
1763
- it("should fail to restore unified backup with 1.2 adapter - backup from newer adapter", async () => {
1764
- const backupFile = getTempFile();
1765
- const backupData: UnifiedBackupStorage = JSON.parse(JSON.stringify(backupMatchingConfig));
1766
- fs.writeFileSync(backupFile, JSON.stringify(backupData), "utf8");
1767
-
1768
- mockZnpRequestWith(empty12UnalignedRequestMock);
1769
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1770
- await expect(adapter.start()).rejects.toThrowError(
1771
- "your backup is from newer platform version (Z-Stack 3.0.x+) and cannot be restored onto Z-Stack 1.2 adapter - please remove backup before proceeding",
1772
- );
1773
- });
1774
-
1775
- it("should fail to create backup with 3.0.x adapter - unable to read ieee address", async () => {
1776
- mockZnpRequestWith(commissioned3AlignedRequestMock.clone().handle(Subsystem.SYS, "getExtAddr", () => ({payload: {}})));
1777
- const result = await adapter.start();
1778
- expect(result).toBe("resumed");
1779
- await expect(adapter.backup([])).rejects.toThrowError("Failed to read adapter IEEE address");
1780
- });
1781
-
1782
- it("should fail to create backup with 3.0.x adapter - adapter not commissioned - missing nib", async () => {
1783
- const builder = empty3AlignedRequestMock.clone();
1784
- mockZnpRequestWith(builder);
1785
- const result = await adapter.start();
1786
- expect(result).toBe("reset");
1787
- builder.nv(NvItemsIds.NIB, null);
1788
- mockZnpRequestWith(builder);
1789
- await expect(adapter.backup([])).rejects.toThrowError("Cannot backup - adapter not commissioned");
1790
- });
1791
-
1792
- it("should fail to create backup with 3.0.x adapter - missing active key info", async () => {
1793
- const builder = empty3AlignedRequestMock.clone();
1794
- mockZnpRequestWith(builder);
1795
- const result = await adapter.start();
1796
- expect(result).toBe("reset");
1797
- builder.nv(NvItemsIds.NWK_ACTIVE_KEY_INFO, null);
1798
- mockZnpRequestWith(builder);
1799
- await expect(adapter.backup([])).rejects.toThrowError("Cannot backup - missing active key info");
1800
- });
1801
-
1802
- it("should restore legacy backup with 3.0.x adapter - empty", async () => {
1803
- const backupFile = getTempFile();
1804
- fs.writeFileSync(backupFile, JSON.stringify(legacyBackup), "utf8");
1805
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1806
- mockZnpRequestWith(empty3AlignedRequestMock);
1807
- const result = await adapter.start();
1808
- expect(result).toBe("restored");
1809
- });
1810
-
1811
- it("should fail to restore legacy backup with 3.0.x adapter - missing NIB", async () => {
1812
- const backupFile = getTempFile();
1813
- const backup = JSON.parse(JSON.stringify(legacyBackup));
1814
- delete backup.data.ZCD_NV_NIB;
1815
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1816
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1817
- mockZnpRequestWith(empty3AlignedRequestMock);
1818
- await expect(adapter.start()).rejects.toThrowError("Backup corrupted - missing NIB");
1819
- });
1820
-
1821
- it("should fail to restore legacy backup with 3.0.x adapter - missing active key info", async () => {
1822
- const backupFile = getTempFile();
1823
- const backup = JSON.parse(JSON.stringify(legacyBackup));
1824
- delete backup.data.ZCD_NV_NWK_ACTIVE_KEY_INFO;
1825
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1826
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1827
- mockZnpRequestWith(empty3AlignedRequestMock);
1828
- await expect(adapter.start()).rejects.toThrowError("Backup corrupted - missing active key info");
1829
- });
1830
-
1831
- it("should fail to restore legacy backup with 3.0.x adapter - missing pre-configured key enabled", async () => {
1832
- const backupFile = getTempFile();
1833
- const backup = JSON.parse(JSON.stringify(legacyBackup));
1834
- delete backup.data.ZCD_NV_PRECFGKEY_ENABLE;
1835
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1836
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1837
- mockZnpRequestWith(empty3AlignedRequestMock);
1838
- await expect(adapter.start()).rejects.toThrowError("Backup corrupted - missing pre-configured key enable attribute");
1839
- });
1840
-
1841
- it("should fail to restore legacy backup with 3.0.x adapter - pre-configured key enabled", async () => {
1842
- const backupFile = getTempFile();
1843
- const backup = JSON.parse(JSON.stringify(legacyBackup));
1844
- delete backup.data.ZCD_NV_EX_NWK_SEC_MATERIAL_TABLE;
1845
- delete backup.data.ZCD_NV_LEGACY_NWK_SEC_MATERIAL_TABLE_START;
1846
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1847
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1848
- mockZnpRequestWith(empty3AlignedRequestMock);
1849
- await expect(adapter.start()).rejects.toThrowError("Backup corrupted - missing network security material table");
1850
- });
1851
-
1852
- it("should fail to restore legacy backup with 3.0.x adapter - missing adapter ieee address", async () => {
1853
- const backupFile = getTempFile();
1854
- const backup = JSON.parse(JSON.stringify(legacyBackup));
1855
- delete backup.data.ZCD_NV_EXTADDR;
1856
- fs.writeFileSync(backupFile, JSON.stringify(backup), "utf8");
1857
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1858
- mockZnpRequestWith(empty3AlignedRequestMock);
1859
- await expect(adapter.start()).rejects.toThrow("Backup corrupted - missing adapter IEEE address NV entry");
1860
- });
1861
-
1862
- it("should fail to start with 3.0.x adapter - commissioned, config-adapter mismatch", async () => {
1863
- const backupFile = getTempFile();
1864
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1865
-
1866
- adapter = new ZStackAdapter(networkOptionsMismatched, serialPortOptions, backupFile, {concurrent: 3});
1867
- mockZnpRequestWith(commissioned3AlignedRequestMock);
1868
- await expect(adapter.start()).rejects.toThrow("startup failed - configuration-adapter mismatch - see logs above for more information");
1869
- expect(mockLogger.error.mock.calls[0][0]).toBe("Configuration is not consistent with adapter state/backup!");
1870
- expect(mockLogger.error.mock.calls[1][0]).toBe("- PAN ID: configured=124, adapter=123");
1871
- expect(mockLogger.error.mock.calls[2][0]).toBe("- Extended PAN ID: configured=00124b0009d69f77, adapter=00124b0009d69f77");
1872
- expect(mockLogger.error.mock.calls[3][0]).toBe(
1873
- "- Network Key: configured=01030507090b0d0f00020406080a0c0d, adapter:active=01030507090b0d0f00020406080a0c0d adapter:preconfigured=01030507090b0d0f00020406080a0c0d, adapter:alternate=01030507090b0d0f00020406080a0c0d",
1874
- );
1875
- expect(mockLogger.error.mock.calls[4][0]).toBe("- Channel List: configured=21, adapter=21");
1876
- expect(mockLogger.error.mock.calls[5][0]).toBe("Please update configuration to prevent further issues.");
1877
- expect(mockLogger.error.mock.calls[6][0]).toMatch(
1878
- `If you wish to re-commission your network, please remove coordinator backup at ${backupFile}`,
1879
- );
1880
- expect(mockLogger.error.mock.calls[7][0]).toBe("Re-commissioning your network will require re-pairing of all devices!");
1881
- });
1882
-
1883
- it("should start with runInconsistent option with 3.0.x adapter - commissioned, config-adapter mismatch", async () => {
1884
- const backupFile = getTempFile();
1885
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1886
-
1887
- adapter = new ZStackAdapter(networkOptionsMismatched, serialPortOptions, backupFile, {
1888
- concurrent: 3,
1889
- forceStartWithInconsistentAdapterConfiguration: true,
1890
- });
1891
- mockZnpRequestWith(commissioned3AlignedRequestMock);
1892
- const result = await adapter.start();
1893
- expect(result).toBe("resumed");
1894
- expect(mockLogger.error.mock.calls[0][0]).toBe("Configuration is not consistent with adapter state/backup!");
1895
- expect(mockLogger.error.mock.calls[1][0]).toBe("- PAN ID: configured=124, adapter=123");
1896
- expect(mockLogger.error.mock.calls[2][0]).toBe("- Extended PAN ID: configured=00124b0009d69f77, adapter=00124b0009d69f77");
1897
- expect(mockLogger.error.mock.calls[3][0]).toBe(
1898
- "- Network Key: configured=01030507090b0d0f00020406080a0c0d, adapter:active=01030507090b0d0f00020406080a0c0d adapter:preconfigured=01030507090b0d0f00020406080a0c0d, adapter:alternate=01030507090b0d0f00020406080a0c0d",
1899
- );
1900
- expect(mockLogger.error.mock.calls[4][0]).toBe("- Channel List: configured=21, adapter=21");
1901
- expect(mockLogger.error.mock.calls[5][0]).toBe("Please update configuration to prevent further issues.");
1902
- expect(mockLogger.error.mock.calls[6][0]).toMatch(
1903
- `If you wish to re-commission your network, please remove coordinator backup at ${backupFile}`,
1904
- );
1905
- expect(mockLogger.error.mock.calls[7][0]).toBe("Re-commissioning your network will require re-pairing of all devices!");
1906
- expect(mockLogger.error.mock.calls[8][0]).toBe(
1907
- "Running despite adapter configuration mismatch as configured. Please update the adapter to compatible firmware and recreate your network as soon as possible.",
1908
- );
1909
- });
1910
-
1911
- it("should start with 3.0.x adapter - backward-compat - reversed extended pan id", async () => {
1912
- const backupFile = getTempFile();
1913
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1914
-
1915
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1916
- const nib = Structs.nib(Buffer.from(commissioned3AlignedRequestMock.nvItems.find((item) => item.id === NvItemsIds.NIB).value));
1917
- nib.extendedPANID = nib.extendedPANID.reverse();
1918
- mockZnpRequestWith(commissioned3AlignedRequestMock.clone().nv(NvItemsIds.NIB, nib.serialize()));
1919
- const result = await adapter.start();
1920
- expect(result).toBe("resumed");
1921
- expect(mockLogger.warning.mock.calls[0][0]).toBe("Extended PAN ID is reversed (expected=00124b0009d69f77, actual=779fd609004b1200)");
1922
- });
1923
-
1924
- it("should restore unified backup with 3.0.x adapter - commissioned, mismatched adapter-config, matching config-backup", async () => {
1925
- const backupFile = getTempFile();
1926
- fs.writeFileSync(backupFile, JSON.stringify(backupMatchingConfig), "utf8");
1927
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, backupFile, {concurrent: 3});
1928
- mockZnpRequestWith(commissioned3AlignedConfigMistmachRequestMock);
1929
- const result = await adapter.start();
1930
- expect(result).toBe("restored");
1931
- });
1932
-
1933
- it("should start network with 3.0.x adapter - resume in coordinator mode", async () => {
1934
- mockZnpRequestWith(
1935
- commissioned3AlignedRequestMock.clone().handle(Subsystem.UTIL, "getDeviceInfo", () => ({payload: {devicestate: DevStates.ZB_COORD}})),
1936
- );
1937
- mockZnpWaitFor.mockImplementation((type, subsystem, command, target, transid, state, timeout) => {
1938
- const missing = () => {
1939
- const msg = `Not implemented - ${Type[type]} - ${Subsystem[subsystem]} - ${command} - ${target} - ${transid} - ${state} - ${timeout}`;
1940
- console.log(msg);
1941
- throw new Error(msg);
1942
- };
1943
-
1944
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "activeEpRsp") {
1945
- return waitForResult(
1946
- mockZdoZpiObject<ActiveEndpointsResponse>("activeEpRsp", target, [
1947
- Zdo.Status.SUCCESS,
1948
- {
1949
- nwkAddress: 0,
1950
- endpointList: [1, 2, 3],
1951
- },
1952
- ]),
1953
- );
1954
- }
1955
-
1956
- if (type === Type.AREQ && subsystem === Subsystem.ZDO && command === "stateChangeInd") {
1957
- return waitForResult({payload: {state: 9}});
1958
- }
1959
-
1960
- missing();
1961
- });
1962
- const result = await adapter.start();
1963
- expect(result).toBe("resumed");
1964
- });
1965
-
1966
- it("should start network with 3.0.x adapter - resume in coordinator mode, extGroupFind failed", async () => {
1967
- mockZnpRequestWith(
1968
- commissioned3AlignedRequestMock
1969
- .clone()
1970
- .handle(Subsystem.UTIL, "getDeviceInfo", () => ({payload: {devicestate: DevStates.ZB_COORD}}))
1971
- .handle(Subsystem.ZDO, "extFindGroup", () => ({payload: {status: 1}})),
1972
- );
1973
- const result = await adapter.start();
1974
- expect(result).toBe("resumed");
1975
- });
1976
-
1977
- it("should commission network with 1.2 adapter", async () => {
1978
- mockZnpRequestWith(empty12UnalignedRequestMock);
1979
- const result = await adapter.start();
1980
- expect(result).toBe("restored");
1981
- });
1982
-
1983
- it("should commission network with 1.2 adapter - default extended pan id", async () => {
1984
- mockZnpRequestWith(empty12UnalignedRequestMock);
1985
- adapter = new ZStackAdapter(networkOptionsDefaultExtendedPanId, serialPortOptions, "backup.json", {concurrent: 3});
1986
- const result = await adapter.start();
1987
- expect(result).toBe("restored");
1988
- });
1989
-
1990
- it("should commission network with 1.2 adapter - old adapter without version reporting", async () => {
1991
- mockZnpRequestWith(empty12UnalignedRequestMock.clone().handle(Subsystem.SYS, "version", () => undefined));
1992
- const result = await adapter.start();
1993
- expect(result).toBe("restored");
1994
- });
1995
-
1996
- it("should reset network with 1.2 adapter - config mismtach", async () => {
1997
- mockZnpRequestWith(commissioned12UnalignedMismatchRequestMock);
1998
- const result = await adapter.start();
1999
- expect(result).toBe("reset");
2000
- });
2001
-
2002
- it("Add install code: Install Code + CRC", async () => {
2003
- basicMocks();
2004
- await adapter.start();
2005
- await adapter.addInstallCode(
2006
- "0x9035EAFFFE424783",
2007
- Buffer.from([0xae, 0x3b, 0x28, 0x72, 0x81, 0xcf, 0x16, 0xf5, 0x50, 0x73, 0x3a, 0x0c, 0xec, 0x38, 0xaa, 0x31, 0xe8, 0x02]),
2008
- false,
2009
- );
2010
- const payload = {
2011
- installCodeFormat: 0x1,
2012
- ieeeaddr: "0x9035EAFFFE424783",
2013
- installCode: Buffer.from([0xae, 0x3b, 0x28, 0x72, 0x81, 0xcf, 0x16, 0xf5, 0x50, 0x73, 0x3a, 0x0c, 0xec, 0x38, 0xaa, 0x31, 0xe8, 0x02]),
2014
- };
2015
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.APP_CNF, "bdbAddInstallCode", payload);
2016
- });
2017
-
2018
- it("Add install code: Key derived from Install Code", async () => {
2019
- basicMocks();
2020
- await adapter.start();
2021
- await adapter.addInstallCode(
2022
- "0x9035EAFFFE424783",
2023
- Buffer.from([0xae, 0x3b, 0x28, 0x72, 0x81, 0xcf, 0x16, 0xf5, 0x50, 0x73, 0x3a, 0x0c, 0xec, 0x38, 0xaa, 0x31]),
2024
- true,
2025
- );
2026
- const payload = {
2027
- installCodeFormat: 0x2,
2028
- ieeeaddr: "0x9035EAFFFE424783",
2029
- installCode: Buffer.from([0xae, 0x3b, 0x28, 0x72, 0x81, 0xcf, 0x16, 0xf5, 0x50, 0x73, 0x3a, 0x0c, 0xec, 0x38, 0xaa, 0x31]),
2030
- };
2031
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.APP_CNF, "bdbAddInstallCode", payload);
2032
- });
2033
-
2034
- it("LED behaviour: disable LED true, firmware not handling leds", async () => {
2035
- basicMocks();
2036
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {disableLED: true});
2037
- await adapter.start();
2038
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 0}, undefined, 500);
2039
- mockZnpRequest.mockClear();
2040
- mockQueueExecute.mockClear();
2041
- await adapter.permitJoin(255, 0);
2042
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), undefined, 500);
2043
- mockZnpRequest.mockClear();
2044
- mockQueueExecute.mockClear();
2045
- await adapter.permitJoin(0, 0);
2046
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), undefined, 500);
2047
- });
2048
-
2049
- it("LED behaviour: disable LED false, firmware not handling leds", async () => {
2050
- basicMocks();
2051
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {disableLED: false});
2052
- await adapter.start();
2053
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), undefined, 500);
2054
- mockZnpRequest.mockClear();
2055
- mockQueueExecute.mockClear();
2056
- await adapter.permitJoin(255, 0);
2057
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 1}, undefined, 500);
2058
- mockZnpRequest.mockClear();
2059
- mockQueueExecute.mockClear();
2060
- await adapter.permitJoin(0, 0);
2061
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 0}, undefined, 500);
2062
- });
2063
-
2064
- it("LED behaviour: disable LED true, firmware handling leds", async () => {
2065
- mockZnpRequestWith(
2066
- baseZnpRequestMock.clone().handle(Subsystem.SYS, "version", (_payload) => {
2067
- return {payload: {product: ZnpVersion.ZStack30x, revision: 20211030}};
2068
- }),
2069
- );
2070
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {disableLED: true});
2071
- await adapter.start();
2072
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 0xff, mode: 5}, undefined, 500);
2073
- mockZnpRequest.mockClear();
2074
- mockQueueExecute.mockClear();
2075
- await adapter.permitJoin(255, 0);
2076
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), undefined, 500);
2077
- mockZnpRequest.mockClear();
2078
- mockQueueExecute.mockClear();
2079
- await adapter.permitJoin(0, 0);
2080
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), undefined, 500);
2081
- });
2082
-
2083
- it("LED behaviour: disable LED false, firmware handling leds", async () => {
2084
- mockZnpRequestWith(
2085
- baseZnpRequestMock.clone().handle(Subsystem.SYS, "version", (_payload) => {
2086
- return {payload: {product: ZnpVersion.ZStack30x, revision: 20211030}};
2087
- }),
2088
- );
2089
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {disableLED: false});
2090
- await adapter.start();
2091
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), null, 500);
2092
- mockZnpRequest.mockClear();
2093
- mockQueueExecute.mockClear();
2094
- await adapter.permitJoin(255, 0);
2095
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), null, 500);
2096
- mockZnpRequest.mockClear();
2097
- mockQueueExecute.mockClear();
2098
- await adapter.permitJoin(0, 0);
2099
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", expect.any(Object), null, 500);
2100
- });
2101
-
2102
- /* Original Tests */
2103
-
2104
- it("Call znp constructor", () => {
2105
- expect(Znp).toHaveBeenCalledWith("dummy", 800, false);
2106
- });
2107
-
2108
- it("Close adapter", async () => {
2109
- basicMocks();
2110
- await adapter.start();
2111
- await adapter.stop();
2112
- expect(mockZnpClose).toHaveBeenCalledTimes(1);
2113
- });
2114
-
2115
- it("Get coordinator IEEE", async () => {
2116
- basicMocks();
2117
- await adapter.start();
2118
- const ieee = await adapter.getCoordinatorIEEE();
2119
- expect(ieee).toStrictEqual("0x00124b0009d80ba7");
2120
- });
2121
-
2122
- it("Permit join all", async () => {
2123
- basicMocks();
2124
- await adapter.start();
2125
- mockZnpRequest.mockClear();
2126
- mockZnpRequestZdo.mockClear();
2127
- mockQueueExecute.mockClear();
2128
- await adapter.permitJoin(100);
2129
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2130
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2131
- const zdoPayload = Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.PERMIT_JOINING_REQUEST, 100, 1, []);
2132
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2133
- Zdo.ClusterId.PERMIT_JOINING_REQUEST,
2134
- Buffer.from([
2135
- AddressMode.ADDR_BROADCAST,
2136
- ZSpec.BroadcastAddress.DEFAULT & 0xff,
2137
- (ZSpec.BroadcastAddress.DEFAULT >> 8) & 0xff,
2138
- ...zdoPayload,
2139
- ]),
2140
- undefined,
2141
- // Subsystem.ZDO, 'mgmtPermitJoinReq', {
2142
- // addrmode: 0x0f,
2143
- // dstaddr: 0xfffc,
2144
- // duration: 100,
2145
- // tcsignificance: 0,
2146
- // }
2147
- );
2148
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 1}, undefined, 500);
2149
- });
2150
-
2151
- it("Permit join specific networkAddress", async () => {
2152
- basicMocks();
2153
- await adapter.start();
2154
- mockZnpRequest.mockClear();
2155
- mockZnpRequestZdo.mockClear();
2156
- mockQueueExecute.mockClear();
2157
- await adapter.permitJoin(102, 42102);
2158
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2159
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2160
- const zdoPayload = Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.PERMIT_JOINING_REQUEST, 102, 1, []);
2161
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2162
- Zdo.ClusterId.PERMIT_JOINING_REQUEST,
2163
- Buffer.from([AddressMode.ADDR_16BIT, 42102 & 0xff, (42102 >> 8) & 0xff, ...zdoPayload]),
2164
- expect.any(Number),
2165
- // Subsystem.ZDO, 'mgmtPermitJoinReq', {
2166
- // addrmode: 2,
2167
- // dstaddr: 42102,
2168
- // duration: 102,
2169
- // tcsignificance: 0,
2170
- // }
2171
- );
2172
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 1}, undefined, 500);
2173
- });
2174
-
2175
- it("Get coordinator version", async () => {
2176
- basicMocks();
2177
- await adapter.start();
2178
- mockZnpRequest.mockClear();
2179
- mockQueueExecute.mockClear();
2180
- expect(await adapter.getCoordinatorVersion()).toStrictEqual({type: "ZStack3x0", meta: {revision: 20210430, product: 1}});
2181
- });
2182
-
2183
- it("Soft reset", async () => {
2184
- basicMocks();
2185
- await adapter.start();
2186
- mockZnpRequest.mockClear();
2187
- mockQueueExecute.mockClear();
2188
- await adapter.reset("soft");
2189
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2190
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.SYS, "resetReq", {type: 1});
2191
- });
2192
-
2193
- it("Hard reset", async () => {
2194
- basicMocks();
2195
- await adapter.start();
2196
- mockZnpRequest.mockClear();
2197
- mockQueueExecute.mockClear();
2198
- await adapter.reset("hard");
2199
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2200
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.SYS, "resetReq", {type: 0});
2201
- });
2202
-
2203
- it("Start with transmit power set", async () => {
2204
- basicMocks();
2205
- adapter = new ZStackAdapter(networkOptions, serialPortOptions, "backup.json", {transmitPower: 2, disableLED: false});
2206
- await adapter.start();
2207
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.SYS, "stackTune", {operation: 0, value: 2});
2208
- });
2209
-
2210
- it("Support LED should go to false when LED request fails", async () => {
2211
- basicMocks();
2212
- await adapter.start();
2213
- mockZnpRequest.mockClear();
2214
- mockQueueExecute.mockClear();
2215
- mockZnpRequest.mockImplementation(
2216
- (_, cmd) =>
2217
- new Promise((resolve, reject) => {
2218
- if (cmd === "ledControl") reject("FAILED");
2219
- else resolve(undefined);
2220
- }),
2221
- );
2222
- await adapter.permitJoin(0, 0);
2223
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 0}, undefined, 500);
2224
- mockZnpRequest.mockClear();
2225
- mockQueueExecute.mockClear();
2226
- await adapter.permitJoin(0, 0);
2227
- expect(mockZnpRequest).not.toHaveBeenCalledWith(Subsystem.UTIL, "ledControl", {ledid: 3, mode: 0}, undefined, 500);
2228
- });
2229
-
2230
- it("Send zcl frame network address", async () => {
2231
- basicMocks();
2232
- await adapter.start();
2233
-
2234
- mockZnpRequest.mockClear();
2235
- mockQueueExecute.mockClear();
2236
- const frame = Zcl.Frame.create(
2237
- Zcl.FrameType.GLOBAL,
2238
- Zcl.Direction.CLIENT_TO_SERVER,
2239
- true,
2240
- undefined,
2241
- 100,
2242
- "writeNoRsp",
2243
- 0,
2244
- [{attrId: 0, dataType: 0, attrData: null}],
2245
- {},
2246
- );
2247
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2248
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
2249
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2250
- expect(mockZnpRequest).toHaveBeenCalledWith(
2251
- 4,
2252
- "dataRequest",
2253
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2254
- 99,
2255
- );
2256
- });
2257
-
2258
- it("Send zcl frame network address retry on MAC channel access failure", async () => {
2259
- basicMocks();
2260
- dataConfirmCode = 225;
2261
- dataConfirmCodeReset = true;
2262
- await adapter.start();
2263
- mockZnpRequest.mockClear();
2264
- mockQueueExecute.mockClear();
2265
- const frame = Zcl.Frame.create(
2266
- Zcl.FrameType.GLOBAL,
2267
- Zcl.Direction.CLIENT_TO_SERVER,
2268
- true,
2269
- undefined,
2270
- 100,
2271
- "writeNoRsp",
2272
- 0,
2273
- [{attrId: 0, dataType: 0, attrData: null}],
2274
- {},
2275
- );
2276
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2277
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
2278
- expect(mockZnpRequest).toHaveBeenCalledTimes(2);
2279
- expect(mockZnpRequest).toHaveBeenCalledWith(
2280
- 4,
2281
- "dataRequest",
2282
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2283
- 99,
2284
- );
2285
- });
2286
-
2287
- it("Send zcl frame network address dataConfirm fails", async () => {
2288
- basicMocks();
2289
- await adapter.start();
2290
- dataConfirmCode = 201;
2291
- mockZnpRequest.mockClear();
2292
- mockQueueExecute.mockClear();
2293
- const frame = Zcl.Frame.create(
2294
- Zcl.FrameType.GLOBAL,
2295
- Zcl.Direction.CLIENT_TO_SERVER,
2296
- true,
2297
- undefined,
2298
- 100,
2299
- "writeNoRsp",
2300
- 0,
2301
- [{attrId: 0, dataType: 0, attrData: null}],
2302
- {},
2303
- );
2304
- let error;
2305
- try {
2306
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2307
- } catch (e) {
2308
- error = e;
2309
- }
2310
- expect(error.message).toStrictEqual("Data request failed with error: 'undefined' (201)");
2311
- });
2312
-
2313
- it("Send zcl frame network address with default response", async () => {
2314
- basicMocks();
2315
- await adapter.start();
2316
- const defaultReponse = Zcl.Frame.create(
2317
- Zcl.FrameType.GLOBAL,
2318
- Zcl.Direction.SERVER_TO_CLIENT,
2319
- true,
2320
- undefined,
2321
- 100,
2322
- "defaultRsp",
2323
- 0,
2324
- {cmdId: 0, status: 0},
2325
- {},
2326
- );
2327
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
2328
- clusterid: 0,
2329
- srcendpoint: 20,
2330
- srcaddr: 2,
2331
- linkquality: 101,
2332
- groupid: 12,
2333
- data: defaultReponse.toBuffer(),
2334
- });
2335
- mockZnpRequest.mockClear();
2336
- mockQueueExecute.mockClear();
2337
- const frame = Zcl.Frame.create(
2338
- Zcl.FrameType.GLOBAL,
2339
- Zcl.Direction.CLIENT_TO_SERVER,
2340
- false,
2341
- undefined,
2342
- 100,
2343
- "writeNoRsp",
2344
- 0,
2345
- [{attrId: 0, dataType: 0, attrData: null}],
2346
- {},
2347
- );
2348
- const request = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2349
- znpReceived(object);
2350
- await request;
2351
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
2352
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2353
- expect(mockZnpRequest).toHaveBeenCalledWith(
2354
- 4,
2355
- "dataRequest",
2356
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2357
- 99,
2358
- );
2359
- });
2360
-
2361
- it("Send zcl frame network address fails because mac transaction expire, should retry", async () => {
2362
- basicMocks();
2363
- await adapter.start();
2364
- dataConfirmCode = 240;
2365
- mockZnpRequest.mockClear();
2366
- mockZnpRequestZdo.mockClear();
2367
- mockQueueExecute.mockClear();
2368
- const frame = Zcl.Frame.create(
2369
- Zcl.FrameType.GLOBAL,
2370
- Zcl.Direction.CLIENT_TO_SERVER,
2371
- true,
2372
- undefined,
2373
- 100,
2374
- "writeNoRsp",
2375
- 0,
2376
- [{attrId: 0, dataType: 0, attrData: null}],
2377
- {},
2378
- );
2379
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2380
- let error;
2381
- try {
2382
- await response;
2383
- } catch (e) {
2384
- error = e;
2385
- }
2386
-
2387
- expect(error.message).toStrictEqual("Data request failed with error: 'MAC transaction expired' (240)");
2388
- expect(mockZnpRequest).toHaveBeenCalledTimes(9);
2389
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2390
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2391
- 1,
2392
- 4,
2393
- "dataRequest",
2394
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2395
- 99,
2396
- );
2397
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2398
- 2,
2399
- 4,
2400
- "dataRequest",
2401
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 2},
2402
- 99,
2403
- );
2404
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 7, "assocGetWithAddress", {extaddr: "0x02", nwkaddr: 2});
2405
- expect(mockZnpRequest).toHaveBeenNthCalledWith(4, 7, "assocRemove", {ieeeadr: "0x02"});
2406
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2407
- 5,
2408
- 4,
2409
- "dataRequest",
2410
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 3},
2411
- 99,
2412
- );
2413
- expect(mockZnpRequest).toHaveBeenNthCalledWith(6, 7, "assocAdd", {ieeeadr: "0x02", noderelation: 1, nwkaddr: 2});
2414
- expect(mockZnpRequest).toHaveBeenNthCalledWith(7, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: 30});
2415
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2416
- 8,
2417
- 4,
2418
- "dataRequest",
2419
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 4},
2420
- 99,
2421
- );
2422
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2423
- Zdo.ClusterId.NETWORK_ADDRESS_REQUEST,
2424
- Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.NETWORK_ADDRESS_REQUEST, "0x02", false, 0),
2425
- expect.any(Number),
2426
- //9, 5, 'nwkAddrReq', {ieeeaddr: '0x02', reqtype: 0, startindex: 0}
2427
- );
2428
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2429
- 9,
2430
- 4,
2431
- "dataRequest",
2432
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 5},
2433
- 99,
2434
- );
2435
- });
2436
-
2437
- it("Send zcl frame network address fails because mac transaction expire when not being a parent, should retry", async () => {
2438
- basicMocks();
2439
- await adapter.start();
2440
- dataConfirmCode = 240;
2441
- assocGetWithAddressNodeRelation = 255;
2442
- mockZnpRequest.mockClear();
2443
- mockZnpRequestZdo.mockClear();
2444
- mockQueueExecute.mockClear();
2445
- const frame = Zcl.Frame.create(
2446
- Zcl.FrameType.GLOBAL,
2447
- Zcl.Direction.CLIENT_TO_SERVER,
2448
- true,
2449
- undefined,
2450
- 100,
2451
- "writeNoRsp",
2452
- 0,
2453
- [{attrId: 0, dataType: 0, attrData: null}],
2454
- {},
2455
- );
2456
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2457
- let error;
2458
- try {
2459
- await response;
2460
- } catch (e) {
2461
- error = e;
2462
- }
2463
-
2464
- expect(error.message).toStrictEqual("Data request failed with error: 'MAC transaction expired' (240)");
2465
- expect(mockZnpRequest).toHaveBeenCalledTimes(7);
2466
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2467
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2468
- 1,
2469
- 4,
2470
- "dataRequest",
2471
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2472
- 99,
2473
- );
2474
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2475
- 2,
2476
- 4,
2477
- "dataRequest",
2478
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 2},
2479
- 99,
2480
- );
2481
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 7, "assocGetWithAddress", {extaddr: "0x02", nwkaddr: 2});
2482
- expect(mockZnpRequest).toHaveBeenNthCalledWith(4, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: 30});
2483
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2484
- 5,
2485
- 4,
2486
- "dataRequest",
2487
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 3},
2488
- 99,
2489
- );
2490
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2491
- Zdo.ClusterId.NETWORK_ADDRESS_REQUEST,
2492
- Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.NETWORK_ADDRESS_REQUEST, "0x02", false, 0),
2493
- expect.any(Number),
2494
- //6, 5, 'nwkAddrReq', {ieeeaddr: '0x02', reqtype: 0, startindex: 0}
2495
- );
2496
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2497
- 6,
2498
- 4,
2499
- "dataRequest",
2500
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 4},
2501
- 99,
2502
- );
2503
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2504
- 7,
2505
- 4,
2506
- "dataRequest",
2507
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 5},
2508
- 99,
2509
- );
2510
- });
2511
-
2512
- it("Send zcl frame network address fails because mac no ack, should retry", async () => {
2513
- basicMocks();
2514
- await adapter.start();
2515
- dataConfirmCode = 233;
2516
- mockZnpRequest.mockClear();
2517
- mockZnpRequestZdo.mockClear();
2518
- mockQueueExecute.mockClear();
2519
- const frame = Zcl.Frame.create(
2520
- Zcl.FrameType.GLOBAL,
2521
- Zcl.Direction.CLIENT_TO_SERVER,
2522
- true,
2523
- undefined,
2524
- 100,
2525
- "writeNoRsp",
2526
- 0,
2527
- [{attrId: 0, dataType: 0, attrData: null}],
2528
- {},
2529
- );
2530
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2531
- let error;
2532
- try {
2533
- await response;
2534
- } catch (e) {
2535
- error = e;
2536
- }
2537
-
2538
- expect(error.message).toStrictEqual("Data request failed with error: 'MAC no ack' (233)");
2539
- expect(mockZnpRequest).toHaveBeenCalledTimes(6);
2540
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2541
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2542
- 1,
2543
- 4,
2544
- "dataRequest",
2545
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2546
- 99,
2547
- );
2548
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2549
- 2,
2550
- 4,
2551
- "dataRequest",
2552
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 2},
2553
- 99,
2554
- );
2555
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: 30});
2556
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2557
- 4,
2558
- 4,
2559
- "dataRequest",
2560
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 3},
2561
- 99,
2562
- );
2563
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2564
- Zdo.ClusterId.NETWORK_ADDRESS_REQUEST,
2565
- Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.NETWORK_ADDRESS_REQUEST, "0x02", false, 0),
2566
- expect.any(Number),
2567
- //5, 5, 'nwkAddrReq', {ieeeaddr: '0x02', reqtype: 0, startindex: 0}
2568
- );
2569
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2570
- 5,
2571
- 4,
2572
- "dataRequest",
2573
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 4},
2574
- 99,
2575
- );
2576
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2577
- 6,
2578
- 4,
2579
- "dataRequest",
2580
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 5},
2581
- 99,
2582
- );
2583
- });
2584
-
2585
- it("Send zcl frame network address fails because mac no ack with network address change, should retry", async () => {
2586
- basicMocks();
2587
- await adapter.start();
2588
- dataConfirmCode = 233;
2589
- mockZnpRequest.mockClear();
2590
- mockZnpRequestZdo.mockClear();
2591
- mockQueueExecute.mockClear();
2592
- const frame = Zcl.Frame.create(
2593
- Zcl.FrameType.GLOBAL,
2594
- Zcl.Direction.CLIENT_TO_SERVER,
2595
- true,
2596
- undefined,
2597
- 100,
2598
- "writeNoRsp",
2599
- 0,
2600
- [{attrId: 0, dataType: 0, attrData: null}],
2601
- {},
2602
- );
2603
- const response = adapter.sendZclFrameToEndpoint("0x03", 2, 20, frame, 10000, false, false);
2604
- let error;
2605
- try {
2606
- await response;
2607
- } catch (e) {
2608
- error = e;
2609
- }
2610
-
2611
- expect(error.message).toStrictEqual("Data request failed with error: 'MAC no ack' (233)");
2612
- // expect(mockZnpRequest).toHaveBeenCalledTimes(7);
2613
- // expect(mockZnpRequestZdo).toHaveBeenCalledTimes(1);
2614
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2615
- 1,
2616
- 4,
2617
- "dataRequest",
2618
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2619
- 99,
2620
- );
2621
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2622
- 2,
2623
- 4,
2624
- "dataRequest",
2625
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 2},
2626
- 99,
2627
- );
2628
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: 30});
2629
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2630
- 4,
2631
- 4,
2632
- "dataRequest",
2633
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 3},
2634
- 99,
2635
- );
2636
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
2637
- Zdo.ClusterId.NETWORK_ADDRESS_REQUEST,
2638
- Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.NETWORK_ADDRESS_REQUEST, "0x03", false, 0),
2639
- expect.any(Number),
2640
- //5, 5, 'nwkAddrReq', {ieeeaddr: '0x03', reqtype: 0, startindex: 0}
2641
- );
2642
- expect(mockZnpRequest).toHaveBeenNthCalledWith(5, 5, "extRouteDisc", {dstAddr: 3, options: 0, radius: 30});
2643
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2644
- 6,
2645
- 4,
2646
- "dataRequest",
2647
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 3, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 4},
2648
- 99,
2649
- );
2650
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2651
- 7,
2652
- 4,
2653
- "dataRequest",
2654
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 3, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 5},
2655
- 99,
2656
- );
2657
- });
2658
-
2659
- it("Send zcl frame network address fails because mac no ack with network address change, without recovery", async () => {
2660
- basicMocks();
2661
- await adapter.start();
2662
- dataConfirmCode = 233;
2663
- mockZnpRequest.mockClear();
2664
- mockQueueExecute.mockClear();
2665
- const frame = Zcl.Frame.create(
2666
- Zcl.FrameType.GLOBAL,
2667
- Zcl.Direction.CLIENT_TO_SERVER,
2668
- true,
2669
- undefined,
2670
- 100,
2671
- "writeNoRsp",
2672
- 0,
2673
- [{attrId: 0, dataType: 0, attrData: null}],
2674
- {},
2675
- );
2676
- const response = adapter.sendZclFrameToEndpoint("0x03", 2, 20, frame, 10000, false, true, undefined);
2677
- let error;
2678
- try {
2679
- await response;
2680
- } catch (e) {
2681
- error = e;
2682
- }
2683
-
2684
- expect(error.message).toStrictEqual("Data request failed with error: 'MAC no ack' (233)");
2685
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2686
- });
2687
-
2688
- it("Send zcl frame network address should retry on dataconfirm timeout", async () => {
2689
- basicMocks();
2690
- await adapter.start();
2691
- dataConfirmCode = 9999;
2692
- dataConfirmCodeReset = true;
2693
- mockZnpRequest.mockClear();
2694
- mockQueueExecute.mockClear();
2695
- const frame = Zcl.Frame.create(
2696
- Zcl.FrameType.GLOBAL,
2697
- Zcl.Direction.CLIENT_TO_SERVER,
2698
- true,
2699
- undefined,
2700
- 100,
2701
- "writeNoRsp",
2702
- 0,
2703
- [{attrId: 0, dataType: 0, attrData: null}],
2704
- {},
2705
- );
2706
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2707
- let error;
2708
- try {
2709
- await response;
2710
- } catch (e) {
2711
- error = e;
2712
- }
2713
- expect(error.message).toStrictEqual("Data request failed with error: 'Timeout' (9999)");
2714
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2715
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
2716
- 1,
2717
- 4,
2718
- "dataRequest",
2719
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 6, options: 0, radius: 30, srcendpoint: 1, transid: 1},
2720
- 99,
2721
- );
2722
- });
2723
-
2724
- it("Send zcl frame group", async () => {
2725
- basicMocks();
2726
- await adapter.start();
2727
-
2728
- mockZnpRequest.mockClear();
2729
- mockQueueExecute.mockClear();
2730
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2731
- await adapter.sendZclFrameToGroup(25, frame, 1);
2732
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2733
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2734
- expect(mockZnpRequest).toHaveBeenCalledWith(
2735
- 4,
2736
- "dataRequestExt",
2737
- {
2738
- clusterid: 0,
2739
- data: frame.toBuffer(),
2740
- destendpoint: 255,
2741
- dstaddr: "0x0000000000000019",
2742
- len: 5,
2743
- options: 0,
2744
- radius: 30,
2745
- srcendpoint: 1,
2746
- transid: 1,
2747
- dstaddrmode: 1,
2748
- dstpanid: 0,
2749
- },
2750
- 99,
2751
- );
2752
- });
2753
-
2754
- it("Send zcl frame group retry on MAC channel access failure", async () => {
2755
- basicMocks();
2756
- dataConfirmCode = 225;
2757
- dataConfirmCodeReset = true;
2758
- await adapter.start();
2759
- mockZnpRequest.mockClear();
2760
- mockQueueExecute.mockClear();
2761
- const frame = Zcl.Frame.create(
2762
- Zcl.FrameType.GLOBAL,
2763
- Zcl.Direction.CLIENT_TO_SERVER,
2764
- false,
2765
- undefined,
2766
- 100,
2767
- "writeNoRsp",
2768
- 0,
2769
- [{attrId: 0, dataType: 0, attrData: null}],
2770
- {},
2771
- );
2772
- await adapter.sendZclFrameToGroup(25, frame, 1);
2773
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2774
- expect(mockZnpRequest).toHaveBeenCalledTimes(2);
2775
- expect(mockZnpRequest).toHaveBeenCalledWith(
2776
- 4,
2777
- "dataRequestExt",
2778
- {
2779
- clusterid: 0,
2780
- data: frame.toBuffer(),
2781
- destendpoint: 255,
2782
- dstaddr: "0x0000000000000019",
2783
- len: 6,
2784
- options: 0,
2785
- radius: 30,
2786
- srcendpoint: 1,
2787
- transid: 1,
2788
- dstaddrmode: 1,
2789
- dstpanid: 0,
2790
- },
2791
- 99,
2792
- );
2793
- });
2794
-
2795
- it("Send zcl frame to all - DEFAULT", async () => {
2796
- basicMocks();
2797
- await adapter.start();
2798
-
2799
- mockZnpRequest.mockClear();
2800
- mockQueueExecute.mockClear();
2801
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2802
- await adapter.sendZclFrameToAll(242, frame, 250, BroadcastAddress.DEFAULT);
2803
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2804
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2805
- expect(mockZnpRequest).toHaveBeenCalledWith(
2806
- 4,
2807
- "dataRequestExt",
2808
- {
2809
- clusterid: 0,
2810
- data: frame.toBuffer(),
2811
- destendpoint: 242,
2812
- dstaddr: "0x000000000000fffc",
2813
- len: 5,
2814
- options: 0,
2815
- radius: 30,
2816
- srcendpoint: 250,
2817
- transid: 1,
2818
- dstaddrmode: 2,
2819
- dstpanid: 0,
2820
- },
2821
- undefined,
2822
- );
2823
- });
2824
-
2825
- it("Send zcl frame to all - RX_ON_WHEN_IDLE", async () => {
2826
- basicMocks();
2827
- await adapter.start();
2828
-
2829
- mockZnpRequest.mockClear();
2830
- mockQueueExecute.mockClear();
2831
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2832
- await adapter.sendZclFrameToAll(255, frame, 1, BroadcastAddress.RX_ON_WHEN_IDLE);
2833
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2834
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2835
- expect(mockZnpRequest).toHaveBeenCalledWith(
2836
- 4,
2837
- "dataRequestExt",
2838
- {
2839
- clusterid: 0,
2840
- data: frame.toBuffer(),
2841
- destendpoint: 255,
2842
- dstaddr: "0x000000000000fffd",
2843
- len: 5,
2844
- options: 0,
2845
- radius: 30,
2846
- srcendpoint: 1,
2847
- transid: 1,
2848
- dstaddrmode: 2,
2849
- dstpanid: 0,
2850
- },
2851
- undefined,
2852
- );
2853
- });
2854
-
2855
- it("Send zcl frame to all - SLEEPY", async () => {
2856
- basicMocks();
2857
- await adapter.start();
2858
-
2859
- mockZnpRequest.mockClear();
2860
- mockQueueExecute.mockClear();
2861
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2862
- await adapter.sendZclFrameToAll(255, frame, 1, BroadcastAddress.SLEEPY);
2863
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2864
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2865
- expect(mockZnpRequest).toHaveBeenCalledWith(
2866
- 4,
2867
- "dataRequestExt",
2868
- {
2869
- clusterid: 0,
2870
- data: frame.toBuffer(),
2871
- destendpoint: 255,
2872
- dstaddr: "0x000000000000ffff",
2873
- len: 5,
2874
- options: 0,
2875
- radius: 30,
2876
- srcendpoint: 1,
2877
- transid: 1,
2878
- dstaddrmode: 2,
2879
- dstpanid: 0,
2880
- },
2881
- undefined,
2882
- );
2883
- });
2884
-
2885
- it("Send zcl frame network address transaction number shouldnt go higher than 255", async () => {
2886
- basicMocks();
2887
- await adapter.start();
2888
- let transactionID = 0;
2889
-
2890
- mockZnpRequest.mockClear();
2891
- mockQueueExecute.mockClear();
2892
-
2893
- for (let i = 0; i < 300; i++) {
2894
- if (transactionID > 200) {
2895
- transactionID = 0;
2896
- }
2897
-
2898
- const frame = Zcl.Frame.create(
2899
- Zcl.FrameType.GLOBAL,
2900
- Zcl.Direction.CLIENT_TO_SERVER,
2901
- true,
2902
- undefined,
2903
- 100,
2904
- "writeNoRsp",
2905
- 0,
2906
- [{attrId: 0, dataType: 0, attrData: null}],
2907
- {},
2908
- );
2909
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
2910
- }
2911
-
2912
- const got: number[] = [];
2913
- for (let i = 0; i < 300; i++) {
2914
- got.push(mockZnpRequest.mock.calls[i][2].transid);
2915
- }
2916
-
2917
- expect(got[0]).toBe(1);
2918
- expect(got.find((g) => g === 0)).toBe(undefined);
2919
- expect(got.find((g) => g > 255)).toBe(undefined);
2920
- expect(got.filter((g) => g === 1).length).toBe(2);
2921
- expect(got.filter((g) => g === 255).length).toBe(1);
2922
- expect(mockZnpRequest).toHaveBeenCalledTimes(300);
2923
- });
2924
-
2925
- it("Send zcl frame group dataConfirm fails", async () => {
2926
- basicMocks();
2927
- await adapter.start();
2928
- dataConfirmCode = 184;
2929
- let error;
2930
- mockZnpRequest.mockClear();
2931
- mockQueueExecute.mockClear();
2932
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2933
- try {
2934
- await adapter.sendZclFrameToGroup(25, frame);
2935
- } catch (e) {
2936
- error = e;
2937
- }
2938
- expect(mockQueueExecute.mock.calls[0][1]).toBe(undefined);
2939
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
2940
- expect(mockZnpRequest).toHaveBeenCalledWith(
2941
- 4,
2942
- "dataRequestExt",
2943
- {
2944
- clusterid: 0,
2945
- data: frame.toBuffer(),
2946
- destendpoint: 255,
2947
- dstaddr: "0x0000000000000019",
2948
- len: 5,
2949
- options: 0,
2950
- radius: 30,
2951
- srcendpoint: 1,
2952
- transid: 1,
2953
- dstaddrmode: 1,
2954
- dstpanid: 0,
2955
- },
2956
- 99,
2957
- );
2958
- expect(error.message).toStrictEqual("Data request failed with error: 'undefined' (184)");
2959
- });
2960
-
2961
- it("Send zcl frame network address and default response", async () => {
2962
- basicMocks();
2963
- await adapter.start();
2964
-
2965
- mockZnpRequest.mockClear();
2966
- mockQueueExecute.mockClear();
2967
-
2968
- const responseMismatchFrame = Zcl.Frame.create(
2969
- Zcl.FrameType.GLOBAL,
2970
- Zcl.Direction.SERVER_TO_CLIENT,
2971
- true,
2972
- undefined,
2973
- 102,
2974
- "readRsp",
2975
- 0,
2976
- [{attrId: 0, attrData: 5, dataType: 32, status: 0}],
2977
- {},
2978
- );
2979
- const responseFrame = Zcl.Frame.create(
2980
- Zcl.FrameType.GLOBAL,
2981
- Zcl.Direction.SERVER_TO_CLIENT,
2982
- true,
2983
- undefined,
2984
- 100,
2985
- "readRsp",
2986
- 0,
2987
- [{attrId: 0, attrData: 2, dataType: 32, status: 0}],
2988
- {},
2989
- );
2990
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
2991
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
2992
- clusterid: 0,
2993
- srcendpoint: 20,
2994
- srcaddr: 2,
2995
- linkquality: 101,
2996
- groupid: 12,
2997
- data: responseFrame.toBuffer(),
2998
- });
2999
- const objectMismatch = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3000
- clusterid: 0,
3001
- srcendpoint: 20,
3002
- srcaddr: 2,
3003
- linkquality: 101,
3004
- groupid: 12,
3005
- data: responseMismatchFrame.toBuffer(),
3006
- });
3007
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3008
- znpReceived(objectMismatch);
3009
- znpReceived(object);
3010
- const result = await response;
3011
-
3012
- expect(mockZnpRequest).toHaveBeenCalledWith(
3013
- 4,
3014
- "dataRequest",
3015
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 1},
3016
- 99,
3017
- );
3018
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
3019
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3020
- expect(result.endpoint).toStrictEqual(20);
3021
- expect(result.groupID).toStrictEqual(12);
3022
- expect(result.linkquality).toStrictEqual(101);
3023
- expect(result.address).toStrictEqual(2);
3024
- expect(result.groupID).toStrictEqual(12);
3025
- expect(result.data).toStrictEqual(Buffer.from([24, 100, 1, 0, 0, 0, 32, 2]));
3026
- });
3027
-
3028
- it("Send zcl frame network address and default response", async () => {
3029
- basicMocks();
3030
- await adapter.start();
3031
-
3032
- mockZnpRequest.mockClear();
3033
- mockQueueExecute.mockClear();
3034
-
3035
- const responseMismatchFrame = Zcl.Frame.create(
3036
- Zcl.FrameType.GLOBAL,
3037
- Zcl.Direction.SERVER_TO_CLIENT,
3038
- true,
3039
- undefined,
3040
- 102,
3041
- "readRsp",
3042
- 0,
3043
- [{attrId: 0, attrData: 5, dataType: 32, status: 0}],
3044
- {},
3045
- );
3046
- const responseFrame = Zcl.Frame.create(
3047
- Zcl.FrameType.GLOBAL,
3048
- Zcl.Direction.SERVER_TO_CLIENT,
3049
- true,
3050
- undefined,
3051
- 100,
3052
- "readRsp",
3053
- 0,
3054
- [{attrId: 0, attrData: 2, dataType: 32, status: 0}],
3055
- {},
3056
- );
3057
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, false, undefined, 100, "read", 0, [{attrId: 0}], {});
3058
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3059
- clusterid: 0,
3060
- srcendpoint: 20,
3061
- srcaddr: 2,
3062
- linkquality: 101,
3063
- groupid: 12,
3064
- data: responseFrame.toBuffer(),
3065
- });
3066
- const objectMismatch = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3067
- clusterid: 0,
3068
- srcendpoint: 20,
3069
- srcaddr: 2,
3070
- linkquality: 101,
3071
- groupid: 12,
3072
- data: responseMismatchFrame.toBuffer(),
3073
- });
3074
- const defaultReponse = Zcl.Frame.create(
3075
- Zcl.FrameType.GLOBAL,
3076
- Zcl.Direction.SERVER_TO_CLIENT,
3077
- true,
3078
- undefined,
3079
- 100,
3080
- "defaultRsp",
3081
- 0,
3082
- {cmdId: 0, status: 0},
3083
- {},
3084
- );
3085
- const defaultObject = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3086
- clusterid: 0,
3087
- srcendpoint: 20,
3088
- srcaddr: 2,
3089
- linkquality: 101,
3090
- groupid: 12,
3091
- data: defaultReponse.toBuffer(),
3092
- });
3093
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3094
- znpReceived(objectMismatch);
3095
- znpReceived(defaultObject);
3096
- znpReceived(object);
3097
- const result = await response;
3098
-
3099
- expect(mockZnpRequest).toHaveBeenCalledWith(
3100
- 4,
3101
- "dataRequest",
3102
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 1},
3103
- 99,
3104
- );
3105
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
3106
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3107
- expect(result.endpoint).toStrictEqual(20);
3108
- expect(result.groupID).toStrictEqual(12);
3109
- expect(result.linkquality).toStrictEqual(101);
3110
- expect(result.address).toStrictEqual(2);
3111
- expect(result.groupID).toStrictEqual(12);
3112
- expect(result.data).toStrictEqual(Buffer.from([24, 100, 1, 0, 0, 0, 32, 2]));
3113
- });
3114
-
3115
- it("Send zcl frame network address data confirm fails with default response", async () => {
3116
- basicMocks();
3117
- await adapter.start();
3118
- dataConfirmCode = 201;
3119
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, false, undefined, 100, "read", 0, [{attrId: 0}], {});
3120
- let error;
3121
- try {
3122
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3123
- } catch (e) {
3124
- error = e;
3125
- }
3126
- expect(error.message).toStrictEqual("Data request failed with error: 'undefined' (201)");
3127
- });
3128
-
3129
- it("Send zcl frame network address data confirm fails without default response", async () => {
3130
- basicMocks();
3131
- await adapter.start();
3132
- dataConfirmCode = 201;
3133
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 100, "read", 0, [{attrId: 0}], {});
3134
- let error;
3135
- try {
3136
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3137
- } catch (e) {
3138
- error = e;
3139
- }
3140
- expect(error.message).toStrictEqual("Data request failed with error: 'undefined' (201)");
3141
- });
3142
-
3143
- it("Send zcl frame network address timeout should discover route and retry", async () => {
3144
- basicMocks();
3145
- await adapter.start();
3146
-
3147
- mockZnpRequest.mockClear();
3148
- mockQueueExecute.mockClear();
3149
- assocGetWithAddressNodeRelation = 2;
3150
- const responseMismatchFrame = Zcl.Frame.create(
3151
- Zcl.FrameType.GLOBAL,
3152
- Zcl.Direction.SERVER_TO_CLIENT,
3153
- true,
3154
- undefined,
3155
- 102,
3156
- "readRsp",
3157
- 0,
3158
- [{attrId: 0, attrData: 5, dataType: 32, status: 0}],
3159
- {},
3160
- );
3161
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, false, undefined, 100, "read", 0, [{attrId: 0}], {});
3162
- const objectMismatch = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3163
- clusterid: 0,
3164
- srcendpoint: 20,
3165
- srcaddr: 2,
3166
- linkquality: 101,
3167
- groupid: 12,
3168
- data: responseMismatchFrame.toBuffer(),
3169
- });
3170
- let error;
3171
- try {
3172
- const spy = mockSetTimeout();
3173
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 1, false, false);
3174
- znpReceived(objectMismatch);
3175
- await response;
3176
- spy.mockRestore();
3177
- } catch (e) {
3178
- error = e;
3179
- }
3180
-
3181
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
3182
- expect(mockZnpRequest).toHaveBeenCalledTimes(4);
3183
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
3184
- 1,
3185
- 4,
3186
- "dataRequest",
3187
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 1},
3188
- 99,
3189
- );
3190
- expect(mockZnpRequest).toHaveBeenNthCalledWith(2, 7, "assocGetWithAddress", {extaddr: "0x02", nwkaddr: 2});
3191
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: Constants.AF.DEFAULT_RADIUS});
3192
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
3193
- 4,
3194
- 4,
3195
- "dataRequest",
3196
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 2},
3197
- 99,
3198
- );
3199
- expect(error).toStrictEqual(new Error("Timeout - 2 - 20 - 100 - 0 - 1 after 1ms"));
3200
- });
3201
-
3202
- it("Send zcl frame network address timeout should discover route, rewrite child entry and retry for sleepy end device", async () => {
3203
- basicMocks();
3204
- await adapter.start();
3205
-
3206
- mockZnpRequest.mockClear();
3207
- mockQueueExecute.mockClear();
3208
-
3209
- const responseMismatchFrame = Zcl.Frame.create(
3210
- Zcl.FrameType.GLOBAL,
3211
- Zcl.Direction.SERVER_TO_CLIENT,
3212
- true,
3213
- undefined,
3214
- 102,
3215
- "readRsp",
3216
- 0,
3217
- [{attrId: 0, attrData: 5, dataType: 32, status: 0}],
3218
- {},
3219
- );
3220
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, false, undefined, 100, "read", 0, [{attrId: 0}], {});
3221
- const objectMismatch = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3222
- clusterid: 0,
3223
- srcendpoint: 20,
3224
- srcaddr: 2,
3225
- linkquality: 101,
3226
- groupid: 12,
3227
- data: responseMismatchFrame.toBuffer(),
3228
- });
3229
- let error;
3230
- try {
3231
- const spy = mockSetTimeout();
3232
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 1, false, false);
3233
- znpReceived(objectMismatch);
3234
- await response;
3235
- spy.mockRestore();
3236
- } catch (e) {
3237
- error = e;
3238
- }
3239
-
3240
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
3241
- expect(mockZnpRequest).toHaveBeenCalledTimes(6);
3242
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
3243
- 1,
3244
- 4,
3245
- "dataRequest",
3246
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 1},
3247
- 99,
3248
- );
3249
- expect(mockZnpRequest).toHaveBeenNthCalledWith(2, 7, "assocGetWithAddress", {extaddr: "0x02", nwkaddr: 2});
3250
- expect(mockZnpRequest).toHaveBeenNthCalledWith(3, 7, "assocRemove", {ieeeadr: "0x02"});
3251
- expect(mockZnpRequest).toHaveBeenNthCalledWith(4, 7, "assocAdd", {ieeeadr: "0x02", nwkaddr: 2, noderelation: 1});
3252
- expect(mockZnpRequest).toHaveBeenNthCalledWith(5, 5, "extRouteDisc", {dstAddr: 2, options: 0, radius: Constants.AF.DEFAULT_RADIUS});
3253
- expect(mockZnpRequest).toHaveBeenNthCalledWith(
3254
- 6,
3255
- 4,
3256
- "dataRequest",
3257
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 2},
3258
- 99,
3259
- );
3260
- expect(error).toStrictEqual(new Error("Timeout - 2 - 20 - 100 - 0 - 1 after 1ms"));
3261
- });
3262
-
3263
- it("Send zcl frame network address with default response timeout shouldnt care because command has response", async () => {
3264
- basicMocks();
3265
- await adapter.start();
3266
-
3267
- mockZnpRequest.mockClear();
3268
- mockQueueExecute.mockClear();
3269
- const responseFrame = Zcl.Frame.create(
3270
- Zcl.FrameType.GLOBAL,
3271
- Zcl.Direction.SERVER_TO_CLIENT,
3272
- true,
3273
- undefined,
3274
- 100,
3275
- "readRsp",
3276
- 0,
3277
- [{attrId: 0, attrData: 2, dataType: 32, status: 0}],
3278
- {},
3279
- );
3280
- const frame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, false, undefined, 100, "read", 0, [{attrId: 0}], {});
3281
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3282
- clusterid: 0,
3283
- srcendpoint: 20,
3284
- srcaddr: 2,
3285
- linkquality: 101,
3286
- groupid: 12,
3287
- data: responseFrame.toBuffer(),
3288
- });
3289
- const response = adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3290
- znpReceived(object);
3291
-
3292
- let error = null;
3293
- try {
3294
- await response;
3295
- } catch (e) {
3296
- error = e;
3297
- }
3298
- expect(mockZnpRequest).toHaveBeenCalledWith(
3299
- 4,
3300
- "dataRequest",
3301
- {clusterid: 0, data: frame.toBuffer(), destendpoint: 20, dstaddr: 2, len: 5, options: 0, radius: 30, srcendpoint: 1, transid: 1},
3302
- 99,
3303
- );
3304
- expect(mockQueueExecute.mock.calls[0][1]).toBe(2);
3305
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3306
- expect(error).toStrictEqual(null);
3307
- });
3308
-
3309
- it("Supports backup", async () => {
3310
- basicMocks();
3311
- await adapter.start();
3312
- expect(await adapter.supportsBackup()).toBeTruthy();
3313
- });
3314
-
3315
- it("Incoming message extended", async () => {
3316
- basicMocks();
3317
- await adapter.start();
3318
- let zclData;
3319
- const responseFrame = Zcl.Frame.create(
3320
- Zcl.FrameType.GLOBAL,
3321
- Zcl.Direction.SERVER_TO_CLIENT,
3322
- true,
3323
- undefined,
3324
- 100,
3325
- "readRsp",
3326
- 0,
3327
- [{attrId: 0, attrData: 2, dataType: 32, status: 0}],
3328
- {},
3329
- );
3330
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsgExt", {
3331
- clusterid: 0,
3332
- srcendpoint: 20,
3333
- srcaddr: 2,
3334
- linkquality: 101,
3335
- groupid: 12,
3336
- data: responseFrame.toBuffer(),
3337
- });
3338
- adapter.on("zclPayload", (p) => {
3339
- zclData = p;
3340
- });
3341
- znpReceived(object);
3342
- expect(zclData.endpoint).toStrictEqual(20);
3343
- expect(zclData.groupID).toStrictEqual(12);
3344
- expect(zclData.linkquality).toStrictEqual(101);
3345
- expect(zclData.address).toStrictEqual(2);
3346
- expect(zclData.groupID).toStrictEqual(12);
3347
- expect(zclData.data).toStrictEqual(Buffer.from([24, 100, 1, 0, 0, 0, 32, 2]));
3348
- expect(zclData.header.commandIdentifier).toBe(1);
3349
- });
3350
-
3351
- it("Incoming message raw (not ZCL)", async () => {
3352
- basicMocks();
3353
- await adapter.start();
3354
- let rawData;
3355
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3356
- clusterid: 1,
3357
- srcendpoint: 20,
3358
- srcaddr: 2,
3359
- linkquality: 101,
3360
- groupid: 12,
3361
- data: Buffer.from([0x0, 0x1]),
3362
- });
3363
- adapter.on("zclPayload", (p) => {
3364
- rawData = p;
3365
- });
3366
- znpReceived(object);
3367
- expect(rawData.clusterID).toStrictEqual(1);
3368
- expect(rawData.endpoint).toStrictEqual(20);
3369
- expect(rawData.groupID).toStrictEqual(12);
3370
- expect(rawData.linkquality).toStrictEqual(101);
3371
- expect(rawData.address).toStrictEqual(2);
3372
- expect(rawData.data).toStrictEqual(Buffer.from([0x0, 0x01]));
3373
- });
3374
-
3375
- it("Adapter disconnected", async () => {
3376
- basicMocks();
3377
- await adapter.start();
3378
- let closeEvent = false;
3379
- adapter.on("disconnected", () => {
3380
- closeEvent = true;
3381
- });
3382
- znpClose();
3383
- expect(closeEvent).toBeTruthy();
3384
- });
3385
-
3386
- it("Adapter disconnected dont emit when closing", async () => {
3387
- basicMocks();
3388
- await adapter.start();
3389
- await adapter.stop();
3390
- let closeEvent = false;
3391
- adapter.on("disconnected", () => {
3392
- closeEvent = true;
3393
- });
3394
- znpClose();
3395
- expect(closeEvent).toBeFalsy();
3396
- });
3397
-
3398
- it("Device joined", async () => {
3399
- basicMocks();
3400
- await adapter.start();
3401
- let deviceJoin;
3402
- const object = mockZpiObject(Type.AREQ, Subsystem.ZDO, "tcDeviceInd", {nwkaddr: 123, extaddr: "0x123"});
3403
- adapter.on("deviceJoined", (p) => {
3404
- deviceJoin = p;
3405
- });
3406
- znpReceived(object);
3407
- expect(deviceJoin).toStrictEqual({ieeeAddr: "0x123", networkAddress: 123});
3408
- });
3409
-
3410
- it("Device announce", async () => {
3411
- basicMocks();
3412
- await adapter.start();
3413
- mockZnpRequest.mockClear();
3414
- mockQueueExecute.mockClear();
3415
- const object = mockZdoZpiObject<EndDeviceAnnounce>("endDeviceAnnceInd", 123, [
3416
- Zdo.Status.SUCCESS,
3417
- {
3418
- capabilities: DUMMY_NODE_DESC_RSP_CAPABILITIES,
3419
- eui64: "0x123",
3420
- nwkAddress: 123,
3421
- },
3422
- ]);
3423
- adapter.on("zdoResponse", (clusterId, payload) => {
3424
- expect(clusterId).toStrictEqual(Zdo.ClusterId.END_DEVICE_ANNOUNCE);
3425
- expect(payload[0]).toStrictEqual(Zdo.Status.SUCCESS);
3426
- expect(payload[1]).toStrictEqual({eui64: "0x123", nwkAddress: 123, capabilities: DUMMY_NODE_DESC_RSP_CAPABILITIES});
3427
- });
3428
- znpReceived(object);
3429
- expect(mockZnpRequest).toHaveBeenCalledTimes(0);
3430
- });
3431
-
3432
- it("Device announce should discover route to end devices", async () => {
3433
- basicMocks();
3434
- await adapter.start();
3435
- mockZnpRequest.mockClear();
3436
- mockQueueExecute.mockClear();
3437
- const object = mockZdoZpiObject<EndDeviceAnnounce>("endDeviceAnnceInd", 123, [
3438
- Zdo.Status.SUCCESS,
3439
- {
3440
- capabilities: {...DUMMY_NODE_DESC_RSP_CAPABILITIES, deviceType: 0},
3441
- eui64: "0x123",
3442
- nwkAddress: 123,
3443
- },
3444
- ]);
3445
- adapter.on("zdoResponse", (clusterId, payload) => {
3446
- expect(clusterId).toStrictEqual(Zdo.ClusterId.END_DEVICE_ANNOUNCE);
3447
- expect(payload[0]).toStrictEqual(Zdo.Status.SUCCESS);
3448
- expect(payload[1]).toStrictEqual({eui64: "0x123", nwkAddress: 123, capabilities: {...DUMMY_NODE_DESC_RSP_CAPABILITIES, deviceType: 0}});
3449
- });
3450
- znpReceived(object);
3451
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3452
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.ZDO, "extRouteDisc", {dstAddr: 123, options: 0, radius: 30});
3453
-
3454
- // Should debounce route discovery.
3455
- znpReceived(object);
3456
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3457
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.ZDO, "extRouteDisc", {dstAddr: 123, options: 0, radius: 30});
3458
- });
3459
-
3460
- it("Network address response", async () => {
3461
- basicMocks();
3462
- await adapter.start();
3463
- const object = mockZdoZpiObject<NetworkAddressResponse>("nwkAddrRsp", 124, [
3464
- Zdo.Status.SUCCESS,
3465
- {
3466
- eui64: "0x123",
3467
- nwkAddress: 124,
3468
- assocDevList: [],
3469
- startIndex: 0,
3470
- },
3471
- ]);
3472
- adapter.on("zdoResponse", (clusterId, payload) => {
3473
- expect(clusterId).toStrictEqual(Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE);
3474
- expect(payload[0]).toStrictEqual(Zdo.Status.SUCCESS);
3475
- expect(payload[1]).toStrictEqual({eui64: "0x123", nwkAddress: 124, assocDevList: [], startIndex: 0});
3476
- });
3477
- znpReceived(object);
3478
- });
3479
-
3480
- it("Concentrator Callback Indication", async () => {
3481
- basicMocks();
3482
- await adapter.start();
3483
- const object = mockZpiObject(Type.AREQ, Subsystem.ZDO, "concentratorIndCb", {srcaddr: 124, extaddr: "0x123"});
3484
- adapter.on("zdoResponse", (clusterId, payload) => {
3485
- expect(clusterId).toStrictEqual(Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE);
3486
- expect(payload[0]).toStrictEqual(Zdo.Status.SUCCESS);
3487
- expect(payload[1]).toStrictEqual({eui64: "0x123", nwkAddress: 124, assocDevList: [], startIndex: 0});
3488
- });
3489
- znpReceived(object);
3490
- });
3491
-
3492
- it("Device leave", async () => {
3493
- basicMocks();
3494
- await adapter.start();
3495
- let deviceAnnounce;
3496
- const object = mockZpiObject(Type.AREQ, Subsystem.ZDO, "leaveInd", {srcaddr: 123, extaddr: "0x123"});
3497
- adapter.on("deviceLeave", (p) => {
3498
- deviceAnnounce = p;
3499
- });
3500
- znpReceived(object);
3501
- expect(deviceAnnounce).toStrictEqual({ieeeAddr: "0x123", networkAddress: 123});
3502
- });
3503
-
3504
- it("Ignore device leave with rejoin", async () => {
3505
- basicMocks();
3506
- await adapter.start();
3507
- let deviceAnnounce;
3508
- const object = mockZpiObject(Type.AREQ, Subsystem.ZDO, "leaveInd", {srcaddr: 123, extaddr: "0x123", rejoin: true});
3509
- adapter.on("deviceLeave", (p) => {
3510
- deviceAnnounce = p;
3511
- });
3512
- znpReceived(object);
3513
- expect(deviceAnnounce).toStrictEqual(undefined);
3514
- });
3515
-
3516
- it("Do nothing wiht non areq event", async () => {
3517
- basicMocks();
3518
- await adapter.start();
3519
- let deviceLeave;
3520
- const object = mockZpiObject(Type.SREQ, Subsystem.ZDO, "leaveInd", {srcaddr: 123, extaddr: "0x123"});
3521
- adapter.on("deviceLeave", (p) => {
3522
- deviceLeave = p;
3523
- });
3524
- znpReceived(object);
3525
- expect(deviceLeave).toStrictEqual(undefined);
3526
- });
3527
-
3528
- it("Get network parameters", async () => {
3529
- basicMocks();
3530
- await adapter.start();
3531
- mockZnpRequest.mockClear();
3532
- mockQueueExecute.mockClear();
3533
- const result = await adapter.getNetworkParameters();
3534
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3535
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.ZDO, "extNwkInfo", {});
3536
- expect(result).toStrictEqual({channel: 21, extendedPanID: "0x00124b0009d69f77", panID: 123, nwkUpdateID: 0});
3537
- });
3538
-
3539
- it("Set interpan channel", async () => {
3540
- basicMocks();
3541
- await adapter.start();
3542
- mockZnpRequest.mockClear();
3543
- mockQueueExecute.mockClear();
3544
- await adapter.setChannelInterPAN(14);
3545
- expect(mockZnpRequest).toHaveBeenCalledTimes(2);
3546
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.AF, "interPanCtl", {cmd: 1, data: [14]});
3547
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.AF, "interPanCtl", {cmd: 2, data: [12]});
3548
-
3549
- mockZnpRequest.mockClear();
3550
- mockQueueExecute.mockClear();
3551
- await adapter.setChannelInterPAN(15);
3552
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3553
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.AF, "interPanCtl", {cmd: 1, data: [15]});
3554
- });
3555
-
3556
- it("Restore interpan channel", async () => {
3557
- basicMocks();
3558
- await adapter.start();
3559
- mockZnpRequest.mockClear();
3560
- mockQueueExecute.mockClear();
3561
- await adapter.restoreChannelInterPAN();
3562
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3563
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.AF, "interPanCtl", {cmd: 0, data: []});
3564
- });
3565
-
3566
- it("Send zcl frame interpan", async () => {
3567
- basicMocks();
3568
- await adapter.start();
3569
- mockZnpRequest.mockClear();
3570
- mockQueueExecute.mockClear();
3571
- await adapter.sendZclFrameInterPANToIeeeAddr(touchlinkIdentifyRequest, "0x0017880104c9cd33");
3572
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3573
- expect(mockZnpRequest).toHaveBeenCalledWith(
3574
- 4,
3575
- "dataRequestExt",
3576
- {
3577
- clusterid: 4096,
3578
- data: touchlinkIdentifyRequest.toBuffer(),
3579
- destendpoint: 254,
3580
- dstaddr: "0x0017880104c9cd33",
3581
- len: 9,
3582
- options: 0,
3583
- radius: 30,
3584
- srcendpoint: 12,
3585
- transid: 1,
3586
- dstaddrmode: 3,
3587
- dstpanid: 65535,
3588
- },
3589
- undefined,
3590
- );
3591
- });
3592
-
3593
- it("Send zcl frame interpan with response", async () => {
3594
- basicMocks();
3595
- await adapter.start();
3596
- mockZnpRequest.mockClear();
3597
- mockQueueExecute.mockClear();
3598
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsgExt", {
3599
- clusterid: 4096,
3600
- srcendpoint: 0xfe,
3601
- srcaddr: 12394,
3602
- linkquality: 101,
3603
- groupid: 0,
3604
- data: touchlinkScanResponse.toBuffer(),
3605
- });
3606
-
3607
- let result: ZclPayload | Promise<ZclPayload> = adapter.sendZclFrameInterPANBroadcast(touchlinkScanRequest, 1000);
3608
- znpReceived(object);
3609
- result = await result;
3610
-
3611
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3612
- expect(mockZnpRequest).toHaveBeenCalledWith(
3613
- 4,
3614
- "dataRequestExt",
3615
- {
3616
- clusterid: 4096,
3617
- data: touchlinkScanRequest.toBuffer(),
3618
- destendpoint: 254,
3619
- dstaddr: "0x000000000000ffff",
3620
- len: 9,
3621
- options: 0,
3622
- radius: 30,
3623
- srcendpoint: 12,
3624
- transid: 1,
3625
- dstaddrmode: 2,
3626
- dstpanid: 65535,
3627
- },
3628
- undefined,
3629
- );
3630
- expect(deepClone(result)).toStrictEqual({
3631
- clusterID: 4096,
3632
- data: {
3633
- type: "Buffer",
3634
- data: [9, 12, 1, 1, 0, 0, 0, 10, 5, 6, 12, 0, 11, 0, 0, 0, 51, 205, 217, 4, 1, 33, 23, 0, 1, 12, 13, 0, 5, 0, 10, 5],
3635
- },
3636
- header: {
3637
- frameControl: {frameType: 1, manufacturerSpecific: false, direction: 1, disableDefaultResponse: false, reservedBits: 0},
3638
- transactionSequenceNumber: 12,
3639
- commandIdentifier: 1,
3640
- },
3641
- address: 12394,
3642
- endpoint: 254,
3643
- linkquality: 101,
3644
- groupID: 0,
3645
- wasBroadcast: false,
3646
- });
3647
- });
3648
-
3649
- it("Send zcl frame interpan throw exception when command has no response", async () => {
3650
- basicMocks();
3651
- await adapter.start();
3652
- mockZnpRequest.mockClear();
3653
- mockQueueExecute.mockClear();
3654
- let error;
3655
- try {
3656
- await adapter.sendZclFrameInterPANBroadcast(touchlinkIdentifyRequest, 1000);
3657
- } catch (e) {
3658
- error = e;
3659
- }
3660
- expect(error).toStrictEqual(new Error(`Command 'identifyRequest' has no response, cannot wait for response`));
3661
- });
3662
-
3663
- it("Send zcl frame interpan throw exception data request fails", async () => {
3664
- basicMocks();
3665
- dataRequestExtCode = 99;
3666
- await adapter.start();
3667
- mockZnpRequest.mockClear();
3668
- mockQueueExecute.mockClear();
3669
- let error;
3670
- try {
3671
- await adapter.sendZclFrameInterPANBroadcast(touchlinkScanRequest, 1000);
3672
- } catch (e) {
3673
- error = e;
3674
- }
3675
- expect(error).toStrictEqual(new Error(`Data request failed with code '99'`));
3676
- });
3677
-
3678
- it("Refuse to start when ping fails", async () => {
3679
- mockZnpRequest.mockImplementation((subsystem, command, payload, _expectedStatus) => {
3680
- const missing = () => {
3681
- const msg = `Not implemented - ${Subsystem[subsystem]} - ${command} - ${JSON.stringify(payload)}`;
3682
- console.log(msg);
3683
- throw new Error(msg);
3684
- };
3685
-
3686
- if (subsystem === Subsystem.SYS && command === "ping") {
3687
- throw new Error("Couldnt lock port");
3688
- }
3689
-
3690
- missing();
3691
- });
3692
-
3693
- let error;
3694
- try {
3695
- await adapter.start();
3696
- } catch (e) {
3697
- error = e;
3698
- }
3699
- expect(error).toStrictEqual(new Error("Failed to connect to the adapter (Error: Couldnt lock port)"));
3700
- });
3701
-
3702
- it("Wait for", async () => {
3703
- basicMocks();
3704
- await adapter.start();
3705
-
3706
- const responseFrame = Zcl.Frame.create(
3707
- Zcl.FrameType.GLOBAL,
3708
- Zcl.Direction.SERVER_TO_CLIENT,
3709
- true,
3710
- undefined,
3711
- 100,
3712
- "readRsp",
3713
- 0,
3714
- [{attrId: 0, attrData: 2, dataType: 32, status: 0}],
3715
- {},
3716
- );
3717
- const object = mockZpiObject(Type.AREQ, Subsystem.AF, "incomingMsg", {
3718
- clusterid: 0,
3719
- srcendpoint: 20,
3720
- srcaddr: 2,
3721
- linkquality: 101,
3722
- groupid: 12,
3723
- data: responseFrame.toBuffer(),
3724
- });
3725
- const wait = adapter.waitFor(2, 20, 0, 1, 100, 0, 1, 10);
3726
- znpReceived(object);
3727
- const result = await wait.promise;
3728
- expect(result.endpoint).toStrictEqual(20);
3729
- expect(result.groupID).toStrictEqual(12);
3730
- expect(result.linkquality).toStrictEqual(101);
3731
- expect(result.address).toStrictEqual(2);
3732
- expect(result.groupID).toStrictEqual(12);
3733
- expect(result.data).toStrictEqual(Buffer.from([24, 100, 1, 0, 0, 0, 32, 2]));
3734
- });
3735
-
3736
- it("Command should fail when in interpan", async () => {
3737
- const frame = Zcl.Frame.create(
3738
- Zcl.FrameType.GLOBAL,
3739
- Zcl.Direction.CLIENT_TO_SERVER,
3740
- true,
3741
- undefined,
3742
- 100,
3743
- "writeNoRsp",
3744
- 0,
3745
- [{attrId: 0, dataType: 0, attrData: null}],
3746
- {},
3747
- );
3748
- basicMocks();
3749
- await adapter.start();
3750
-
3751
- await adapter.setChannelInterPAN(14);
3752
- mockZnpRequest.mockClear();
3753
- mockQueueExecute.mockClear();
3754
- let error;
3755
- try {
3756
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3757
- } catch (e) {
3758
- error = e;
3759
- }
3760
- expect(error).toStrictEqual(new Error("Cannot execute command, in Inter-PAN mode"));
3761
- expect(mockZnpRequest).toHaveBeenCalledTimes(0);
3762
-
3763
- await adapter.restoreChannelInterPAN();
3764
- mockZnpRequest.mockClear();
3765
- mockQueueExecute.mockClear();
3766
-
3767
- await adapter.sendZclFrameToEndpoint("0x02", 2, 20, frame, 10000, false, false);
3768
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3769
- });
3770
-
3771
- it("Sends proper ZDO request payload for PERMIT_JOINING_REQUEST to target", async () => {
3772
- basicMocks();
3773
- await adapter.start();
3774
- mockZnpRequestZdo.mockClear();
3775
-
3776
- const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
3777
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, 250, 1, []);
3778
-
3779
- await adapter.sendZdo("0x1122334455667788", 1234, clusterId, zdoPayload, true);
3780
-
3781
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
3782
- clusterId,
3783
- Buffer.from([AddressMode.ADDR_16BIT, 1234 & 0xff, (1234 >> 8) & 0xff, ...zdoPayload]),
3784
- undefined,
3785
- );
3786
- });
3787
-
3788
- it("Sends proper ZDO request payload for PERMIT_JOINING_REQUEST broadcast", async () => {
3789
- basicMocks();
3790
- await adapter.start();
3791
- mockZnpRequestZdo.mockClear();
3792
-
3793
- const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
3794
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, 250, 1, []);
3795
-
3796
- await adapter.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.DEFAULT, clusterId, zdoPayload, true);
3797
-
3798
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
3799
- clusterId,
3800
- Buffer.from([
3801
- AddressMode.ADDR_BROADCAST,
3802
- ZSpec.BroadcastAddress.DEFAULT & 0xff,
3803
- (ZSpec.BroadcastAddress.DEFAULT >> 8) & 0xff,
3804
- ...zdoPayload,
3805
- ]),
3806
- undefined,
3807
- );
3808
- });
3809
-
3810
- it("Sends proper ZDO request payload for NWK_UPDATE_REQUEST UNICAST", async () => {
3811
- basicMocks();
3812
- await adapter.start();
3813
- mockZnpRequestZdo.mockClear();
3814
-
3815
- const clusterId = Zdo.ClusterId.NWK_UPDATE_REQUEST;
3816
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, [15], 0xfe, 0, undefined, 0);
3817
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 0x123, clusterId, zdoPayload, true);
3818
-
3819
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
3820
- clusterId,
3821
- Buffer.from([
3822
- 0x123 & 0xff,
3823
- (0x123 >> 8) & 0xff,
3824
- AddressMode.ADDR_16BIT,
3825
- ...zdoPayload,
3826
- 0, // scancount
3827
- 0, // nwkmanageraddr
3828
- 0, // nwkmanageraddr
3829
- ]),
3830
- undefined,
3831
- );
3832
- });
3833
-
3834
- it("Sends proper ZDO request payload for NWK_UPDATE_REQUEST BROADCAST", async () => {
3835
- basicMocks();
3836
- await adapter.start();
3837
- mockZnpRequestZdo.mockClear();
3838
-
3839
- const clusterId = Zdo.ClusterId.NWK_UPDATE_REQUEST;
3840
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, [15], 0xfe, 0, undefined, 0);
3841
- await adapter.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.SLEEPY, clusterId, zdoPayload, true);
3842
-
3843
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
3844
- clusterId,
3845
- Buffer.from([
3846
- ZSpec.BroadcastAddress.SLEEPY & 0xff,
3847
- (ZSpec.BroadcastAddress.SLEEPY >> 8) & 0xff,
3848
- AddressMode.ADDR_BROADCAST,
3849
- ...zdoPayload,
3850
- 0, // scancount
3851
- 0, // nwkmanageraddr
3852
- 0, // nwkmanageraddr
3853
- ]),
3854
- undefined,
3855
- );
3856
- });
3857
-
3858
- it("Sends proper ZDO request payload for BIND_REQUEST/UNBIND_REQUEST UNICAST", async () => {
3859
- basicMocks();
3860
- await adapter.start();
3861
- mockZnpRequestZdo.mockClear();
3862
-
3863
- const clusterId = Zdo.ClusterId.BIND_REQUEST;
3864
- const zdoPayload = Zdo.Buffalo.buildRequest(
3865
- false,
3866
- clusterId,
3867
- "0x1122334455667788",
3868
- 3,
3869
- Zcl.Clusters.barrierControl.ID,
3870
- Zdo.UNICAST_BINDING,
3871
- "0x5544332211667788",
3872
- 0,
3873
- 5,
3874
- );
3875
-
3876
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true);
3877
-
3878
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(clusterId, Buffer.from([1234 & 0xff, (1234 >> 8) & 0xff, ...zdoPayload]), undefined);
3879
- });
3880
-
3881
- it("Sends proper ZDO request payload for BIND_REQUEST/UNBIND_REQUEST MULTICAST", async () => {
3882
- basicMocks();
3883
- await adapter.start();
3884
- mockZnpRequestZdo.mockClear();
3885
-
3886
- const clusterId = Zdo.ClusterId.BIND_REQUEST;
3887
- const zdoPayload = Zdo.Buffalo.buildRequest(
3888
- false,
3889
- clusterId,
3890
- "0x1122334455667788",
3891
- 3,
3892
- Zcl.Clusters.barrierControl.ID,
3893
- Zdo.MULTICAST_BINDING,
3894
- ZSpec.BLANK_EUI64,
3895
- 32,
3896
- 0,
3897
- );
3898
-
3899
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true);
3900
-
3901
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(
3902
- clusterId,
3903
- Buffer.from([
3904
- 1234 & 0xff,
3905
- (1234 >> 8) & 0xff,
3906
- ...zdoPayload,
3907
- 0, // match destination EUI64 length
3908
- 0, // match destination EUI64 length
3909
- 0, // match destination EUI64 length
3910
- 0, // match destination EUI64 length
3911
- 0, // match destination EUI64 length
3912
- 0, // match destination EUI64 length
3913
- 0, // endpoint
3914
- ]),
3915
- undefined,
3916
- );
3917
- });
3918
-
3919
- it("Sends proper ZDO request payload for NETWORK_ADDRESS_REQUEST", async () => {
3920
- basicMocks();
3921
- await adapter.start();
3922
- mockZnpRequestZdo.mockClear();
3923
-
3924
- const clusterId = Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
3925
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, "0x1122334455667788", false, 0);
3926
-
3927
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true);
3928
-
3929
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(clusterId, zdoPayload, undefined);
3930
- });
3931
-
3932
- it("Sends proper ZDO request payload for generic logic request", async () => {
3933
- basicMocks();
3934
- await adapter.start();
3935
- mockZnpRequestZdo.mockClear();
3936
-
3937
- const clusterId = Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST;
3938
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, 1234);
3939
-
3940
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true);
3941
-
3942
- expect(mockZnpRequestZdo).toHaveBeenCalledWith(clusterId, Buffer.from([1234 & 0xff, (1234 >> 8) & 0xff, ...zdoPayload]), undefined);
3943
- });
3944
-
3945
- it("Node descriptor request should discover route to fix potential fails", async () => {
3946
- // https://github.com/Koenkk/zigbee2mqtt/issues/3276
3947
- basicMocks();
3948
- await adapter.start();
3949
- mockZnpRequest.mockClear();
3950
- mockZnpRequestZdo.mockClear();
3951
- mockZnpRequestZdo.mockRejectedValueOnce(new Error("Failed"));
3952
-
3953
- const clusterId = Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST;
3954
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, 1234);
3955
-
3956
- await adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true);
3957
-
3958
- expect(mockZnpRequestZdo).toHaveBeenCalledTimes(2);
3959
- expect(mockZnpRequestZdo).toHaveBeenNthCalledWith(1, clusterId, Buffer.from([1234 & 0xff, (1234 >> 8) & 0xff, ...zdoPayload]), undefined);
3960
- expect(mockZnpRequestZdo).toHaveBeenNthCalledWith(2, clusterId, Buffer.from([1234 & 0xff, (1234 >> 8) & 0xff, ...zdoPayload]), undefined);
3961
- expect(mockZnpRequest).toHaveBeenCalledTimes(1);
3962
- expect(mockZnpRequest).toHaveBeenCalledWith(Subsystem.ZDO, "extRouteDisc", {dstAddr: 1234, options: 0, radius: 30});
3963
- });
3964
-
3965
- it("Should throw error when ZDO call fails", async () => {
3966
- basicMocks();
3967
- await adapter.start();
3968
- mockZnpRequest.mockClear();
3969
- mockZnpRequestZdo.mockClear();
3970
- mockZnpRequestZdo.mockRejectedValueOnce(new Error("Failed"));
3971
-
3972
- const clusterId = Zdo.ClusterId.SIMPLE_DESCRIPTOR_REQUEST;
3973
- const zdoPayload = Zdo.Buffalo.buildRequest(false, clusterId, 123, 0);
3974
-
3975
- await expect(adapter.sendZdo(ZSpec.BLANK_EUI64, 1234, clusterId, zdoPayload, true)).rejects.toThrow("Failed");
3976
- });
3977
-
3978
- it("Should throw error when registerEndpoints fails", async () => {
3979
- basicMocks();
3980
- vi.spyOn(adapter, "sendZdo").mockResolvedValueOnce([Zdo.Status.NOT_ACTIVE, undefined]);
3981
-
3982
- await expect(adapter.start()).rejects.toThrow(`Status 'NOT_ACTIVE'`);
3983
- });
3984
- });