zigbee-herdsman 6.0.2 → 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 (252) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +12 -3
  3. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  4. package/.github/dependabot.yml +0 -22
  5. package/.github/workflows/ci.yml +0 -69
  6. package/.github/workflows/release-please.yml +0 -18
  7. package/.github/workflows/stale.yml +0 -20
  8. package/.github/workflows/typedoc.yaml +0 -47
  9. package/.release-please-manifest.json +0 -3
  10. package/.vscode/extensions.json +0 -3
  11. package/.vscode/settings.json +0 -11
  12. package/biome.json +0 -98
  13. package/examples/join-and-log.js +0 -24
  14. package/release-please-config.json +0 -9
  15. package/src/adapter/adapter.ts +0 -189
  16. package/src/adapter/adapterDiscovery.ts +0 -666
  17. package/src/adapter/const.ts +0 -12
  18. package/src/adapter/deconz/adapter/deconzAdapter.ts +0 -877
  19. package/src/adapter/deconz/driver/constants.ts +0 -246
  20. package/src/adapter/deconz/driver/driver.ts +0 -1540
  21. package/src/adapter/deconz/driver/frame.ts +0 -11
  22. package/src/adapter/deconz/driver/frameParser.ts +0 -753
  23. package/src/adapter/deconz/driver/parser.ts +0 -45
  24. package/src/adapter/deconz/driver/writer.ts +0 -22
  25. package/src/adapter/deconz/types.d.ts +0 -13
  26. package/src/adapter/ember/adapter/emberAdapter.ts +0 -2265
  27. package/src/adapter/ember/adapter/endpoints.ts +0 -86
  28. package/src/adapter/ember/adapter/oneWaitress.ts +0 -324
  29. package/src/adapter/ember/adapter/tokensManager.ts +0 -782
  30. package/src/adapter/ember/consts.ts +0 -178
  31. package/src/adapter/ember/enums.ts +0 -1746
  32. package/src/adapter/ember/ezsp/buffalo.ts +0 -1392
  33. package/src/adapter/ember/ezsp/consts.ts +0 -148
  34. package/src/adapter/ember/ezsp/enums.ts +0 -1114
  35. package/src/adapter/ember/ezsp/ezsp.ts +0 -9061
  36. package/src/adapter/ember/ezspError.ts +0 -10
  37. package/src/adapter/ember/types.ts +0 -866
  38. package/src/adapter/ember/uart/ash.ts +0 -1960
  39. package/src/adapter/ember/uart/consts.ts +0 -109
  40. package/src/adapter/ember/uart/enums.ts +0 -192
  41. package/src/adapter/ember/uart/parser.ts +0 -48
  42. package/src/adapter/ember/uart/queues.ts +0 -247
  43. package/src/adapter/ember/uart/writer.ts +0 -53
  44. package/src/adapter/ember/utils/initters.ts +0 -58
  45. package/src/adapter/ember/utils/math.ts +0 -73
  46. package/src/adapter/events.ts +0 -21
  47. package/src/adapter/ezsp/adapter/backup.ts +0 -109
  48. package/src/adapter/ezsp/adapter/ezspAdapter.ts +0 -614
  49. package/src/adapter/ezsp/driver/commands.ts +0 -2497
  50. package/src/adapter/ezsp/driver/consts.ts +0 -11
  51. package/src/adapter/ezsp/driver/driver.ts +0 -1002
  52. package/src/adapter/ezsp/driver/ezsp.ts +0 -802
  53. package/src/adapter/ezsp/driver/frame.ts +0 -101
  54. package/src/adapter/ezsp/driver/index.ts +0 -4
  55. package/src/adapter/ezsp/driver/multicast.ts +0 -78
  56. package/src/adapter/ezsp/driver/parser.ts +0 -81
  57. package/src/adapter/ezsp/driver/types/basic.ts +0 -201
  58. package/src/adapter/ezsp/driver/types/index.ts +0 -239
  59. package/src/adapter/ezsp/driver/types/named.ts +0 -2330
  60. package/src/adapter/ezsp/driver/types/struct.ts +0 -844
  61. package/src/adapter/ezsp/driver/uart.ts +0 -460
  62. package/src/adapter/ezsp/driver/utils/crc16ccitt.ts +0 -44
  63. package/src/adapter/ezsp/driver/utils/index.ts +0 -32
  64. package/src/adapter/ezsp/driver/writer.ts +0 -64
  65. package/src/adapter/index.ts +0 -3
  66. package/src/adapter/serialPort.ts +0 -58
  67. package/src/adapter/socketPortUtils.ts +0 -16
  68. package/src/adapter/tstype.ts +0 -78
  69. package/src/adapter/z-stack/adapter/adapter-backup.ts +0 -519
  70. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +0 -457
  71. package/src/adapter/z-stack/adapter/endpoints.ts +0 -57
  72. package/src/adapter/z-stack/adapter/manager.ts +0 -543
  73. package/src/adapter/z-stack/adapter/tstype.ts +0 -6
  74. package/src/adapter/z-stack/adapter/zStackAdapter.ts +0 -1190
  75. package/src/adapter/z-stack/constants/af.ts +0 -27
  76. package/src/adapter/z-stack/constants/common.ts +0 -285
  77. package/src/adapter/z-stack/constants/dbg.ts +0 -23
  78. package/src/adapter/z-stack/constants/index.ts +0 -11
  79. package/src/adapter/z-stack/constants/mac.ts +0 -128
  80. package/src/adapter/z-stack/constants/sapi.ts +0 -25
  81. package/src/adapter/z-stack/constants/sys.ts +0 -72
  82. package/src/adapter/z-stack/constants/util.ts +0 -82
  83. package/src/adapter/z-stack/constants/utils.ts +0 -14
  84. package/src/adapter/z-stack/constants/zdo.ts +0 -103
  85. package/src/adapter/z-stack/models/startup-options.ts +0 -13
  86. package/src/adapter/z-stack/structs/entries/address-manager-entry.ts +0 -44
  87. package/src/adapter/z-stack/structs/entries/address-manager-table.ts +0 -19
  88. package/src/adapter/z-stack/structs/entries/aps-link-key-data-entry.ts +0 -12
  89. package/src/adapter/z-stack/structs/entries/aps-link-key-data-table.ts +0 -21
  90. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-entry.ts +0 -19
  91. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-table.ts +0 -21
  92. package/src/adapter/z-stack/structs/entries/channel-list.ts +0 -8
  93. package/src/adapter/z-stack/structs/entries/has-configured.ts +0 -16
  94. package/src/adapter/z-stack/structs/entries/index.ts +0 -16
  95. package/src/adapter/z-stack/structs/entries/nib.ts +0 -66
  96. package/src/adapter/z-stack/structs/entries/nwk-key-descriptor.ts +0 -15
  97. package/src/adapter/z-stack/structs/entries/nwk-key.ts +0 -13
  98. package/src/adapter/z-stack/structs/entries/nwk-pan-id.ts +0 -8
  99. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.ts +0 -20
  100. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.ts +0 -19
  101. package/src/adapter/z-stack/structs/entries/security-manager-entry.ts +0 -33
  102. package/src/adapter/z-stack/structs/entries/security-manager-table.ts +0 -22
  103. package/src/adapter/z-stack/structs/index.ts +0 -4
  104. package/src/adapter/z-stack/structs/serializable-memory-object.ts +0 -14
  105. package/src/adapter/z-stack/structs/struct.ts +0 -367
  106. package/src/adapter/z-stack/structs/table.ts +0 -198
  107. package/src/adapter/z-stack/unpi/constants.ts +0 -33
  108. package/src/adapter/z-stack/unpi/frame.ts +0 -62
  109. package/src/adapter/z-stack/unpi/index.ts +0 -4
  110. package/src/adapter/z-stack/unpi/parser.ts +0 -56
  111. package/src/adapter/z-stack/unpi/writer.ts +0 -21
  112. package/src/adapter/z-stack/utils/channel-list.ts +0 -40
  113. package/src/adapter/z-stack/utils/index.ts +0 -2
  114. package/src/adapter/z-stack/utils/network-options.ts +0 -26
  115. package/src/adapter/z-stack/znp/buffaloZnp.ts +0 -175
  116. package/src/adapter/z-stack/znp/definition.ts +0 -2713
  117. package/src/adapter/z-stack/znp/index.ts +0 -2
  118. package/src/adapter/z-stack/znp/parameterType.ts +0 -22
  119. package/src/adapter/z-stack/znp/tstype.ts +0 -44
  120. package/src/adapter/z-stack/znp/utils.ts +0 -10
  121. package/src/adapter/z-stack/znp/znp.ts +0 -342
  122. package/src/adapter/z-stack/znp/zpiObject.ts +0 -148
  123. package/src/adapter/zboss/adapter/zbossAdapter.ts +0 -526
  124. package/src/adapter/zboss/commands.ts +0 -1184
  125. package/src/adapter/zboss/consts.ts +0 -9
  126. package/src/adapter/zboss/driver.ts +0 -422
  127. package/src/adapter/zboss/enums.ts +0 -360
  128. package/src/adapter/zboss/frame.ts +0 -227
  129. package/src/adapter/zboss/reader.ts +0 -65
  130. package/src/adapter/zboss/types.ts +0 -0
  131. package/src/adapter/zboss/uart.ts +0 -428
  132. package/src/adapter/zboss/utils.ts +0 -58
  133. package/src/adapter/zboss/writer.ts +0 -49
  134. package/src/adapter/zigate/adapter/patchZdoBuffaloBE.ts +0 -27
  135. package/src/adapter/zigate/adapter/zigateAdapter.ts +0 -618
  136. package/src/adapter/zigate/driver/LICENSE +0 -17
  137. package/src/adapter/zigate/driver/buffaloZiGate.ts +0 -212
  138. package/src/adapter/zigate/driver/commandType.ts +0 -418
  139. package/src/adapter/zigate/driver/constants.ts +0 -150
  140. package/src/adapter/zigate/driver/frame.ts +0 -197
  141. package/src/adapter/zigate/driver/messageType.ts +0 -287
  142. package/src/adapter/zigate/driver/parameterType.ts +0 -32
  143. package/src/adapter/zigate/driver/ziGateObject.ts +0 -146
  144. package/src/adapter/zigate/driver/zigate.ts +0 -423
  145. package/src/adapter/zoh/adapter/utils.ts +0 -27
  146. package/src/adapter/zoh/adapter/zohAdapter.ts +0 -838
  147. package/src/buffalo/buffalo.ts +0 -342
  148. package/src/buffalo/index.ts +0 -1
  149. package/src/controller/controller.ts +0 -1022
  150. package/src/controller/database.ts +0 -124
  151. package/src/controller/events.ts +0 -52
  152. package/src/controller/greenPower.ts +0 -603
  153. package/src/controller/helpers/index.ts +0 -1
  154. package/src/controller/helpers/installCodes.ts +0 -107
  155. package/src/controller/helpers/request.ts +0 -96
  156. package/src/controller/helpers/requestQueue.ts +0 -125
  157. package/src/controller/helpers/zclFrameConverter.ts +0 -47
  158. package/src/controller/helpers/zclTransactionSequenceNumber.ts +0 -19
  159. package/src/controller/index.ts +0 -6
  160. package/src/controller/model/device.ts +0 -1249
  161. package/src/controller/model/endpoint.ts +0 -1105
  162. package/src/controller/model/entity.ts +0 -23
  163. package/src/controller/model/group.ts +0 -424
  164. package/src/controller/model/index.ts +0 -5
  165. package/src/controller/model/zigbeeEntity.ts +0 -30
  166. package/src/controller/touchlink.ts +0 -189
  167. package/src/controller/tstype.ts +0 -274
  168. package/src/index.ts +0 -12
  169. package/src/models/backup-storage-legacy.ts +0 -48
  170. package/src/models/backup-storage-unified.ts +0 -47
  171. package/src/models/backup.ts +0 -37
  172. package/src/models/index.ts +0 -5
  173. package/src/models/network-options.ts +0 -11
  174. package/src/utils/backup.ts +0 -152
  175. package/src/utils/index.ts +0 -5
  176. package/src/utils/logger.ts +0 -20
  177. package/src/utils/patchBigIntSerialization.ts +0 -8
  178. package/src/utils/queue.ts +0 -76
  179. package/src/utils/types.d.ts +0 -3
  180. package/src/utils/utils.ts +0 -19
  181. package/src/utils/wait.ts +0 -5
  182. package/src/utils/waitress.ts +0 -96
  183. package/src/zspec/consts.ts +0 -84
  184. package/src/zspec/enums.ts +0 -22
  185. package/src/zspec/index.ts +0 -3
  186. package/src/zspec/tstypes.ts +0 -18
  187. package/src/zspec/utils.ts +0 -247
  188. package/src/zspec/zcl/buffaloZcl.ts +0 -1220
  189. package/src/zspec/zcl/definition/cluster.ts +0 -5915
  190. package/src/zspec/zcl/definition/clusters-typegen.ts +0 -588
  191. package/src/zspec/zcl/definition/clusters-types.ts +0 -7331
  192. package/src/zspec/zcl/definition/consts.ts +0 -24
  193. package/src/zspec/zcl/definition/enums.ts +0 -203
  194. package/src/zspec/zcl/definition/foundation.ts +0 -329
  195. package/src/zspec/zcl/definition/manufacturerCode.ts +0 -729
  196. package/src/zspec/zcl/definition/status.ts +0 -69
  197. package/src/zspec/zcl/definition/tstype.ts +0 -377
  198. package/src/zspec/zcl/index.ts +0 -11
  199. package/src/zspec/zcl/utils.ts +0 -321
  200. package/src/zspec/zcl/zclFrame.ts +0 -356
  201. package/src/zspec/zcl/zclHeader.ts +0 -102
  202. package/src/zspec/zcl/zclStatusError.ts +0 -10
  203. package/src/zspec/zdo/buffaloZdo.ts +0 -2336
  204. package/src/zspec/zdo/definition/clusters.ts +0 -722
  205. package/src/zspec/zdo/definition/consts.ts +0 -16
  206. package/src/zspec/zdo/definition/enums.ts +0 -99
  207. package/src/zspec/zdo/definition/status.ts +0 -105
  208. package/src/zspec/zdo/definition/tstypes.ts +0 -1062
  209. package/src/zspec/zdo/index.ts +0 -7
  210. package/src/zspec/zdo/utils.ts +0 -76
  211. package/src/zspec/zdo/zdoStatusError.ts +0 -10
  212. package/test/adapter/adapter.test.ts +0 -1062
  213. package/test/adapter/ember/ash.test.ts +0 -337
  214. package/test/adapter/ember/consts.ts +0 -131
  215. package/test/adapter/ember/emberAdapter.test.ts +0 -3449
  216. package/test/adapter/ember/ezsp.test.ts +0 -385
  217. package/test/adapter/ember/ezspBuffalo.test.ts +0 -93
  218. package/test/adapter/ember/ezspError.test.ts +0 -12
  219. package/test/adapter/ember/math.test.ts +0 -206
  220. package/test/adapter/ezsp/frame.test.ts +0 -30
  221. package/test/adapter/ezsp/uart.test.ts +0 -181
  222. package/test/adapter/z-stack/adapter.test.ts +0 -3984
  223. package/test/adapter/z-stack/constants.test.ts +0 -33
  224. package/test/adapter/z-stack/structs.test.ts +0 -115
  225. package/test/adapter/z-stack/unpi.test.ts +0 -213
  226. package/test/adapter/z-stack/znp.test.ts +0 -1284
  227. package/test/adapter/zboss/fixZdoResponse.test.ts +0 -179
  228. package/test/adapter/zigate/patchZdoBuffaloBE.test.ts +0 -81
  229. package/test/adapter/zigate/zdo.test.ts +0 -187
  230. package/test/adapter/zoh/utils.test.ts +0 -36
  231. package/test/adapter/zoh/zohAdapter.test.ts +0 -1307
  232. package/test/benchOptions.ts +0 -14
  233. package/test/buffalo.test.ts +0 -431
  234. package/test/controller.bench.ts +0 -214
  235. package/test/controller.test.ts +0 -8702
  236. package/test/greenpower.test.ts +0 -1408
  237. package/test/mockAdapters.ts +0 -65
  238. package/test/mockDevices.ts +0 -598
  239. package/test/requests.bench.ts +0 -229
  240. package/test/testUtils.ts +0 -20
  241. package/test/tsconfig.json +0 -9
  242. package/test/utils/math.ts +0 -19
  243. package/test/utils.test.ts +0 -279
  244. package/test/vitest.config.mts +0 -26
  245. package/test/zcl.test.ts +0 -2831
  246. package/test/zspec/utils.test.ts +0 -68
  247. package/test/zspec/zcl/buffalo.test.ts +0 -1374
  248. package/test/zspec/zcl/frame.test.ts +0 -960
  249. package/test/zspec/zcl/utils.test.ts +0 -273
  250. package/test/zspec/zdo/buffalo.test.ts +0 -1850
  251. package/test/zspec/zdo/utils.test.ts +0 -241
  252. 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
- });