@willieee802/zigbee-herdsman 0.48.2 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1025) hide show
  1. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  2. package/.github/copilot-instructions.md +689 -0
  3. package/.github/dependabot.yml +22 -0
  4. package/.github/prompts/copilot-instructions-blueprint-generator.prompt.md +294 -0
  5. package/.github/prompts/create-agentsmd.prompt.md +249 -0
  6. package/.github/prompts/create-specification.prompt.md +127 -0
  7. package/.github/prompts/review-and-refactor.prompt.md +15 -0
  8. package/.github/prompts/update-specification.prompt.md +127 -0
  9. package/.github/workflows/ci.yml +70 -0
  10. package/.github/workflows/release-please.yml +18 -0
  11. package/.github/workflows/stale.yml +20 -0
  12. package/.github/workflows/typedoc.yaml +47 -0
  13. package/.release-please-manifest.json +2 -2
  14. package/.vscode/extensions.json +3 -0
  15. package/.vscode/settings.json +11 -0
  16. package/AGENTS.md +441 -0
  17. package/CHANGELOG.md +1245 -0
  18. package/README.md +2 -2
  19. package/biome.json +103 -0
  20. package/examples/join-and-log.js +18 -18
  21. package/package.json +83 -70
  22. package/release-please-config.json +8 -8
  23. package/scripts/check-clusters-changes.ts +328 -0
  24. package/scripts/clusters-changes.log +584 -0
  25. package/scripts/clusters-typegen.ts +608 -0
  26. package/scripts/utils.ts +88 -0
  27. package/scripts/zap-update-clusters-report.json +303 -0
  28. package/scripts/zap-update-clusters.ts +1520 -0
  29. package/scripts/zap-update-types.ts +707 -0
  30. package/scripts/zap-xml-clusters-overrides-data.ts +52 -0
  31. package/scripts/zap-xml-clusters-overrides.ts +400 -0
  32. package/scripts/zap-xml-types.ts +146 -0
  33. package/src/adapter/adapter.ts +210 -0
  34. package/src/adapter/adapterDiscovery.ts +736 -0
  35. package/src/adapter/const.ts +12 -0
  36. package/src/adapter/deconz/adapter/deconzAdapter.ts +888 -0
  37. package/src/adapter/deconz/driver/constants.ts +246 -0
  38. package/src/adapter/deconz/driver/driver.ts +1528 -0
  39. package/src/adapter/deconz/driver/frame.ts +11 -0
  40. package/src/adapter/deconz/driver/frameParser.ts +766 -0
  41. package/src/adapter/deconz/driver/parser.ts +45 -0
  42. package/src/adapter/deconz/driver/writer.ts +22 -0
  43. package/src/adapter/deconz/types.d.ts +13 -0
  44. package/src/adapter/ember/adapter/emberAdapter.ts +2262 -0
  45. package/src/adapter/ember/adapter/endpoints.ts +86 -0
  46. package/src/adapter/ember/adapter/oneWaitress.ts +324 -0
  47. package/src/adapter/ember/adapter/tokensManager.ts +780 -0
  48. package/src/adapter/ember/consts.ts +178 -0
  49. package/src/adapter/ember/enums.ts +1746 -0
  50. package/src/adapter/ember/ezsp/buffalo.ts +1392 -0
  51. package/src/adapter/ember/ezsp/consts.ts +148 -0
  52. package/src/adapter/ember/ezsp/enums.ts +1114 -0
  53. package/src/adapter/ember/ezsp/ezsp.ts +9073 -0
  54. package/src/adapter/ember/ezspError.ts +10 -0
  55. package/src/adapter/ember/types.ts +866 -0
  56. package/src/adapter/ember/uart/ash.ts +1933 -0
  57. package/src/adapter/ember/uart/consts.ts +109 -0
  58. package/src/adapter/ember/uart/enums.ts +192 -0
  59. package/src/adapter/ember/uart/parser.ts +42 -0
  60. package/src/adapter/ember/uart/queues.ts +247 -0
  61. package/src/adapter/ember/uart/writer.ts +50 -0
  62. package/src/adapter/ember/utils/initters.ts +58 -0
  63. package/src/adapter/ember/utils/math.ts +71 -0
  64. package/src/adapter/events.ts +21 -0
  65. package/src/adapter/ezsp/adapter/backup.ts +100 -0
  66. package/src/adapter/ezsp/adapter/ezspAdapter.ts +632 -0
  67. package/src/adapter/ezsp/driver/commands.ts +2497 -0
  68. package/src/adapter/ezsp/driver/consts.ts +11 -0
  69. package/src/adapter/ezsp/driver/driver.ts +1002 -0
  70. package/src/adapter/ezsp/driver/ezsp.ts +802 -0
  71. package/src/adapter/ezsp/driver/frame.ts +101 -0
  72. package/src/adapter/ezsp/driver/index.ts +4 -0
  73. package/src/adapter/ezsp/driver/multicast.ts +78 -0
  74. package/src/adapter/ezsp/driver/parser.ts +81 -0
  75. package/src/adapter/ezsp/driver/types/basic.ts +201 -0
  76. package/src/adapter/ezsp/driver/types/index.ts +239 -0
  77. package/src/adapter/ezsp/driver/types/named.ts +2330 -0
  78. package/src/adapter/ezsp/driver/types/struct.ts +844 -0
  79. package/src/adapter/ezsp/driver/uart.ts +460 -0
  80. package/src/adapter/ezsp/driver/utils/crc16ccitt.ts +44 -0
  81. package/src/adapter/ezsp/driver/utils/index.ts +32 -0
  82. package/src/adapter/ezsp/driver/writer.ts +64 -0
  83. package/src/adapter/index.ts +3 -0
  84. package/src/adapter/serialPort.ts +58 -0
  85. package/src/adapter/tstype.ts +57 -0
  86. package/src/adapter/utils.ts +41 -0
  87. package/src/adapter/z-stack/adapter/adapter-backup.ts +509 -0
  88. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +457 -0
  89. package/src/adapter/z-stack/adapter/endpoints.ts +60 -0
  90. package/src/adapter/z-stack/adapter/manager.ts +543 -0
  91. package/src/adapter/z-stack/adapter/tstype.ts +6 -0
  92. package/src/adapter/z-stack/adapter/zStackAdapter.ts +1350 -0
  93. package/src/adapter/z-stack/constants/af.ts +27 -0
  94. package/src/adapter/z-stack/constants/common.ts +285 -0
  95. package/src/adapter/z-stack/constants/dbg.ts +23 -0
  96. package/src/adapter/z-stack/constants/index.ts +11 -0
  97. package/src/adapter/z-stack/constants/mac.ts +128 -0
  98. package/src/adapter/z-stack/constants/sapi.ts +25 -0
  99. package/src/adapter/z-stack/constants/sys.ts +72 -0
  100. package/src/adapter/z-stack/constants/util.ts +82 -0
  101. package/src/adapter/z-stack/constants/utils.ts +14 -0
  102. package/src/adapter/z-stack/constants/zdo.ts +103 -0
  103. package/src/adapter/z-stack/models/startup-options.ts +13 -0
  104. package/src/adapter/z-stack/structs/entries/address-manager-entry.ts +44 -0
  105. package/src/adapter/z-stack/structs/entries/address-manager-table.ts +19 -0
  106. package/src/adapter/z-stack/structs/entries/aps-link-key-data-entry.ts +12 -0
  107. package/src/adapter/z-stack/structs/entries/aps-link-key-data-table.ts +21 -0
  108. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-entry.ts +19 -0
  109. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-table.ts +21 -0
  110. package/src/adapter/z-stack/structs/entries/channel-list.ts +8 -0
  111. package/src/adapter/z-stack/structs/entries/has-configured.ts +16 -0
  112. package/src/adapter/z-stack/structs/entries/index.ts +16 -0
  113. package/src/adapter/z-stack/structs/entries/nib.ts +66 -0
  114. package/src/adapter/z-stack/structs/entries/nwk-key-descriptor.ts +15 -0
  115. package/src/adapter/z-stack/structs/entries/nwk-key.ts +13 -0
  116. package/src/adapter/z-stack/structs/entries/nwk-pan-id.ts +8 -0
  117. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.ts +20 -0
  118. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.ts +19 -0
  119. package/src/adapter/z-stack/structs/entries/security-manager-entry.ts +33 -0
  120. package/src/adapter/z-stack/structs/entries/security-manager-table.ts +22 -0
  121. package/src/adapter/z-stack/structs/index.ts +4 -0
  122. package/src/adapter/z-stack/structs/serializable-memory-object.ts +14 -0
  123. package/src/adapter/z-stack/structs/struct.ts +367 -0
  124. package/src/adapter/z-stack/structs/table.ts +198 -0
  125. package/src/adapter/z-stack/unpi/constants.ts +33 -0
  126. package/src/adapter/z-stack/unpi/frame.ts +62 -0
  127. package/src/adapter/z-stack/unpi/index.ts +4 -0
  128. package/src/adapter/z-stack/unpi/parser.ts +67 -0
  129. package/src/adapter/z-stack/unpi/writer.ts +37 -0
  130. package/src/adapter/z-stack/utils/channel-list.ts +40 -0
  131. package/src/adapter/z-stack/utils/index.ts +2 -0
  132. package/src/adapter/z-stack/utils/network-options.ts +26 -0
  133. package/src/adapter/z-stack/znp/buffaloZnp.ts +175 -0
  134. package/src/adapter/z-stack/znp/definition.ts +2713 -0
  135. package/src/adapter/z-stack/znp/index.ts +2 -0
  136. package/src/adapter/z-stack/znp/parameterType.ts +22 -0
  137. package/src/adapter/z-stack/znp/tstype.ts +44 -0
  138. package/src/adapter/z-stack/znp/utils.ts +10 -0
  139. package/src/adapter/z-stack/znp/znp.ts +345 -0
  140. package/src/adapter/z-stack/znp/zpiObject.ts +148 -0
  141. package/src/adapter/zboss/adapter/zbossAdapter.ts +535 -0
  142. package/src/adapter/zboss/commands.ts +1184 -0
  143. package/src/adapter/zboss/consts.ts +9 -0
  144. package/src/adapter/zboss/driver.ts +422 -0
  145. package/src/adapter/zboss/enums.ts +360 -0
  146. package/src/adapter/zboss/frame.ts +227 -0
  147. package/src/adapter/zboss/reader.ts +65 -0
  148. package/src/adapter/zboss/types.ts +0 -0
  149. package/src/adapter/zboss/uart.ts +428 -0
  150. package/src/adapter/zboss/utils.ts +58 -0
  151. package/src/adapter/zboss/writer.ts +49 -0
  152. package/src/adapter/zigate/adapter/patchZdoBuffaloBE.ts +25 -0
  153. package/src/adapter/zigate/adapter/zigateAdapter.ts +633 -0
  154. package/src/adapter/zigate/driver/LICENSE +17 -0
  155. package/src/adapter/zigate/driver/buffaloZiGate.ts +210 -0
  156. package/src/adapter/zigate/driver/commandType.ts +418 -0
  157. package/src/adapter/zigate/driver/constants.ts +150 -0
  158. package/src/adapter/zigate/driver/frame.ts +197 -0
  159. package/src/adapter/zigate/driver/messageType.ts +287 -0
  160. package/src/adapter/zigate/driver/parameterType.ts +32 -0
  161. package/src/adapter/zigate/driver/ziGateObject.ts +146 -0
  162. package/src/adapter/zigate/driver/zigate.ts +422 -0
  163. package/src/adapter/zoh/adapter/utils.ts +27 -0
  164. package/src/adapter/zoh/adapter/zohAdapter.ts +931 -0
  165. package/src/buffalo/buffalo.ts +336 -0
  166. package/src/buffalo/index.ts +1 -0
  167. package/src/controller/controller.ts +1159 -0
  168. package/src/controller/database.ts +148 -0
  169. package/src/controller/events.ts +52 -0
  170. package/src/controller/greenPower.ts +613 -0
  171. package/src/controller/helpers/index.ts +1 -0
  172. package/src/controller/helpers/installCodes.ts +107 -0
  173. package/src/controller/helpers/ota.ts +575 -0
  174. package/src/controller/helpers/request.ts +96 -0
  175. package/src/controller/helpers/requestQueue.ts +126 -0
  176. package/src/controller/helpers/zclFrameConverter.ts +64 -0
  177. package/src/controller/helpers/zclTransactionSequenceNumber.ts +15 -0
  178. package/src/controller/index.ts +6 -0
  179. package/src/controller/model/device.ts +1791 -0
  180. package/src/controller/model/endpoint.ts +1235 -0
  181. package/src/controller/model/entity.ts +43 -0
  182. package/src/controller/model/group.ts +446 -0
  183. package/src/controller/model/index.ts +5 -0
  184. package/src/controller/model/konnextConfig.ts +6 -0
  185. package/src/controller/model/zigbeeEntity.ts +30 -0
  186. package/src/controller/touchlink.ts +195 -0
  187. package/src/controller/tstype.ts +374 -0
  188. package/src/index.ts +14 -0
  189. package/src/models/backup-storage-legacy.ts +48 -0
  190. package/src/models/backup-storage-unified.ts +47 -0
  191. package/src/models/backup.ts +37 -0
  192. package/src/models/index.ts +5 -0
  193. package/src/models/network-options.ts +11 -0
  194. package/src/utils/aes.ts +218 -0
  195. package/src/utils/async-mutex.ts +31 -0
  196. package/src/utils/backup.ts +152 -0
  197. package/src/utils/index.ts +5 -0
  198. package/src/utils/logger.ts +20 -0
  199. package/src/utils/patchBigIntSerialization.ts +8 -0
  200. package/src/utils/queue.ts +79 -0
  201. package/src/utils/timeService.ts +139 -0
  202. package/src/utils/utils.ts +19 -0
  203. package/src/utils/wait.ts +5 -0
  204. package/src/utils/waitress.ts +96 -0
  205. package/src/zspec/consts.ts +89 -0
  206. package/src/zspec/enums.ts +22 -0
  207. package/src/zspec/index.ts +3 -0
  208. package/src/zspec/tstypes.ts +18 -0
  209. package/src/zspec/utils.ts +247 -0
  210. package/src/zspec/zcl/buffaloZcl.ts +1073 -0
  211. package/src/zspec/zcl/definition/cluster.ts +7845 -0
  212. package/src/zspec/zcl/definition/clusters-types.ts +8577 -0
  213. package/src/zspec/zcl/definition/consts.ts +24 -0
  214. package/src/zspec/zcl/definition/datatypes.ts +2454 -0
  215. package/src/zspec/zcl/definition/enums.ts +224 -0
  216. package/src/zspec/zcl/definition/foundation.ts +342 -0
  217. package/src/zspec/zcl/definition/manufacturerCode.ts +730 -0
  218. package/src/zspec/zcl/definition/status.ts +69 -0
  219. package/src/zspec/zcl/definition/tstype.ts +446 -0
  220. package/src/zspec/zcl/index.ts +11 -0
  221. package/src/zspec/zcl/utils.ts +521 -0
  222. package/src/zspec/zcl/zclFrame.ts +383 -0
  223. package/src/zspec/zcl/zclHeader.ts +102 -0
  224. package/src/zspec/zcl/zclStatusError.ts +10 -0
  225. package/src/zspec/zdo/buffaloZdo.ts +2336 -0
  226. package/src/zspec/zdo/definition/clusters.ts +722 -0
  227. package/src/zspec/zdo/definition/consts.ts +16 -0
  228. package/src/zspec/zdo/definition/enums.ts +99 -0
  229. package/src/zspec/zdo/definition/status.ts +105 -0
  230. package/src/zspec/zdo/definition/tstypes.ts +1062 -0
  231. package/src/zspec/zdo/index.ts +7 -0
  232. package/src/zspec/zdo/utils.ts +76 -0
  233. package/src/zspec/zdo/zdoStatusError.ts +10 -0
  234. package/test/adapter/adapter.test.ts +1276 -0
  235. package/test/adapter/ember/ash.test.ts +337 -0
  236. package/test/adapter/ember/consts.ts +131 -0
  237. package/test/adapter/ember/emberAdapter.test.ts +3447 -0
  238. package/test/adapter/ember/ezsp.test.ts +389 -0
  239. package/test/adapter/ember/ezspBuffalo.test.ts +93 -0
  240. package/test/adapter/ember/ezspError.test.ts +12 -0
  241. package/test/adapter/ember/math.test.ts +190 -0
  242. package/test/adapter/ezsp/frame.test.ts +30 -0
  243. package/test/adapter/ezsp/uart.test.ts +181 -0
  244. package/test/adapter/z-stack/adapter.test.ts +4260 -0
  245. package/test/adapter/z-stack/constants.test.ts +33 -0
  246. package/test/adapter/z-stack/structs.test.ts +115 -0
  247. package/test/adapter/z-stack/unpi.test.ts +213 -0
  248. package/test/adapter/z-stack/znp.test.ts +1288 -0
  249. package/test/adapter/zboss/fixZdoResponse.test.ts +179 -0
  250. package/test/adapter/zigate/patchZdoBuffaloBE.test.ts +81 -0
  251. package/test/adapter/zigate/zdo.test.ts +187 -0
  252. package/test/adapter/zoh/utils.test.ts +36 -0
  253. package/test/adapter/zoh/zohAdapter.test.ts +1451 -0
  254. package/test/benchOptions.ts +14 -0
  255. package/test/buffalo.test.ts +431 -0
  256. package/test/controller.bench.ts +215 -0
  257. package/test/controller.test.ts +10030 -0
  258. package/test/data/integrity-code-1166-012B-24031511-upgradeMe-RB 249 T.zigbee +0 -0
  259. package/test/data/manuf-tags-tradfri-cv-cct-unified_release_prod_v587757105_33e34452-9267-4665-bc5a-844c8f61f063.ota +0 -0
  260. package/test/data/padded-tretakt_smart_plug_soc-0x1100-2.4.25-prod.ota.ota.signed +0 -0
  261. package/test/data/telink-aes-A60_RGBW_T-0x00B6-0x03483712-MF_DIS.OTA +0 -0
  262. package/test/data/zbminir2_v1.0.8.ota +0 -0
  263. package/test/device-ota.test.ts +3332 -0
  264. package/test/greenpower.test.ts +1409 -0
  265. package/test/mockAdapters.ts +95 -0
  266. package/test/mockDevices.ts +623 -0
  267. package/test/requests.bench.ts +321 -0
  268. package/test/testUtils.ts +20 -0
  269. package/test/timeService.test.ts +214 -0
  270. package/test/tsconfig.json +9 -0
  271. package/test/utils/math.ts +19 -0
  272. package/test/utils.test.ts +352 -0
  273. package/test/vitest.config.mts +28 -0
  274. package/test/vitest.ts +9 -0
  275. package/test/zcl.test.ts +2858 -0
  276. package/test/zspec/utils.test.ts +68 -0
  277. package/test/zspec/zcl/buffalo.test.ts +1316 -0
  278. package/test/zspec/zcl/frame.test.ts +1056 -0
  279. package/test/zspec/zcl/utils.test.ts +650 -0
  280. package/test/zspec/zdo/buffalo.test.ts +1850 -0
  281. package/test/zspec/zdo/utils.test.ts +241 -0
  282. package/tsconfig.json +8 -10
  283. package/.babelrc.js +0 -6
  284. package/.eslintignore +0 -3
  285. package/dist/adapter/adapter.d.ts +0 -64
  286. package/dist/adapter/adapter.d.ts.map +0 -1
  287. package/dist/adapter/adapter.js +0 -157
  288. package/dist/adapter/adapter.js.map +0 -1
  289. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +0 -71
  290. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +0 -1
  291. package/dist/adapter/deconz/adapter/deconzAdapter.js +0 -1072
  292. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +0 -1
  293. package/dist/adapter/deconz/adapter/index.d.ts +0 -3
  294. package/dist/adapter/deconz/adapter/index.d.ts.map +0 -1
  295. package/dist/adapter/deconz/adapter/index.js +0 -11
  296. package/dist/adapter/deconz/adapter/index.js.map +0 -1
  297. package/dist/adapter/deconz/driver/constants.d.ts +0 -105
  298. package/dist/adapter/deconz/driver/constants.d.ts.map +0 -1
  299. package/dist/adapter/deconz/driver/constants.js +0 -56
  300. package/dist/adapter/deconz/driver/constants.js.map +0 -1
  301. package/dist/adapter/deconz/driver/driver.d.ts +0 -82
  302. package/dist/adapter/deconz/driver/driver.d.ts.map +0 -1
  303. package/dist/adapter/deconz/driver/driver.js +0 -751
  304. package/dist/adapter/deconz/driver/driver.js.map +0 -1
  305. package/dist/adapter/deconz/driver/frame.d.ts +0 -7
  306. package/dist/adapter/deconz/driver/frame.d.ts.map +0 -1
  307. package/dist/adapter/deconz/driver/frame.js +0 -14
  308. package/dist/adapter/deconz/driver/frame.js.map +0 -1
  309. package/dist/adapter/deconz/driver/frameParser.d.ts +0 -3
  310. package/dist/adapter/deconz/driver/frameParser.d.ts.map +0 -1
  311. package/dist/adapter/deconz/driver/frameParser.js +0 -444
  312. package/dist/adapter/deconz/driver/frameParser.js.map +0 -1
  313. package/dist/adapter/deconz/driver/parser.d.ts +0 -13
  314. package/dist/adapter/deconz/driver/parser.d.ts.map +0 -1
  315. package/dist/adapter/deconz/driver/parser.js +0 -64
  316. package/dist/adapter/deconz/driver/parser.js.map +0 -1
  317. package/dist/adapter/deconz/driver/writer.d.ts +0 -9
  318. package/dist/adapter/deconz/driver/writer.d.ts.map +0 -1
  319. package/dist/adapter/deconz/driver/writer.js +0 -45
  320. package/dist/adapter/deconz/driver/writer.js.map +0 -1
  321. package/dist/adapter/ember/adapter/emberAdapter.d.ts +0 -806
  322. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +0 -1
  323. package/dist/adapter/ember/adapter/emberAdapter.js +0 -2942
  324. package/dist/adapter/ember/adapter/emberAdapter.js.map +0 -1
  325. package/dist/adapter/ember/adapter/endpoints.d.ts +0 -27
  326. package/dist/adapter/ember/adapter/endpoints.d.ts.map +0 -1
  327. package/dist/adapter/ember/adapter/endpoints.js +0 -68
  328. package/dist/adapter/ember/adapter/endpoints.js.map +0 -1
  329. package/dist/adapter/ember/adapter/index.d.ts +0 -3
  330. package/dist/adapter/ember/adapter/index.d.ts.map +0 -1
  331. package/dist/adapter/ember/adapter/index.js +0 -6
  332. package/dist/adapter/ember/adapter/index.js.map +0 -1
  333. package/dist/adapter/ember/adapter/oneWaitress.d.ts +0 -108
  334. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +0 -1
  335. package/dist/adapter/ember/adapter/oneWaitress.js +0 -241
  336. package/dist/adapter/ember/adapter/oneWaitress.js.map +0 -1
  337. package/dist/adapter/ember/adapter/requestQueue.d.ts +0 -57
  338. package/dist/adapter/ember/adapter/requestQueue.d.ts.map +0 -1
  339. package/dist/adapter/ember/adapter/requestQueue.js +0 -139
  340. package/dist/adapter/ember/adapter/requestQueue.js.map +0 -1
  341. package/dist/adapter/ember/adapter/tokensManager.d.ts +0 -69
  342. package/dist/adapter/ember/adapter/tokensManager.d.ts.map +0 -1
  343. package/dist/adapter/ember/adapter/tokensManager.js +0 -688
  344. package/dist/adapter/ember/adapter/tokensManager.js.map +0 -1
  345. package/dist/adapter/ember/consts.d.ts +0 -191
  346. package/dist/adapter/ember/consts.d.ts.map +0 -1
  347. package/dist/adapter/ember/consts.js +0 -246
  348. package/dist/adapter/ember/consts.js.map +0 -1
  349. package/dist/adapter/ember/enums.d.ts +0 -2172
  350. package/dist/adapter/ember/enums.d.ts.map +0 -1
  351. package/dist/adapter/ember/enums.js +0 -2375
  352. package/dist/adapter/ember/enums.js.map +0 -1
  353. package/dist/adapter/ember/ezsp/buffalo.d.ts +0 -156
  354. package/dist/adapter/ember/ezsp/buffalo.d.ts.map +0 -1
  355. package/dist/adapter/ember/ezsp/buffalo.js +0 -1033
  356. package/dist/adapter/ember/ezsp/buffalo.js.map +0 -1
  357. package/dist/adapter/ember/ezsp/consts.d.ts +0 -116
  358. package/dist/adapter/ember/ezsp/consts.d.ts.map +0 -1
  359. package/dist/adapter/ember/ezsp/consts.js +0 -128
  360. package/dist/adapter/ember/ezsp/consts.js.map +0 -1
  361. package/dist/adapter/ember/ezsp/enums.d.ts +0 -879
  362. package/dist/adapter/ember/ezsp/enums.d.ts.map +0 -1
  363. package/dist/adapter/ember/ezsp/enums.js +0 -948
  364. package/dist/adapter/ember/ezsp/enums.js.map +0 -1
  365. package/dist/adapter/ember/ezsp/ezsp.d.ts +0 -2662
  366. package/dist/adapter/ember/ezsp/ezsp.d.ts.map +0 -1
  367. package/dist/adapter/ember/ezsp/ezsp.js +0 -6454
  368. package/dist/adapter/ember/ezsp/ezsp.js.map +0 -1
  369. package/dist/adapter/ember/types.d.ts +0 -733
  370. package/dist/adapter/ember/types.d.ts.map +0 -1
  371. package/dist/adapter/ember/types.js +0 -3
  372. package/dist/adapter/ember/types.js.map +0 -1
  373. package/dist/adapter/ember/uart/ash.d.ts +0 -464
  374. package/dist/adapter/ember/uart/ash.d.ts.map +0 -1
  375. package/dist/adapter/ember/uart/ash.js +0 -1633
  376. package/dist/adapter/ember/uart/ash.js.map +0 -1
  377. package/dist/adapter/ember/uart/consts.d.ts +0 -91
  378. package/dist/adapter/ember/uart/consts.d.ts.map +0 -1
  379. package/dist/adapter/ember/uart/consts.js +0 -100
  380. package/dist/adapter/ember/uart/consts.js.map +0 -1
  381. package/dist/adapter/ember/uart/enums.d.ts +0 -191
  382. package/dist/adapter/ember/uart/enums.d.ts.map +0 -1
  383. package/dist/adapter/ember/uart/enums.js +0 -197
  384. package/dist/adapter/ember/uart/enums.js.map +0 -1
  385. package/dist/adapter/ember/uart/parser.d.ts +0 -10
  386. package/dist/adapter/ember/uart/parser.d.ts.map +0 -1
  387. package/dist/adapter/ember/uart/parser.js +0 -37
  388. package/dist/adapter/ember/uart/parser.js.map +0 -1
  389. package/dist/adapter/ember/uart/queues.d.ts +0 -85
  390. package/dist/adapter/ember/uart/queues.d.ts.map +0 -1
  391. package/dist/adapter/ember/uart/queues.js +0 -214
  392. package/dist/adapter/ember/uart/queues.js.map +0 -1
  393. package/dist/adapter/ember/uart/writer.d.ts +0 -15
  394. package/dist/adapter/ember/uart/writer.d.ts.map +0 -1
  395. package/dist/adapter/ember/uart/writer.js +0 -46
  396. package/dist/adapter/ember/uart/writer.js.map +0 -1
  397. package/dist/adapter/ember/utils/initters.d.ts +0 -20
  398. package/dist/adapter/ember/utils/initters.d.ts.map +0 -1
  399. package/dist/adapter/ember/utils/initters.js +0 -58
  400. package/dist/adapter/ember/utils/initters.js.map +0 -1
  401. package/dist/adapter/ember/utils/math.d.ts +0 -51
  402. package/dist/adapter/ember/utils/math.d.ts.map +0 -1
  403. package/dist/adapter/ember/utils/math.js +0 -102
  404. package/dist/adapter/ember/utils/math.js.map +0 -1
  405. package/dist/adapter/ember/zdo.d.ts +0 -925
  406. package/dist/adapter/ember/zdo.d.ts.map +0 -1
  407. package/dist/adapter/ember/zdo.js +0 -723
  408. package/dist/adapter/ember/zdo.js.map +0 -1
  409. package/dist/adapter/events.d.ts +0 -42
  410. package/dist/adapter/events.d.ts.map +0 -1
  411. package/dist/adapter/events.js +0 -13
  412. package/dist/adapter/events.js.map +0 -1
  413. package/dist/adapter/ezsp/adapter/backup.d.ts +0 -13
  414. package/dist/adapter/ezsp/adapter/backup.d.ts.map +0 -1
  415. package/dist/adapter/ezsp/adapter/backup.js +0 -101
  416. package/dist/adapter/ezsp/adapter/backup.js.map +0 -1
  417. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +0 -65
  418. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +0 -1
  419. package/dist/adapter/ezsp/adapter/ezspAdapter.js +0 -634
  420. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +0 -1
  421. package/dist/adapter/ezsp/adapter/index.d.ts +0 -3
  422. package/dist/adapter/ezsp/adapter/index.d.ts.map +0 -1
  423. package/dist/adapter/ezsp/adapter/index.js +0 -11
  424. package/dist/adapter/ezsp/adapter/index.js.map +0 -1
  425. package/dist/adapter/ezsp/driver/commands.d.ts +0 -37
  426. package/dist/adapter/ezsp/driver/commands.d.ts.map +0 -1
  427. package/dist/adapter/ezsp/driver/commands.js +0 -2387
  428. package/dist/adapter/ezsp/driver/commands.js.map +0 -1
  429. package/dist/adapter/ezsp/driver/consts.d.ts +0 -11
  430. package/dist/adapter/ezsp/driver/consts.d.ts.map +0 -1
  431. package/dist/adapter/ezsp/driver/consts.js +0 -14
  432. package/dist/adapter/ezsp/driver/consts.js.map +0 -1
  433. package/dist/adapter/ezsp/driver/driver.d.ts +0 -109
  434. package/dist/adapter/ezsp/driver/driver.d.ts.map +0 -1
  435. package/dist/adapter/ezsp/driver/driver.js +0 -796
  436. package/dist/adapter/ezsp/driver/driver.js.map +0 -1
  437. package/dist/adapter/ezsp/driver/ezsp.d.ts +0 -106
  438. package/dist/adapter/ezsp/driver/ezsp.d.ts.map +0 -1
  439. package/dist/adapter/ezsp/driver/ezsp.js +0 -664
  440. package/dist/adapter/ezsp/driver/ezsp.js.map +0 -1
  441. package/dist/adapter/ezsp/driver/frame.d.ts +0 -40
  442. package/dist/adapter/ezsp/driver/frame.d.ts.map +0 -1
  443. package/dist/adapter/ezsp/driver/frame.js +0 -101
  444. package/dist/adapter/ezsp/driver/frame.js.map +0 -1
  445. package/dist/adapter/ezsp/driver/index.d.ts +0 -4
  446. package/dist/adapter/ezsp/driver/index.d.ts.map +0 -1
  447. package/dist/adapter/ezsp/driver/index.js +0 -9
  448. package/dist/adapter/ezsp/driver/index.js.map +0 -1
  449. package/dist/adapter/ezsp/driver/multicast.d.ts +0 -13
  450. package/dist/adapter/ezsp/driver/multicast.d.ts.map +0 -1
  451. package/dist/adapter/ezsp/driver/multicast.js +0 -74
  452. package/dist/adapter/ezsp/driver/multicast.js.map +0 -1
  453. package/dist/adapter/ezsp/driver/parser.d.ts +0 -12
  454. package/dist/adapter/ezsp/driver/parser.d.ts.map +0 -1
  455. package/dist/adapter/ezsp/driver/parser.js +0 -105
  456. package/dist/adapter/ezsp/driver/parser.js.map +0 -1
  457. package/dist/adapter/ezsp/driver/types/basic.d.ts +0 -63
  458. package/dist/adapter/ezsp/driver/types/basic.d.ts.map +0 -1
  459. package/dist/adapter/ezsp/driver/types/basic.js +0 -209
  460. package/dist/adapter/ezsp/driver/types/basic.js.map +0 -1
  461. package/dist/adapter/ezsp/driver/types/index.d.ts +0 -10
  462. package/dist/adapter/ezsp/driver/types/index.d.ts.map +0 -1
  463. package/dist/adapter/ezsp/driver/types/index.js +0 -139
  464. package/dist/adapter/ezsp/driver/types/index.js.map +0 -1
  465. package/dist/adapter/ezsp/driver/types/named.d.ts +0 -1288
  466. package/dist/adapter/ezsp/driver/types/named.d.ts.map +0 -1
  467. package/dist/adapter/ezsp/driver/types/named.js +0 -2330
  468. package/dist/adapter/ezsp/driver/types/named.js.map +0 -1
  469. package/dist/adapter/ezsp/driver/types/struct.d.ts +0 -271
  470. package/dist/adapter/ezsp/driver/types/struct.d.ts.map +0 -1
  471. package/dist/adapter/ezsp/driver/types/struct.js +0 -804
  472. package/dist/adapter/ezsp/driver/types/struct.js.map +0 -1
  473. package/dist/adapter/ezsp/driver/uart.d.ts +0 -49
  474. package/dist/adapter/ezsp/driver/uart.d.ts.map +0 -1
  475. package/dist/adapter/ezsp/driver/uart.js +0 -383
  476. package/dist/adapter/ezsp/driver/uart.js.map +0 -1
  477. package/dist/adapter/ezsp/driver/utils/crc16ccitt.d.ts +0 -3
  478. package/dist/adapter/ezsp/driver/utils/crc16ccitt.d.ts.map +0 -1
  479. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js +0 -56
  480. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js.map +0 -1
  481. package/dist/adapter/ezsp/driver/utils/index.d.ts +0 -20
  482. package/dist/adapter/ezsp/driver/utils/index.d.ts.map +0 -1
  483. package/dist/adapter/ezsp/driver/utils/index.js +0 -73
  484. package/dist/adapter/ezsp/driver/utils/index.js.map +0 -1
  485. package/dist/adapter/ezsp/driver/writer.d.ts +0 -14
  486. package/dist/adapter/ezsp/driver/writer.d.ts.map +0 -1
  487. package/dist/adapter/ezsp/driver/writer.js +0 -83
  488. package/dist/adapter/ezsp/driver/writer.js.map +0 -1
  489. package/dist/adapter/index.d.ts +0 -5
  490. package/dist/adapter/index.d.ts.map +0 -1
  491. package/dist/adapter/index.js +0 -36
  492. package/dist/adapter/index.js.map +0 -1
  493. package/dist/adapter/serialPort.d.ts +0 -14
  494. package/dist/adapter/serialPort.d.ts.map +0 -1
  495. package/dist/adapter/serialPort.js +0 -47
  496. package/dist/adapter/serialPort.js.map +0 -1
  497. package/dist/adapter/serialPortUtils.d.ts +0 -13
  498. package/dist/adapter/serialPortUtils.d.ts.map +0 -1
  499. package/dist/adapter/serialPortUtils.js +0 -19
  500. package/dist/adapter/serialPortUtils.js.map +0 -1
  501. package/dist/adapter/socketPortUtils.d.ts +0 -11
  502. package/dist/adapter/socketPortUtils.d.ts.map +0 -1
  503. package/dist/adapter/socketPortUtils.js +0 -17
  504. package/dist/adapter/socketPortUtils.js.map +0 -1
  505. package/dist/adapter/tstype.d.ts +0 -86
  506. package/dist/adapter/tstype.d.ts.map +0 -1
  507. package/dist/adapter/tstype.js +0 -3
  508. package/dist/adapter/tstype.js.map +0 -1
  509. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts +0 -62
  510. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts.map +0 -1
  511. package/dist/adapter/z-stack/adapter/adapter-backup.js +0 -459
  512. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +0 -1
  513. package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts +0 -151
  514. package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts.map +0 -1
  515. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +0 -259
  516. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +0 -1
  517. package/dist/adapter/z-stack/adapter/endpoints.d.ts +0 -12
  518. package/dist/adapter/z-stack/adapter/endpoints.d.ts.map +0 -1
  519. package/dist/adapter/z-stack/adapter/endpoints.js +0 -74
  520. package/dist/adapter/z-stack/adapter/endpoints.js.map +0 -1
  521. package/dist/adapter/z-stack/adapter/index.d.ts +0 -3
  522. package/dist/adapter/z-stack/adapter/index.d.ts.map +0 -1
  523. package/dist/adapter/z-stack/adapter/index.js +0 -9
  524. package/dist/adapter/z-stack/adapter/index.js.map +0 -1
  525. package/dist/adapter/z-stack/adapter/manager.d.ts +0 -84
  526. package/dist/adapter/z-stack/adapter/manager.d.ts.map +0 -1
  527. package/dist/adapter/z-stack/adapter/manager.js +0 -474
  528. package/dist/adapter/z-stack/adapter/manager.js.map +0 -1
  529. package/dist/adapter/z-stack/adapter/tstype.d.ts +0 -7
  530. package/dist/adapter/z-stack/adapter/tstype.d.ts.map +0 -1
  531. package/dist/adapter/z-stack/adapter/tstype.js +0 -10
  532. package/dist/adapter/z-stack/adapter/tstype.js.map +0 -1
  533. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +0 -86
  534. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +0 -1
  535. package/dist/adapter/z-stack/adapter/zStackAdapter.js +0 -912
  536. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +0 -1
  537. package/dist/adapter/z-stack/constants/af.d.ts +0 -24
  538. package/dist/adapter/z-stack/constants/af.d.ts.map +0 -1
  539. package/dist/adapter/z-stack/constants/af.js +0 -28
  540. package/dist/adapter/z-stack/constants/af.js.map +0 -1
  541. package/dist/adapter/z-stack/constants/common.d.ts +0 -279
  542. package/dist/adapter/z-stack/constants/common.d.ts.map +0 -1
  543. package/dist/adapter/z-stack/constants/common.js +0 -293
  544. package/dist/adapter/z-stack/constants/common.js.map +0 -1
  545. package/dist/adapter/z-stack/constants/dbg.d.ts +0 -23
  546. package/dist/adapter/z-stack/constants/dbg.d.ts.map +0 -1
  547. package/dist/adapter/z-stack/constants/dbg.js +0 -25
  548. package/dist/adapter/z-stack/constants/dbg.js.map +0 -1
  549. package/dist/adapter/z-stack/constants/index.d.ts +0 -11
  550. package/dist/adapter/z-stack/constants/index.d.ts.map +0 -1
  551. package/dist/adapter/z-stack/constants/index.js +0 -48
  552. package/dist/adapter/z-stack/constants/index.js.map +0 -1
  553. package/dist/adapter/z-stack/constants/mac.d.ts +0 -128
  554. package/dist/adapter/z-stack/constants/mac.d.ts.map +0 -1
  555. package/dist/adapter/z-stack/constants/mac.js +0 -130
  556. package/dist/adapter/z-stack/constants/mac.js.map +0 -1
  557. package/dist/adapter/z-stack/constants/sapi.d.ts +0 -25
  558. package/dist/adapter/z-stack/constants/sapi.d.ts.map +0 -1
  559. package/dist/adapter/z-stack/constants/sapi.js +0 -27
  560. package/dist/adapter/z-stack/constants/sapi.js.map +0 -1
  561. package/dist/adapter/z-stack/constants/sys.d.ts +0 -72
  562. package/dist/adapter/z-stack/constants/sys.d.ts.map +0 -1
  563. package/dist/adapter/z-stack/constants/sys.js +0 -74
  564. package/dist/adapter/z-stack/constants/sys.js.map +0 -1
  565. package/dist/adapter/z-stack/constants/util.d.ts +0 -82
  566. package/dist/adapter/z-stack/constants/util.d.ts.map +0 -1
  567. package/dist/adapter/z-stack/constants/util.js +0 -84
  568. package/dist/adapter/z-stack/constants/util.js.map +0 -1
  569. package/dist/adapter/z-stack/constants/utils.d.ts +0 -5
  570. package/dist/adapter/z-stack/constants/utils.d.ts.map +0 -1
  571. package/dist/adapter/z-stack/constants/utils.js +0 -15
  572. package/dist/adapter/z-stack/constants/utils.js.map +0 -1
  573. package/dist/adapter/z-stack/constants/zdo.d.ts +0 -103
  574. package/dist/adapter/z-stack/constants/zdo.d.ts.map +0 -1
  575. package/dist/adapter/z-stack/constants/zdo.js +0 -105
  576. package/dist/adapter/z-stack/constants/zdo.js.map +0 -1
  577. package/dist/adapter/z-stack/models/index.d.ts +0 -2
  578. package/dist/adapter/z-stack/models/index.d.ts.map +0 -1
  579. package/dist/adapter/z-stack/models/index.js +0 -18
  580. package/dist/adapter/z-stack/models/index.js.map +0 -1
  581. package/dist/adapter/z-stack/models/startup-options.d.ts +0 -13
  582. package/dist/adapter/z-stack/models/startup-options.d.ts.map +0 -1
  583. package/dist/adapter/z-stack/models/startup-options.js +0 -3
  584. package/dist/adapter/z-stack/models/startup-options.js.map +0 -1
  585. package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts +0 -24
  586. package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts.map +0 -1
  587. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js +0 -46
  588. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js.map +0 -1
  589. package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts +0 -11
  590. package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts.map +0 -1
  591. package/dist/adapter/z-stack/structs/entries/address-manager-table.js +0 -23
  592. package/dist/adapter/z-stack/structs/entries/address-manager-table.js.map +0 -1
  593. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts +0 -11
  594. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts.map +0 -1
  595. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js +0 -22
  596. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js.map +0 -1
  597. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts +0 -11
  598. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts.map +0 -1
  599. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js +0 -24
  600. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js.map +0 -1
  601. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts +0 -11
  602. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts.map +0 -1
  603. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js +0 -25
  604. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js.map +0 -1
  605. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts +0 -11
  606. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts.map +0 -1
  607. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js +0 -24
  608. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js.map +0 -1
  609. package/dist/adapter/z-stack/structs/entries/channel-list.d.ts +0 -9
  610. package/dist/adapter/z-stack/structs/entries/channel-list.d.ts.map +0 -1
  611. package/dist/adapter/z-stack/structs/entries/channel-list.js +0 -16
  612. package/dist/adapter/z-stack/structs/entries/channel-list.js.map +0 -1
  613. package/dist/adapter/z-stack/structs/entries/has-configured.d.ts +0 -9
  614. package/dist/adapter/z-stack/structs/entries/has-configured.d.ts.map +0 -1
  615. package/dist/adapter/z-stack/structs/entries/has-configured.js +0 -17
  616. package/dist/adapter/z-stack/structs/entries/has-configured.js.map +0 -1
  617. package/dist/adapter/z-stack/structs/entries/index.d.ts +0 -17
  618. package/dist/adapter/z-stack/structs/entries/index.d.ts.map +0 -1
  619. package/dist/adapter/z-stack/structs/entries/index.js +0 -33
  620. package/dist/adapter/z-stack/structs/entries/index.js.map +0 -1
  621. package/dist/adapter/z-stack/structs/entries/nib.d.ts +0 -11
  622. package/dist/adapter/z-stack/structs/entries/nib.d.ts.map +0 -1
  623. package/dist/adapter/z-stack/structs/entries/nib.js +0 -69
  624. package/dist/adapter/z-stack/structs/entries/nib.js.map +0 -1
  625. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts +0 -11
  626. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts.map +0 -1
  627. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js +0 -19
  628. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js.map +0 -1
  629. package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts +0 -9
  630. package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts.map +0 -1
  631. package/dist/adapter/z-stack/structs/entries/nwk-key.js +0 -16
  632. package/dist/adapter/z-stack/structs/entries/nwk-key.js.map +0 -1
  633. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts +0 -9
  634. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts.map +0 -1
  635. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js +0 -16
  636. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js.map +0 -1
  637. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts +0 -14
  638. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts.map +0 -1
  639. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js +0 -24
  640. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js.map +0 -1
  641. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts +0 -11
  642. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts.map +0 -1
  643. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js +0 -23
  644. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js.map +0 -1
  645. package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts +0 -21
  646. package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts.map +0 -1
  647. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js +0 -37
  648. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js.map +0 -1
  649. package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts +0 -11
  650. package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts.map +0 -1
  651. package/dist/adapter/z-stack/structs/entries/security-manager-table.js +0 -25
  652. package/dist/adapter/z-stack/structs/entries/security-manager-table.js.map +0 -1
  653. package/dist/adapter/z-stack/structs/index.d.ts +0 -5
  654. package/dist/adapter/z-stack/structs/index.d.ts.map +0 -1
  655. package/dist/adapter/z-stack/structs/index.js +0 -21
  656. package/dist/adapter/z-stack/structs/index.js.map +0 -1
  657. package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts +0 -14
  658. package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts.map +0 -1
  659. package/dist/adapter/z-stack/structs/serializable-memory-object.js +0 -3
  660. package/dist/adapter/z-stack/structs/serializable-memory-object.js.map +0 -1
  661. package/dist/adapter/z-stack/structs/struct.d.ts +0 -100
  662. package/dist/adapter/z-stack/structs/struct.d.ts.map +0 -1
  663. package/dist/adapter/z-stack/structs/struct.js +0 -297
  664. package/dist/adapter/z-stack/structs/struct.js.map +0 -1
  665. package/dist/adapter/z-stack/structs/table.d.ts +0 -95
  666. package/dist/adapter/z-stack/structs/table.d.ts.map +0 -1
  667. package/dist/adapter/z-stack/structs/table.js +0 -164
  668. package/dist/adapter/z-stack/structs/table.js.map +0 -1
  669. package/dist/adapter/z-stack/unpi/constants.d.ts +0 -29
  670. package/dist/adapter/z-stack/unpi/constants.d.ts.map +0 -1
  671. package/dist/adapter/z-stack/unpi/constants.js +0 -40
  672. package/dist/adapter/z-stack/unpi/constants.js.map +0 -1
  673. package/dist/adapter/z-stack/unpi/frame.d.ts +0 -17
  674. package/dist/adapter/z-stack/unpi/frame.d.ts.map +0 -1
  675. package/dist/adapter/z-stack/unpi/frame.js +0 -55
  676. package/dist/adapter/z-stack/unpi/frame.js.map +0 -1
  677. package/dist/adapter/z-stack/unpi/index.d.ts +0 -6
  678. package/dist/adapter/z-stack/unpi/index.d.ts.map +0 -1
  679. package/dist/adapter/z-stack/unpi/index.js +0 -38
  680. package/dist/adapter/z-stack/unpi/index.js.map +0 -1
  681. package/dist/adapter/z-stack/unpi/parser.d.ts +0 -13
  682. package/dist/adapter/z-stack/unpi/parser.d.ts.map +0 -1
  683. package/dist/adapter/z-stack/unpi/parser.js +0 -86
  684. package/dist/adapter/z-stack/unpi/parser.js.map +0 -1
  685. package/dist/adapter/z-stack/unpi/writer.d.ts +0 -12
  686. package/dist/adapter/z-stack/unpi/writer.d.ts.map +0 -1
  687. package/dist/adapter/z-stack/unpi/writer.js +0 -55
  688. package/dist/adapter/z-stack/unpi/writer.js.map +0 -1
  689. package/dist/adapter/z-stack/utils/channel-list.d.ts +0 -21
  690. package/dist/adapter/z-stack/utils/channel-list.d.ts.map +0 -1
  691. package/dist/adapter/z-stack/utils/channel-list.js +0 -41
  692. package/dist/adapter/z-stack/utils/channel-list.js.map +0 -1
  693. package/dist/adapter/z-stack/utils/index.d.ts +0 -3
  694. package/dist/adapter/z-stack/utils/index.d.ts.map +0 -1
  695. package/dist/adapter/z-stack/utils/index.js +0 -19
  696. package/dist/adapter/z-stack/utils/index.js.map +0 -1
  697. package/dist/adapter/z-stack/utils/network-options.d.ts +0 -9
  698. package/dist/adapter/z-stack/utils/network-options.d.ts.map +0 -1
  699. package/dist/adapter/z-stack/utils/network-options.js +0 -23
  700. package/dist/adapter/z-stack/utils/network-options.js.map +0 -1
  701. package/dist/adapter/z-stack/znp/buffaloZnp.d.ts +0 -14
  702. package/dist/adapter/z-stack/znp/buffaloZnp.d.ts.map +0 -1
  703. package/dist/adapter/z-stack/znp/buffaloZnp.js +0 -243
  704. package/dist/adapter/z-stack/znp/buffaloZnp.js.map +0 -1
  705. package/dist/adapter/z-stack/znp/definition.d.ts +0 -6
  706. package/dist/adapter/z-stack/znp/definition.d.ts.map +0 -1
  707. package/dist/adapter/z-stack/znp/definition.js +0 -3052
  708. package/dist/adapter/z-stack/znp/definition.js.map +0 -1
  709. package/dist/adapter/z-stack/znp/index.d.ts +0 -4
  710. package/dist/adapter/z-stack/znp/index.d.ts.map +0 -1
  711. package/dist/adapter/z-stack/znp/index.js +0 -11
  712. package/dist/adapter/z-stack/znp/index.js.map +0 -1
  713. package/dist/adapter/z-stack/znp/parameterType.d.ts +0 -23
  714. package/dist/adapter/z-stack/znp/parameterType.d.ts.map +0 -1
  715. package/dist/adapter/z-stack/znp/parameterType.js +0 -26
  716. package/dist/adapter/z-stack/znp/parameterType.js.map +0 -1
  717. package/dist/adapter/z-stack/znp/tstype.d.ts +0 -23
  718. package/dist/adapter/z-stack/znp/tstype.d.ts.map +0 -1
  719. package/dist/adapter/z-stack/znp/tstype.js +0 -3
  720. package/dist/adapter/z-stack/znp/tstype.js.map +0 -1
  721. package/dist/adapter/z-stack/znp/znp.d.ts +0 -47
  722. package/dist/adapter/z-stack/znp/znp.d.ts.map +0 -1
  723. package/dist/adapter/z-stack/znp/znp.js +0 -322
  724. package/dist/adapter/z-stack/znp/znp.js.map +0 -1
  725. package/dist/adapter/z-stack/znp/zpiObject.d.ts +0 -20
  726. package/dist/adapter/z-stack/znp/zpiObject.d.ts.map +0 -1
  727. package/dist/adapter/z-stack/znp/zpiObject.js +0 -103
  728. package/dist/adapter/z-stack/znp/zpiObject.js.map +0 -1
  729. package/dist/adapter/zigate/adapter/index.d.ts +0 -3
  730. package/dist/adapter/zigate/adapter/index.d.ts.map +0 -1
  731. package/dist/adapter/zigate/adapter/index.js +0 -11
  732. package/dist/adapter/zigate/adapter/index.js.map +0 -1
  733. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +0 -72
  734. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +0 -1
  735. package/dist/adapter/zigate/adapter/zigateAdapter.js +0 -681
  736. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +0 -1
  737. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts +0 -18
  738. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts.map +0 -1
  739. package/dist/adapter/zigate/driver/buffaloZiGate.js +0 -190
  740. package/dist/adapter/zigate/driver/buffaloZiGate.js.map +0 -1
  741. package/dist/adapter/zigate/driver/commandType.d.ts +0 -43
  742. package/dist/adapter/zigate/driver/commandType.d.ts.map +0 -1
  743. package/dist/adapter/zigate/driver/commandType.js +0 -390
  744. package/dist/adapter/zigate/driver/commandType.js.map +0 -1
  745. package/dist/adapter/zigate/driver/constants.d.ts +0 -277
  746. package/dist/adapter/zigate/driver/constants.d.ts.map +0 -1
  747. package/dist/adapter/zigate/driver/constants.js +0 -372
  748. package/dist/adapter/zigate/driver/constants.js.map +0 -1
  749. package/dist/adapter/zigate/driver/frame.d.ts +0 -27
  750. package/dist/adapter/zigate/driver/frame.d.ts.map +0 -1
  751. package/dist/adapter/zigate/driver/frame.js +0 -173
  752. package/dist/adapter/zigate/driver/frame.js.map +0 -1
  753. package/dist/adapter/zigate/driver/messageType.d.ts +0 -13
  754. package/dist/adapter/zigate/driver/messageType.d.ts.map +0 -1
  755. package/dist/adapter/zigate/driver/messageType.js +0 -284
  756. package/dist/adapter/zigate/driver/messageType.js.map +0 -1
  757. package/dist/adapter/zigate/driver/parameterType.d.ts +0 -28
  758. package/dist/adapter/zigate/driver/parameterType.d.ts.map +0 -1
  759. package/dist/adapter/zigate/driver/parameterType.js +0 -33
  760. package/dist/adapter/zigate/driver/parameterType.js.map +0 -1
  761. package/dist/adapter/zigate/driver/ziGateObject.d.ts +0 -24
  762. package/dist/adapter/zigate/driver/ziGateObject.d.ts.map +0 -1
  763. package/dist/adapter/zigate/driver/ziGateObject.js +0 -111
  764. package/dist/adapter/zigate/driver/ziGateObject.js.map +0 -1
  765. package/dist/adapter/zigate/driver/zigate.d.ts +0 -50
  766. package/dist/adapter/zigate/driver/zigate.d.ts.map +0 -1
  767. package/dist/adapter/zigate/driver/zigate.js +0 -289
  768. package/dist/adapter/zigate/driver/zigate.js.map +0 -1
  769. package/dist/buffalo/buffalo.d.ts +0 -55
  770. package/dist/buffalo/buffalo.d.ts.map +0 -1
  771. package/dist/buffalo/buffalo.js +0 -230
  772. package/dist/buffalo/buffalo.js.map +0 -1
  773. package/dist/buffalo/index.d.ts +0 -3
  774. package/dist/buffalo/index.d.ts.map +0 -1
  775. package/dist/buffalo/index.js +0 -9
  776. package/dist/buffalo/index.js.map +0 -1
  777. package/dist/controller/controller.d.ts +0 -119
  778. package/dist/controller/controller.d.ts.map +0 -1
  779. package/dist/controller/controller.js +0 -700
  780. package/dist/controller/controller.js.map +0 -1
  781. package/dist/controller/database.d.ts +0 -20
  782. package/dist/controller/database.d.ts.map +0 -1
  783. package/dist/controller/database.js +0 -94
  784. package/dist/controller/database.js.map +0 -1
  785. package/dist/controller/events.d.ts +0 -59
  786. package/dist/controller/events.d.ts.map +0 -1
  787. package/dist/controller/events.js +0 -113
  788. package/dist/controller/events.js.map +0 -1
  789. package/dist/controller/greenPower.d.ts +0 -14
  790. package/dist/controller/greenPower.d.ts.map +0 -1
  791. package/dist/controller/greenPower.js +0 -216
  792. package/dist/controller/greenPower.js.map +0 -1
  793. package/dist/controller/helpers/index.d.ts +0 -3
  794. package/dist/controller/helpers/index.d.ts.map +0 -1
  795. package/dist/controller/helpers/index.js +0 -29
  796. package/dist/controller/helpers/index.js.map +0 -1
  797. package/dist/controller/helpers/request.d.ts +0 -22
  798. package/dist/controller/helpers/request.d.ts.map +0 -1
  799. package/dist/controller/helpers/request.js +0 -78
  800. package/dist/controller/helpers/request.js.map +0 -1
  801. package/dist/controller/helpers/requestQueue.d.ts +0 -13
  802. package/dist/controller/helpers/requestQueue.d.ts.map +0 -1
  803. package/dist/controller/helpers/requestQueue.js +0 -106
  804. package/dist/controller/helpers/requestQueue.js.map +0 -1
  805. package/dist/controller/helpers/zclFrameConverter.d.ts +0 -9
  806. package/dist/controller/helpers/zclFrameConverter.d.ts.map +0 -1
  807. package/dist/controller/helpers/zclFrameConverter.js +0 -70
  808. package/dist/controller/helpers/zclFrameConverter.js.map +0 -1
  809. package/dist/controller/helpers/zclTransactionSequenceNumber.d.ts +0 -6
  810. package/dist/controller/helpers/zclTransactionSequenceNumber.d.ts.map +0 -1
  811. package/dist/controller/helpers/zclTransactionSequenceNumber.js +0 -14
  812. package/dist/controller/helpers/zclTransactionSequenceNumber.js.map +0 -1
  813. package/dist/controller/index.d.ts +0 -6
  814. package/dist/controller/index.d.ts.map +0 -1
  815. package/dist/controller/index.js +0 -9
  816. package/dist/controller/index.js.map +0 -1
  817. package/dist/controller/model/device.d.ts +0 -140
  818. package/dist/controller/model/device.d.ts.map +0 -1
  819. package/dist/controller/model/device.js +0 -746
  820. package/dist/controller/model/device.js.map +0 -1
  821. package/dist/controller/model/endpoint.d.ts +0 -134
  822. package/dist/controller/model/endpoint.d.ts.map +0 -1
  823. package/dist/controller/model/endpoint.js +0 -667
  824. package/dist/controller/model/endpoint.js.map +0 -1
  825. package/dist/controller/model/entity.d.ts +0 -15
  826. package/dist/controller/model/entity.d.ts.map +0 -1
  827. package/dist/controller/model/entity.js +0 -27
  828. package/dist/controller/model/entity.js.map +0 -1
  829. package/dist/controller/model/group.d.ts +0 -39
  830. package/dist/controller/model/group.d.ts.map +0 -1
  831. package/dist/controller/model/group.js +0 -226
  832. package/dist/controller/model/group.js.map +0 -1
  833. package/dist/controller/model/index.d.ts +0 -6
  834. package/dist/controller/model/index.d.ts.map +0 -1
  835. package/dist/controller/model/index.js +0 -15
  836. package/dist/controller/model/index.js.map +0 -1
  837. package/dist/controller/model/konnextConfig.d.ts +0 -7
  838. package/dist/controller/model/konnextConfig.d.ts.map +0 -1
  839. package/dist/controller/model/konnextConfig.js +0 -3
  840. package/dist/controller/model/konnextConfig.js.map +0 -1
  841. package/dist/controller/touchlink.d.ts +0 -20
  842. package/dist/controller/touchlink.d.ts.map +0 -1
  843. package/dist/controller/touchlink.js +0 -157
  844. package/dist/controller/touchlink.js.map +0 -1
  845. package/dist/controller/tstype.d.ts +0 -21
  846. package/dist/controller/tstype.d.ts.map +0 -1
  847. package/dist/controller/tstype.js +0 -9
  848. package/dist/controller/tstype.js.map +0 -1
  849. package/dist/index.d.ts +0 -6
  850. package/dist/index.d.ts.map +0 -1
  851. package/dist/index.js +0 -37
  852. package/dist/index.js.map +0 -1
  853. package/dist/models/backup-storage-legacy.d.ts +0 -27
  854. package/dist/models/backup-storage-legacy.d.ts.map +0 -1
  855. package/dist/models/backup-storage-legacy.js +0 -3
  856. package/dist/models/backup-storage-legacy.js.map +0 -1
  857. package/dist/models/backup-storage-unified.d.ts +0 -50
  858. package/dist/models/backup-storage-unified.d.ts.map +0 -1
  859. package/dist/models/backup-storage-unified.js +0 -3
  860. package/dist/models/backup-storage-unified.js.map +0 -1
  861. package/dist/models/backup.d.ts +0 -38
  862. package/dist/models/backup.d.ts.map +0 -1
  863. package/dist/models/backup.js +0 -3
  864. package/dist/models/backup.js.map +0 -1
  865. package/dist/models/index.d.ts +0 -5
  866. package/dist/models/index.d.ts.map +0 -1
  867. package/dist/models/index.js +0 -21
  868. package/dist/models/index.js.map +0 -1
  869. package/dist/models/network-options.d.ts +0 -13
  870. package/dist/models/network-options.d.ts.map +0 -1
  871. package/dist/models/network-options.js +0 -3
  872. package/dist/models/network-options.js.map +0 -1
  873. package/dist/utils/aes.d.ts +0 -40
  874. package/dist/utils/aes.d.ts.map +0 -1
  875. package/dist/utils/aes.js +0 -198
  876. package/dist/utils/aes.js.map +0 -1
  877. package/dist/utils/assertString.d.ts +0 -3
  878. package/dist/utils/assertString.d.ts.map +0 -1
  879. package/dist/utils/assertString.js +0 -9
  880. package/dist/utils/assertString.js.map +0 -1
  881. package/dist/utils/backup.d.ts +0 -21
  882. package/dist/utils/backup.d.ts.map +0 -1
  883. package/dist/utils/backup.js +0 -190
  884. package/dist/utils/backup.js.map +0 -1
  885. package/dist/utils/equalsPartial.d.ts +0 -3
  886. package/dist/utils/equalsPartial.d.ts.map +0 -1
  887. package/dist/utils/equalsPartial.js +0 -12
  888. package/dist/utils/equalsPartial.js.map +0 -1
  889. package/dist/utils/index.d.ts +0 -10
  890. package/dist/utils/index.d.ts.map +0 -1
  891. package/dist/utils/index.js +0 -46
  892. package/dist/utils/index.js.map +0 -1
  893. package/dist/utils/isNumberArray.d.ts +0 -3
  894. package/dist/utils/isNumberArray.d.ts.map +0 -1
  895. package/dist/utils/isNumberArray.js +0 -7
  896. package/dist/utils/isNumberArray.js.map +0 -1
  897. package/dist/utils/logger.d.ts +0 -9
  898. package/dist/utils/logger.d.ts.map +0 -1
  899. package/dist/utils/logger.js +0 -14
  900. package/dist/utils/logger.js.map +0 -1
  901. package/dist/utils/queue.d.ts +0 -12
  902. package/dist/utils/queue.d.ts.map +0 -1
  903. package/dist/utils/queue.js +0 -62
  904. package/dist/utils/queue.js.map +0 -1
  905. package/dist/utils/realpathSync.d.ts +0 -3
  906. package/dist/utils/realpathSync.d.ts.map +0 -1
  907. package/dist/utils/realpathSync.js +0 -13
  908. package/dist/utils/realpathSync.js.map +0 -1
  909. package/dist/utils/wait.d.ts +0 -3
  910. package/dist/utils/wait.d.ts.map +0 -1
  911. package/dist/utils/wait.js +0 -9
  912. package/dist/utils/wait.js.map +0 -1
  913. package/dist/utils/waitress.d.ts +0 -22
  914. package/dist/utils/waitress.d.ts.map +0 -1
  915. package/dist/utils/waitress.js +0 -69
  916. package/dist/utils/waitress.js.map +0 -1
  917. package/dist/zspec/consts.d.ts +0 -60
  918. package/dist/zspec/consts.d.ts.map +0 -1
  919. package/dist/zspec/consts.js +0 -64
  920. package/dist/zspec/consts.js.map +0 -1
  921. package/dist/zspec/enums.d.ts +0 -19
  922. package/dist/zspec/enums.d.ts.map +0 -1
  923. package/dist/zspec/enums.js +0 -28
  924. package/dist/zspec/enums.js.map +0 -1
  925. package/dist/zspec/index.d.ts +0 -4
  926. package/dist/zspec/index.d.ts.map +0 -1
  927. package/dist/zspec/index.js +0 -43
  928. package/dist/zspec/index.js.map +0 -1
  929. package/dist/zspec/tstypes.d.ts +0 -19
  930. package/dist/zspec/tstypes.d.ts.map +0 -1
  931. package/dist/zspec/tstypes.js +0 -3
  932. package/dist/zspec/tstypes.js.map +0 -1
  933. package/dist/zspec/utils.d.ts +0 -14
  934. package/dist/zspec/utils.d.ts.map +0 -1
  935. package/dist/zspec/utils.js +0 -29
  936. package/dist/zspec/utils.js.map +0 -1
  937. package/dist/zspec/zcl/buffaloZcl.d.ts +0 -55
  938. package/dist/zspec/zcl/buffaloZcl.d.ts.map +0 -1
  939. package/dist/zspec/zcl/buffaloZcl.js +0 -929
  940. package/dist/zspec/zcl/buffaloZcl.js.map +0 -1
  941. package/dist/zspec/zcl/definition/cluster.d.ts +0 -3
  942. package/dist/zspec/zcl/definition/cluster.d.ts.map +0 -1
  943. package/dist/zspec/zcl/definition/cluster.js +0 -5500
  944. package/dist/zspec/zcl/definition/cluster.js.map +0 -1
  945. package/dist/zspec/zcl/definition/consts.d.ts +0 -9
  946. package/dist/zspec/zcl/definition/consts.d.ts.map +0 -1
  947. package/dist/zspec/zcl/definition/consts.js +0 -27
  948. package/dist/zspec/zcl/definition/consts.js.map +0 -1
  949. package/dist/zspec/zcl/definition/enums.d.ts +0 -177
  950. package/dist/zspec/zcl/definition/enums.d.ts.map +0 -1
  951. package/dist/zspec/zcl/definition/enums.js +0 -187
  952. package/dist/zspec/zcl/definition/enums.js.map +0 -1
  953. package/dist/zspec/zcl/definition/foundation.d.ts +0 -11
  954. package/dist/zspec/zcl/definition/foundation.d.ts.map +0 -1
  955. package/dist/zspec/zcl/definition/foundation.js +0 -241
  956. package/dist/zspec/zcl/definition/foundation.js.map +0 -1
  957. package/dist/zspec/zcl/definition/manufacturerCode.d.ts +0 -727
  958. package/dist/zspec/zcl/definition/manufacturerCode.d.ts.map +0 -1
  959. package/dist/zspec/zcl/definition/manufacturerCode.js +0 -733
  960. package/dist/zspec/zcl/definition/manufacturerCode.js.map +0 -1
  961. package/dist/zspec/zcl/definition/status.d.ts +0 -69
  962. package/dist/zspec/zcl/definition/status.d.ts.map +0 -1
  963. package/dist/zspec/zcl/definition/status.js +0 -74
  964. package/dist/zspec/zcl/definition/status.js.map +0 -1
  965. package/dist/zspec/zcl/definition/tstype.d.ts +0 -114
  966. package/dist/zspec/zcl/definition/tstype.d.ts.map +0 -1
  967. package/dist/zspec/zcl/definition/tstype.js +0 -4
  968. package/dist/zspec/zcl/definition/tstype.js.map +0 -1
  969. package/dist/zspec/zcl/index.d.ts +0 -11
  970. package/dist/zspec/zcl/index.d.ts.map +0 -1
  971. package/dist/zspec/zcl/index.js +0 -47
  972. package/dist/zspec/zcl/index.js.map +0 -1
  973. package/dist/zspec/zcl/utils.d.ts +0 -7
  974. package/dist/zspec/zcl/utils.d.ts.map +0 -1
  975. package/dist/zspec/zcl/utils.js +0 -234
  976. package/dist/zspec/zcl/utils.js.map +0 -1
  977. package/dist/zspec/zcl/zclFrame.d.ts +0 -36
  978. package/dist/zspec/zcl/zclFrame.d.ts.map +0 -1
  979. package/dist/zspec/zcl/zclFrame.js +0 -304
  980. package/dist/zspec/zcl/zclFrame.js.map +0 -1
  981. package/dist/zspec/zcl/zclHeader.d.ts +0 -17
  982. package/dist/zspec/zcl/zclHeader.d.ts.map +0 -1
  983. package/dist/zspec/zcl/zclHeader.js +0 -88
  984. package/dist/zspec/zcl/zclHeader.js.map +0 -1
  985. package/dist/zspec/zcl/zclStatusError.d.ts +0 -6
  986. package/dist/zspec/zcl/zclStatusError.d.ts.map +0 -1
  987. package/dist/zspec/zcl/zclStatusError.js +0 -13
  988. package/dist/zspec/zcl/zclStatusError.js.map +0 -1
  989. package/dist/zspec/zdo/buffaloZdo.d.ts +0 -438
  990. package/dist/zspec/zdo/buffaloZdo.d.ts.map +0 -1
  991. package/dist/zspec/zdo/buffaloZdo.js +0 -1892
  992. package/dist/zspec/zdo/buffaloZdo.js.map +0 -1
  993. package/dist/zspec/zdo/definition/clusters.d.ts +0 -624
  994. package/dist/zspec/zdo/definition/clusters.d.ts.map +0 -1
  995. package/dist/zspec/zdo/definition/clusters.js +0 -687
  996. package/dist/zspec/zdo/definition/clusters.js.map +0 -1
  997. package/dist/zspec/zdo/definition/consts.d.ts +0 -13
  998. package/dist/zspec/zdo/definition/consts.d.ts.map +0 -1
  999. package/dist/zspec/zdo/definition/consts.js +0 -16
  1000. package/dist/zspec/zdo/definition/consts.js.map +0 -1
  1001. package/dist/zspec/zdo/definition/enums.d.ts +0 -75
  1002. package/dist/zspec/zdo/definition/enums.d.ts.map +0 -1
  1003. package/dist/zspec/zdo/definition/enums.js +0 -97
  1004. package/dist/zspec/zdo/definition/enums.js.map +0 -1
  1005. package/dist/zspec/zdo/definition/status.d.ts +0 -99
  1006. package/dist/zspec/zdo/definition/status.d.ts.map +0 -1
  1007. package/dist/zspec/zdo/definition/status.js +0 -109
  1008. package/dist/zspec/zdo/definition/status.js.map +0 -1
  1009. package/dist/zspec/zdo/definition/tstypes.d.ts +0 -787
  1010. package/dist/zspec/zdo/definition/tstypes.d.ts.map +0 -1
  1011. package/dist/zspec/zdo/definition/tstypes.js +0 -3
  1012. package/dist/zspec/zdo/definition/tstypes.js.map +0 -1
  1013. package/dist/zspec/zdo/index.d.ts +0 -7
  1014. package/dist/zspec/zdo/index.d.ts.map +0 -1
  1015. package/dist/zspec/zdo/index.js +0 -39
  1016. package/dist/zspec/zdo/index.js.map +0 -1
  1017. package/dist/zspec/zdo/utils.d.ts +0 -25
  1018. package/dist/zspec/zdo/utils.d.ts.map +0 -1
  1019. package/dist/zspec/zdo/utils.js +0 -75
  1020. package/dist/zspec/zdo/utils.js.map +0 -1
  1021. package/dist/zspec/zdo/zdoStatusError.d.ts +0 -6
  1022. package/dist/zspec/zdo/zdoStatusError.d.ts.map +0 -1
  1023. package/dist/zspec/zdo/zdoStatusError.js +0 -13
  1024. package/dist/zspec/zdo/zdoStatusError.js.map +0 -1
  1025. package/typedoc-tsconfig.json +0 -44
@@ -0,0 +1,3447 @@
1
+ import {existsSync, mkdirSync, unlinkSync, writeFileSync} from "node:fs";
2
+ import path from "node:path";
3
+ import {EventEmitter} from "node:stream";
4
+ import {afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
5
+ import type {TsType} from "../../../src/adapter";
6
+ import {
7
+ DEFAULT_APS_OPTIONS,
8
+ DEFAULT_STACK_CONFIG,
9
+ EmberAdapter,
10
+ type LinkKeyBackupData,
11
+ type NetworkCache,
12
+ } from "../../../src/adapter/ember/adapter/emberAdapter";
13
+ import {FIXED_ENDPOINTS} from "../../../src/adapter/ember/adapter/endpoints";
14
+ import {OneWaitressEvents} from "../../../src/adapter/ember/adapter/oneWaitress";
15
+ import {EMBER_LOW_RAM_CONCENTRATOR, SECURITY_LEVEL_Z3} from "../../../src/adapter/ember/consts";
16
+ import {
17
+ EmberApsOption,
18
+ EmberDeviceUpdate,
19
+ EmberIncomingMessageType,
20
+ EmberJoinDecision,
21
+ EmberJoinMethod,
22
+ EmberKeyStructBitmask,
23
+ EmberNetworkStatus,
24
+ EmberNodeType,
25
+ EmberOutgoingMessageType,
26
+ EmberVersionType,
27
+ EzspStatus,
28
+ IEEE802154CcaMode,
29
+ SecManDerivedKeyType,
30
+ SecManFlag,
31
+ SecManKeyType,
32
+ SLStatus,
33
+ } from "../../../src/adapter/ember/enums";
34
+ import {EZSP_MIN_PROTOCOL_VERSION, EZSP_PROTOCOL_VERSION, EZSP_STACK_TYPE_MESH} from "../../../src/adapter/ember/ezsp/consts";
35
+ import {EzspConfigId, EzspDecisionBitmask, EzspEndpointFlag, EzspPolicyId, EzspValueId} from "../../../src/adapter/ember/ezsp/enums";
36
+ import type {EmberEzspEventMap} from "../../../src/adapter/ember/ezsp/ezsp";
37
+ import {EzspError} from "../../../src/adapter/ember/ezspError";
38
+ import type {
39
+ EmberApsFrame,
40
+ EmberMulticastTableEntry,
41
+ EmberNetworkInitStruct,
42
+ EmberNetworkParameters,
43
+ EmberVersion,
44
+ SecManAPSKeyMetadata,
45
+ SecManContext,
46
+ SecManKey,
47
+ SecManNetworkKeyInfo,
48
+ } from "../../../src/adapter/ember/types";
49
+ import {lowHighBytes} from "../../../src/adapter/ember/utils/math";
50
+ import type {DeviceJoinedPayload, DeviceLeavePayload, ZclPayload} from "../../../src/adapter/events";
51
+ import type {AdapterOptions, NetworkOptions, SerialPortOptions} from "../../../src/adapter/tstype";
52
+ import type {Backup} from "../../../src/models/backup";
53
+ import type {UnifiedBackupStorage} from "../../../src/models/backup-storage-unified";
54
+ import {logger} from "../../../src/utils/logger";
55
+ import * as ZSpec from "../../../src/zspec";
56
+ import type {Eui64, NodeId, PanId} from "../../../src/zspec/tstypes";
57
+ import * as Zcl from "../../../src/zspec/zcl";
58
+ import * as Zdo from "../../../src/zspec/zdo";
59
+ import type * as ZdoTypes from "../../../src/zspec/zdo/definition/tstypes";
60
+
61
+ // https://github.com/jestjs/jest/issues/6028#issuecomment-567669082
62
+ function defuseRejection<T>(promise: Promise<T>) {
63
+ promise.catch(() => {});
64
+
65
+ return promise;
66
+ }
67
+
68
+ function deepClone<T>(obj: T): T {
69
+ return JSON.parse(JSON.stringify(obj));
70
+ }
71
+
72
+ function reverseApsFrame(apsFrame: EmberApsFrame): EmberApsFrame {
73
+ return Object.assign({}, apsFrame, {sourceEndpoint: apsFrame.destinationEndpoint, destinationEndpoint: apsFrame.sourceEndpoint});
74
+ }
75
+
76
+ async function flushPromises(): Promise<void> {
77
+ const {setImmediate} = await vi.importActual<typeof import("node:timers")>("node:timers");
78
+ return new Promise(setImmediate);
79
+ }
80
+
81
+ const TEMP_PATH = path.resolve("temp");
82
+ const STACK_CONFIG_PATH = path.join(TEMP_PATH, "stack_config.json");
83
+ const DEFAULT_NETWORK_OPTIONS: Readonly<NetworkOptions> = {
84
+ panID: 24404,
85
+ extendedPanID: [118, 185, 136, 236, 199, 244, 246, 85],
86
+ channelList: [20],
87
+ networkKey: [72, 97, 39, 230, 92, 72, 101, 148, 64, 225, 250, 214, 195, 31, 105, 71],
88
+ networkKeyDistribute: false,
89
+ };
90
+ const DEFAULT_SERIAL_PORT_OPTIONS: Readonly<SerialPortOptions> = {
91
+ baudRate: 115200,
92
+ rtscts: false,
93
+ path: "MOCK",
94
+ adapter: "ember",
95
+ };
96
+ const DEFAULT_ADAPTER_OPTIONS: Readonly<AdapterOptions> = {
97
+ concurrent: 16,
98
+ disableLED: false,
99
+ };
100
+ const DEFAULT_BACKUP: Readonly<UnifiedBackupStorage> = {
101
+ metadata: {
102
+ format: "zigpy/open-coordinator-backup",
103
+ version: 1,
104
+ source: "zigbee-herdsman@0.55.0",
105
+ internal: {
106
+ date: "2024-07-19T15:57:15.163Z",
107
+ ezspVersion: 13,
108
+ },
109
+ },
110
+ stack_specific: {
111
+ ezsp: {
112
+ hashed_tclk: "da85e5bac80c8a958b14d44f14c2ba16",
113
+ },
114
+ },
115
+ coordinator_ieee: "1122334455667788",
116
+ pan_id: "5f54",
117
+ extended_pan_id: "76b988ecc7f4f655",
118
+ nwk_update_id: 0,
119
+ security_level: 5,
120
+ channel: 20,
121
+ channel_mask: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
122
+ network_key: {
123
+ key: "486127e65c48659440e1fad6c31f6947",
124
+ sequence_number: 0,
125
+ frame_counter: 16434,
126
+ },
127
+ devices: [],
128
+ };
129
+ const DEFAULT_COORDINATOR_IEEE: Eui64 = ZSpec.Utils.eui64LEBufferToHex(Buffer.from(DEFAULT_BACKUP.coordinator_ieee, "hex"));
130
+ const DEFAULT_ADAPTER_NETWORK_PARAMETERS: EmberNetworkParameters = {
131
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
132
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
133
+ radioTxPower: 5,
134
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
135
+ joinMethod: 0,
136
+ nwkManagerId: 0,
137
+ nwkUpdateId: 0,
138
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
139
+ };
140
+
141
+ let mockManufCode = Zcl.ManufacturerCode.SILICON_LABORATORIES;
142
+ let mockAPSSequence = -1; // start at 0
143
+ let mockMessageTag = -1; // start at 0
144
+ let mockEzspEmitter = new EventEmitter<EmberEzspEventMap>();
145
+ const mockEzspRemoveAllListeners = vi.fn().mockImplementation((e) => {
146
+ mockEzspEmitter.removeAllListeners(e);
147
+ });
148
+ const mockEzspOn = vi.fn().mockImplementation((e, l) => {
149
+ mockEzspEmitter.on(e, l);
150
+ });
151
+ const mockEzspOnce = vi.fn().mockImplementation((e, l) => {
152
+ mockEzspEmitter.once(e, l);
153
+ });
154
+ const mockEzspStart = vi.fn().mockResolvedValue(EzspStatus.SUCCESS);
155
+ const mockEzspStop = vi.fn();
156
+
157
+ const mockEzspSend = vi.fn().mockResolvedValue([SLStatus.OK, ++mockMessageTag]);
158
+ const mockEzspSetMulticastTableEntry = vi.fn().mockResolvedValue(SLStatus.OK);
159
+ const mockEzspSetManufacturerCode = vi.fn().mockImplementation((code) => {
160
+ mockManufCode = code;
161
+ });
162
+ const mockEzspReadAndClearCounters = vi.fn().mockResolvedValue([1, 2, 3, 4]); // not matching EmberCounterType, but doesn't matter here
163
+ const mockEzspGetNetworkParameters = vi
164
+ .fn()
165
+ .mockResolvedValue([SLStatus.OK, EmberNodeType.COORDINATOR, deepClone(DEFAULT_ADAPTER_NETWORK_PARAMETERS)]);
166
+ const mockEzspNetworkState = vi.fn().mockResolvedValue(EmberNetworkStatus.JOINED_NETWORK);
167
+ const mockEzspGetEui64 = vi.fn().mockResolvedValue(DEFAULT_COORDINATOR_IEEE);
168
+ const mockEzspSetConcentrator = vi.fn().mockResolvedValue(SLStatus.OK);
169
+ const mockEzspSetSourceRouteDiscoveryMode = vi.fn().mockResolvedValue(1240 /* ms */);
170
+ const mockEzspSetRadioIeee802154CcaMode = vi.fn().mockResolvedValue(SLStatus.OK);
171
+ // not OK by default since used to detected unreged EP
172
+ const mockEzspGetEndpointFlags = vi.fn().mockResolvedValue([SLStatus.NOT_FOUND, EzspEndpointFlag.DISABLED]);
173
+ const mockEzspAddEndpoint = vi.fn().mockResolvedValue(SLStatus.OK);
174
+ const mockEzspNetworkInit = vi.fn().mockImplementation((_networkInitStruct: EmberNetworkInitStruct) => {
175
+ setTimeout(async () => {
176
+ mockEzspEmitter.emit("stackStatus", SLStatus.NETWORK_UP);
177
+ await flushPromises();
178
+ }, 300);
179
+
180
+ return SLStatus.OK;
181
+ });
182
+ const mockEzspExportKey = vi.fn().mockImplementation((context: SecManContext) => {
183
+ switch (context.coreKeyType) {
184
+ case SecManKeyType.NETWORK: {
185
+ return [SLStatus.OK, {contents: Buffer.from(DEFAULT_BACKUP.network_key.key, "hex")} as SecManKey];
186
+ }
187
+ case SecManKeyType.TC_LINK: {
188
+ return [SLStatus.OK, {contents: Buffer.from(DEFAULT_BACKUP.stack_specific!.ezsp!.hashed_tclk!, "hex")} as SecManKey];
189
+ }
190
+ }
191
+ });
192
+ const mockEzspLeaveNetwork = vi.fn().mockImplementation(() => {
193
+ setTimeout(async () => {
194
+ mockEzspEmitter.emit("stackStatus", SLStatus.NETWORK_DOWN);
195
+ await flushPromises();
196
+ }, 300);
197
+
198
+ return SLStatus.OK;
199
+ });
200
+ const mockEzspSetInitialSecurityState = vi.fn().mockResolvedValue(SLStatus.OK);
201
+ const mockEzspSetExtendedSecurityBitmask = vi.fn().mockResolvedValue(SLStatus.OK);
202
+ const mockEzspClearKeyTable = vi.fn().mockResolvedValue(SLStatus.OK);
203
+ const mockEzspFormNetwork = vi.fn().mockImplementation((_parameters: EmberNetworkParameters) => {
204
+ setTimeout(async () => {
205
+ mockEzspEmitter.emit("stackStatus", SLStatus.NETWORK_UP);
206
+ await flushPromises();
207
+ }, 300);
208
+
209
+ return SLStatus.OK;
210
+ });
211
+ const mockEzspStartWritingStackTokens = vi.fn().mockResolvedValue(SLStatus.OK);
212
+ const mockEzspGetConfigurationValue = vi.fn().mockImplementation((config: EzspConfigId) => {
213
+ switch (config) {
214
+ case EzspConfigId.KEY_TABLE_SIZE: {
215
+ return [SLStatus.OK, 0];
216
+ }
217
+ }
218
+ });
219
+ const mockEzspExportLinkKeyByIndex = vi.fn();
220
+ const mockEzspEraseKeyTableEntry = vi.fn().mockResolvedValue(SLStatus.OK);
221
+ const mockEzspImportLinkKey = vi.fn().mockResolvedValue(SLStatus.OK);
222
+ const mockEzspBroadcastNextNetworkKey = vi.fn().mockResolvedValue(SLStatus.OK);
223
+ const mockEzspBroadcastNetworkKeySwitch = vi.fn().mockResolvedValue(SLStatus.OK);
224
+ const mockEzspStartScan = vi.fn().mockResolvedValue(SLStatus.OK);
225
+ const mockEzspVersion = vi.fn().mockImplementation((version: number) => [version, EZSP_STACK_TYPE_MESH, 0]);
226
+ const mockEzspSetProtocolVersion = vi.fn();
227
+ const mockEzspGetVersionStruct = vi.fn().mockResolvedValue([
228
+ SLStatus.OK,
229
+ {
230
+ build: 135,
231
+ major: 8,
232
+ minor: 0,
233
+ patch: 0,
234
+ special: 0,
235
+ type: EmberVersionType.GA,
236
+ } as EmberVersion,
237
+ ]);
238
+ const mockEzspSetConfigurationValue = vi.fn().mockResolvedValue(SLStatus.OK);
239
+ const mockEzspSetValue = vi.fn().mockResolvedValue(SLStatus.OK);
240
+ const mockEzspSetPolicy = vi.fn().mockResolvedValue(SLStatus.OK);
241
+ const mockEzspPermitJoining = vi.fn().mockImplementation((duration: number) => {
242
+ setTimeout(async () => {
243
+ mockEzspEmitter.emit("stackStatus", duration > 0 ? SLStatus.ZIGBEE_NETWORK_OPENED : SLStatus.ZIGBEE_NETWORK_CLOSED);
244
+ await flushPromises();
245
+ }, 300);
246
+
247
+ return SLStatus.OK;
248
+ });
249
+ const mockEzspSendBroadcast = vi.fn().mockResolvedValue([SLStatus.OK, ++mockAPSSequence]);
250
+ const mockEzspSendUnicast = vi.fn().mockResolvedValue([SLStatus.OK, ++mockAPSSequence]);
251
+ const mockEzspGetNetworkKeyInfo = vi.fn().mockResolvedValue([
252
+ SLStatus.OK,
253
+ {
254
+ networkKeySet: true,
255
+ alternateNetworkKeySet: false,
256
+ networkKeySequenceNumber: DEFAULT_BACKUP.network_key.sequence_number,
257
+ altNetworkKeySequenceNumber: 0,
258
+ networkKeyFrameCounter: DEFAULT_BACKUP.network_key.frame_counter,
259
+ } as SecManNetworkKeyInfo,
260
+ ]);
261
+ const mockEzspGetApsKeyInfo = vi.fn().mockResolvedValue([
262
+ SLStatus.OK,
263
+ {
264
+ bitmask: EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
265
+ outgoingFrameCounter: 456,
266
+ incomingFrameCounter: 0,
267
+ ttlInSeconds: 0,
268
+ } as SecManAPSKeyMetadata,
269
+ ]);
270
+ const mockEzspSetRadioPower = vi.fn().mockResolvedValue(SLStatus.OK);
271
+ const mockEzspImportTransientKey = vi.fn().mockResolvedValue(SLStatus.OK);
272
+ const mockEzspClearTransientLinkKeys = vi.fn().mockResolvedValue(SLStatus.OK);
273
+ const mockEzspSetLogicalAndRadioChannel = vi.fn().mockResolvedValue(SLStatus.OK);
274
+ const mockEzspSendRawMessage = vi.fn().mockResolvedValue(SLStatus.OK);
275
+ const mockEzspSetNWKFrameCounter = vi.fn().mockResolvedValue(SLStatus.OK);
276
+ const mockEzspSetAPSFrameCounter = vi.fn().mockResolvedValue(SLStatus.OK);
277
+
278
+ vi.mock("../../../src/adapter/ember/uart/ash");
279
+
280
+ vi.mock("../../../src/adapter/ember/ezsp/ezsp", async (importOriginal) => ({
281
+ ...(await importOriginal()),
282
+ Ezsp: vi.fn(() => ({
283
+ removeAllListeners: mockEzspRemoveAllListeners,
284
+ on: mockEzspOn,
285
+ once: mockEzspOnce,
286
+
287
+ // only functions called from adapter
288
+ ash: {readAndClearCounters: vi.fn().mockReturnValue([9, 8, 7])},
289
+
290
+ start: mockEzspStart,
291
+ stop: mockEzspStop,
292
+ send: mockEzspSend,
293
+ ezspSetMulticastTableEntry: mockEzspSetMulticastTableEntry,
294
+ ezspSetManufacturerCode: mockEzspSetManufacturerCode,
295
+ ezspReadAndClearCounters: mockEzspReadAndClearCounters,
296
+ ezspGetNetworkParameters: mockEzspGetNetworkParameters,
297
+ ezspNetworkState: mockEzspNetworkState,
298
+ ezspGetEui64: mockEzspGetEui64,
299
+ ezspSetConcentrator: mockEzspSetConcentrator,
300
+ ezspSetSourceRouteDiscoveryMode: mockEzspSetSourceRouteDiscoveryMode,
301
+ ezspSetRadioIeee802154CcaMode: mockEzspSetRadioIeee802154CcaMode,
302
+ ezspGetEndpointFlags: mockEzspGetEndpointFlags,
303
+ ezspAddEndpoint: mockEzspAddEndpoint,
304
+ ezspNetworkInit: mockEzspNetworkInit,
305
+ ezspExportKey: mockEzspExportKey,
306
+ ezspLeaveNetwork: mockEzspLeaveNetwork,
307
+ ezspSetInitialSecurityState: mockEzspSetInitialSecurityState,
308
+ ezspSetExtendedSecurityBitmask: mockEzspSetExtendedSecurityBitmask,
309
+ ezspClearKeyTable: mockEzspClearKeyTable,
310
+ ezspFormNetwork: mockEzspFormNetwork,
311
+ ezspStartWritingStackTokens: mockEzspStartWritingStackTokens,
312
+ ezspGetConfigurationValue: mockEzspGetConfigurationValue,
313
+ ezspExportLinkKeyByIndex: mockEzspExportLinkKeyByIndex,
314
+ ezspEraseKeyTableEntry: mockEzspEraseKeyTableEntry,
315
+ ezspImportLinkKey: mockEzspImportLinkKey,
316
+ ezspBroadcastNextNetworkKey: mockEzspBroadcastNextNetworkKey,
317
+ ezspBroadcastNetworkKeySwitch: mockEzspBroadcastNetworkKeySwitch,
318
+ ezspStartScan: mockEzspStartScan,
319
+ ezspVersion: mockEzspVersion,
320
+ setProtocolVersion: mockEzspSetProtocolVersion,
321
+ ezspGetVersionStruct: mockEzspGetVersionStruct,
322
+ ezspSetConfigurationValue: mockEzspSetConfigurationValue,
323
+ ezspSetValue: mockEzspSetValue,
324
+ ezspSetPolicy: mockEzspSetPolicy,
325
+ ezspPermitJoining: mockEzspPermitJoining,
326
+ ezspSendBroadcast: mockEzspSendBroadcast,
327
+ ezspSendUnicast: mockEzspSendUnicast,
328
+ ezspGetNetworkKeyInfo: mockEzspGetNetworkKeyInfo,
329
+ ezspGetApsKeyInfo: mockEzspGetApsKeyInfo,
330
+ ezspSetRadioPower: mockEzspSetRadioPower,
331
+ ezspImportTransientKey: mockEzspImportTransientKey,
332
+ ezspClearTransientLinkKeys: mockEzspClearTransientLinkKeys,
333
+ ezspSetLogicalAndRadioChannel: mockEzspSetLogicalAndRadioChannel,
334
+ ezspSendRawMessage: mockEzspSendRawMessage,
335
+ ezspSetNWKFrameCounter: mockEzspSetNWKFrameCounter,
336
+ ezspSetAPSFrameCounter: mockEzspSetAPSFrameCounter,
337
+ })),
338
+ }));
339
+
340
+ const ezspMocks = [
341
+ mockEzspRemoveAllListeners,
342
+ mockEzspOn,
343
+ mockEzspOnce,
344
+ mockEzspStart,
345
+ mockEzspStop,
346
+ mockEzspSend,
347
+ mockEzspSetMulticastTableEntry,
348
+ mockEzspSetManufacturerCode,
349
+ mockEzspReadAndClearCounters,
350
+ mockEzspGetNetworkParameters,
351
+ mockEzspNetworkState,
352
+ mockEzspGetEui64,
353
+ mockEzspSetConcentrator,
354
+ mockEzspSetSourceRouteDiscoveryMode,
355
+ mockEzspSetRadioIeee802154CcaMode,
356
+ mockEzspGetEndpointFlags,
357
+ mockEzspAddEndpoint,
358
+ mockEzspNetworkInit,
359
+ mockEzspExportKey,
360
+ mockEzspLeaveNetwork,
361
+ mockEzspSetInitialSecurityState,
362
+ mockEzspSetExtendedSecurityBitmask,
363
+ mockEzspClearKeyTable,
364
+ mockEzspFormNetwork,
365
+ mockEzspStartWritingStackTokens,
366
+ mockEzspGetConfigurationValue,
367
+ mockEzspExportLinkKeyByIndex,
368
+ mockEzspEraseKeyTableEntry,
369
+ mockEzspImportLinkKey,
370
+ mockEzspBroadcastNextNetworkKey,
371
+ mockEzspBroadcastNetworkKeySwitch,
372
+ mockEzspStartScan,
373
+ mockEzspVersion,
374
+ mockEzspSetProtocolVersion,
375
+ mockEzspGetVersionStruct,
376
+ mockEzspSetConfigurationValue,
377
+ mockEzspSetValue,
378
+ mockEzspSetPolicy,
379
+ mockEzspPermitJoining,
380
+ mockEzspSendBroadcast,
381
+ mockEzspSendUnicast,
382
+ mockEzspGetNetworkKeyInfo,
383
+ mockEzspGetApsKeyInfo,
384
+ mockEzspSetRadioPower,
385
+ mockEzspImportTransientKey,
386
+ mockEzspClearTransientLinkKeys,
387
+ mockEzspSetLogicalAndRadioChannel,
388
+ mockEzspSendRawMessage,
389
+ mockEzspSetNWKFrameCounter,
390
+ mockEzspSetAPSFrameCounter,
391
+ ];
392
+
393
+ describe("Ember Adapter Layer", () => {
394
+ let adapter: EmberAdapter;
395
+ let backupPath: string;
396
+ const loggerSpies = {
397
+ debug: vi.spyOn(logger, "debug"),
398
+ info: vi.spyOn(logger, "info"),
399
+ warning: vi.spyOn(logger, "warning"),
400
+ error: vi.spyOn(logger, "error"),
401
+ };
402
+
403
+ const deleteCoordinatorBackup = () => {
404
+ if (existsSync(backupPath)) {
405
+ unlinkSync(backupPath);
406
+ }
407
+ };
408
+
409
+ const deleteStackConfig = () => {
410
+ if (existsSync(STACK_CONFIG_PATH)) {
411
+ unlinkSync(STACK_CONFIG_PATH);
412
+ }
413
+ };
414
+
415
+ const takeResetCodePath = () => {
416
+ deleteCoordinatorBackup();
417
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([
418
+ SLStatus.OK,
419
+ EmberNodeType.COORDINATOR,
420
+ {
421
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
422
+ panId: 1234,
423
+ radioTxPower: 5,
424
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
425
+ joinMethod: 0,
426
+ nwkManagerId: 0,
427
+ nwkUpdateId: 0,
428
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
429
+ } as EmberNetworkParameters,
430
+ ]);
431
+ };
432
+
433
+ const takeRestoredCodePath = () => {
434
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([
435
+ SLStatus.OK,
436
+ EmberNodeType.COORDINATOR,
437
+ {
438
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
439
+ panId: 1234,
440
+ radioTxPower: 5,
441
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
442
+ joinMethod: 0,
443
+ nwkManagerId: 0,
444
+ nwkUpdateId: 0,
445
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
446
+ } as EmberNetworkParameters,
447
+ ]);
448
+ };
449
+
450
+ const clearMocks = () => {
451
+ for (const mock of ezspMocks) {
452
+ mock.mockClear();
453
+ }
454
+
455
+ loggerSpies.debug.mockClear();
456
+ loggerSpies.info.mockClear();
457
+ loggerSpies.warning.mockClear();
458
+ loggerSpies.error.mockClear();
459
+ };
460
+
461
+ beforeAll(() => {
462
+ if (!existsSync(TEMP_PATH)) {
463
+ mkdirSync(TEMP_PATH);
464
+ } else {
465
+ // just in case, remove previous remnants
466
+ deleteCoordinatorBackup();
467
+ deleteStackConfig();
468
+ }
469
+ });
470
+
471
+ afterAll(() => {
472
+ deleteCoordinatorBackup();
473
+ deleteStackConfig();
474
+ });
475
+
476
+ beforeEach(() => {
477
+ vi.useFakeTimers();
478
+
479
+ backupPath = path.join(TEMP_PATH, "ember_coordinator_backup.json");
480
+
481
+ writeFileSync(backupPath, JSON.stringify(DEFAULT_BACKUP, undefined, 2));
482
+
483
+ mockManufCode = Zcl.ManufacturerCode.SILICON_LABORATORIES;
484
+ mockAPSSequence = -1;
485
+ mockMessageTag = -1;
486
+ // make sure emitter is reset too
487
+ mockEzspEmitter = new EventEmitter();
488
+
489
+ clearMocks();
490
+ });
491
+
492
+ afterEach(() => {
493
+ vi.useRealTimers();
494
+ });
495
+
496
+ it("Creates default instance", () => {
497
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
498
+
499
+ expect(adapter).toBeInstanceOf(EmberAdapter);
500
+ expect(adapter.stackConfig).toStrictEqual(DEFAULT_STACK_CONFIG);
501
+ });
502
+
503
+ it("Loads custom stack config", () => {
504
+ const config = {
505
+ CONCENTRATOR_RAM_TYPE: "low",
506
+ CONCENTRATOR_MIN_TIME: 1,
507
+ CONCENTRATOR_MAX_TIME: 31,
508
+ CONCENTRATOR_ROUTE_ERROR_THRESHOLD: 5,
509
+ CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD: 2,
510
+ CONCENTRATOR_MAX_HOPS: 5,
511
+ MAX_END_DEVICE_CHILDREN: 16,
512
+ TRANSIENT_DEVICE_TIMEOUT: 1000,
513
+ END_DEVICE_POLL_TIMEOUT: 12,
514
+ TRANSIENT_KEY_TIMEOUT_S: 500,
515
+ CCA_MODE: "SIGNAL_AND_RSSI",
516
+ };
517
+
518
+ writeFileSync(STACK_CONFIG_PATH, JSON.stringify(config, undefined, 2));
519
+
520
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
521
+
522
+ expect(adapter.stackConfig).toStrictEqual(config);
523
+
524
+ // cleanup
525
+ unlinkSync(STACK_CONFIG_PATH);
526
+ });
527
+
528
+ it("Loads only valid custom stack config", () => {
529
+ const config = {
530
+ CONCENTRATOR_RAM_TYPE: "bad",
531
+ CONCENTRATOR_MIN_TIME: -1,
532
+ CONCENTRATOR_MAX_TIME: 15,
533
+ CONCENTRATOR_ROUTE_ERROR_THRESHOLD: 500,
534
+ CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD: 200,
535
+ CONCENTRATOR_MAX_HOPS: 35,
536
+ MAX_END_DEVICE_CHILDREN: 65,
537
+ TRANSIENT_DEVICE_TIMEOUT: 65536,
538
+ END_DEVICE_POLL_TIMEOUT: 15,
539
+ TRANSIENT_KEY_TIMEOUT_S: 65536,
540
+ CCA_MODE: "abcd",
541
+ };
542
+
543
+ writeFileSync(STACK_CONFIG_PATH, JSON.stringify(config, undefined, 2));
544
+
545
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
546
+
547
+ expect(adapter.stackConfig).toStrictEqual(DEFAULT_STACK_CONFIG);
548
+
549
+ // cleanup
550
+ unlinkSync(STACK_CONFIG_PATH);
551
+ });
552
+
553
+ it("Loads only valid custom stack config - null CCA_MODE", () => {
554
+ const config = {
555
+ CCA_MODE: null,
556
+ };
557
+
558
+ writeFileSync(STACK_CONFIG_PATH, JSON.stringify(config, undefined, 2));
559
+
560
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
561
+
562
+ expect(adapter.stackConfig).toStrictEqual(DEFAULT_STACK_CONFIG);
563
+
564
+ // cleanup
565
+ unlinkSync(STACK_CONFIG_PATH);
566
+ });
567
+
568
+ it("Uses default concurrency for queue if not supplied/valid", () => {
569
+ adapter = new EmberAdapter(
570
+ DEFAULT_NETWORK_OPTIONS,
571
+ DEFAULT_SERIAL_PORT_OPTIONS,
572
+ backupPath,
573
+ Object.assign({}, DEFAULT_ADAPTER_OPTIONS, {concurrent: undefined}),
574
+ );
575
+ });
576
+
577
+ it("Starts with resumed when everything matches", async () => {
578
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
579
+ const result = adapter.start();
580
+
581
+ await vi.advanceTimersByTimeAsync(5000);
582
+ await expect(result).resolves.toStrictEqual("resumed");
583
+ expect(mockEzspSetProtocolVersion).toHaveBeenCalledWith(EZSP_PROTOCOL_VERSION);
584
+ expect(
585
+ // @ts-expect-error private
586
+ adapter.networkCache,
587
+ ).toStrictEqual({
588
+ eui64: DEFAULT_COORDINATOR_IEEE,
589
+ parameters: {
590
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
591
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
592
+ radioTxPower: 5,
593
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
594
+ joinMethod: 0,
595
+ nwkManagerId: 0,
596
+ nwkUpdateId: 0,
597
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
598
+ } as EmberNetworkParameters,
599
+ } as NetworkCache);
600
+ });
601
+
602
+ it("Starts with custom stack config", async () => {
603
+ const config = {
604
+ CONCENTRATOR_RAM_TYPE: "low",
605
+ CONCENTRATOR_MIN_TIME: 1,
606
+ CONCENTRATOR_MAX_TIME: 31,
607
+ CONCENTRATOR_ROUTE_ERROR_THRESHOLD: 5,
608
+ CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD: 2,
609
+ CONCENTRATOR_MAX_HOPS: 5,
610
+ MAX_END_DEVICE_CHILDREN: 16,
611
+ TRANSIENT_DEVICE_TIMEOUT: 1000,
612
+ END_DEVICE_POLL_TIMEOUT: 12,
613
+ TRANSIENT_KEY_TIMEOUT_S: 500,
614
+ CCA_MODE: "SIGNAL_AND_RSSI",
615
+ };
616
+
617
+ writeFileSync(STACK_CONFIG_PATH, JSON.stringify(config, undefined, 2));
618
+
619
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
620
+ const result = adapter.start();
621
+
622
+ await vi.advanceTimersByTimeAsync(5000);
623
+ await expect(result).resolves.toStrictEqual("resumed");
624
+ expect(mockEzspSetValue).toHaveBeenCalledWith(EzspValueId.TRANSIENT_DEVICE_TIMEOUT, 2, lowHighBytes(config.TRANSIENT_DEVICE_TIMEOUT));
625
+ expect(mockEzspSetConfigurationValue).toHaveBeenCalledWith(EzspConfigId.MAX_END_DEVICE_CHILDREN, config.MAX_END_DEVICE_CHILDREN);
626
+ expect(mockEzspSetConfigurationValue).toHaveBeenCalledWith(EzspConfigId.END_DEVICE_POLL_TIMEOUT, config.END_DEVICE_POLL_TIMEOUT);
627
+ expect(mockEzspSetConfigurationValue).toHaveBeenCalledWith(EzspConfigId.TRANSIENT_KEY_TIMEOUT_S, config.TRANSIENT_KEY_TIMEOUT_S);
628
+ expect(mockEzspSetConcentrator).toHaveBeenCalledWith(
629
+ true,
630
+ EMBER_LOW_RAM_CONCENTRATOR,
631
+ config.CONCENTRATOR_MIN_TIME,
632
+ config.CONCENTRATOR_MAX_TIME,
633
+ config.CONCENTRATOR_ROUTE_ERROR_THRESHOLD,
634
+ config.CONCENTRATOR_DELIVERY_FAILURE_THRESHOLD,
635
+ config.CONCENTRATOR_MAX_HOPS,
636
+ );
637
+ expect(mockEzspSetRadioIeee802154CcaMode).toHaveBeenCalledWith(IEEE802154CcaMode.SIGNAL_AND_RSSI);
638
+
639
+ // cleanup
640
+ unlinkSync(STACK_CONFIG_PATH);
641
+ });
642
+
643
+ it("Starts with custom stack config invalid CCA_MODE", async () => {
644
+ const config = {
645
+ CCA_MODE: "abcd",
646
+ };
647
+
648
+ writeFileSync(STACK_CONFIG_PATH, JSON.stringify(config, undefined, 2));
649
+
650
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
651
+ const result = adapter.start();
652
+
653
+ await vi.advanceTimersByTimeAsync(5000);
654
+ await expect(result).resolves.toStrictEqual("resumed");
655
+ expect(mockEzspSetRadioIeee802154CcaMode).toHaveBeenCalledTimes(0);
656
+
657
+ // cleanup
658
+ unlinkSync(STACK_CONFIG_PATH);
659
+ });
660
+
661
+ it("Starts with restored when no network in adapter", async () => {
662
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
663
+ const expectedNetParams: EmberNetworkParameters = {
664
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
665
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
666
+ radioTxPower: 5,
667
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
668
+ joinMethod: 0,
669
+ nwkManagerId: 0,
670
+ nwkUpdateId: 0,
671
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
672
+ };
673
+
674
+ mockEzspNetworkInit.mockResolvedValueOnce(SLStatus.NOT_JOINED);
675
+
676
+ const result = adapter.start();
677
+
678
+ await vi.advanceTimersByTimeAsync(5000);
679
+ expect(mockEzspSetNWKFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.network_key.frame_counter);
680
+ // expect(mockEzspSetAPSFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.???.???);
681
+ expect(mockEzspFormNetwork).toHaveBeenCalledWith(expectedNetParams);
682
+ await expect(result).resolves.toStrictEqual("restored");
683
+ });
684
+
685
+ it("Starts with restored when network param mismatch but backup available", async () => {
686
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
687
+ const expectedNetParams: EmberNetworkParameters = {
688
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
689
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
690
+ radioTxPower: 5,
691
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
692
+ joinMethod: 0,
693
+ nwkManagerId: 0,
694
+ nwkUpdateId: 0,
695
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
696
+ };
697
+
698
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([
699
+ SLStatus.OK,
700
+ EmberNodeType.COORDINATOR,
701
+ {
702
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
703
+ panId: 1234,
704
+ radioTxPower: 5,
705
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
706
+ joinMethod: 0,
707
+ nwkManagerId: 0,
708
+ nwkUpdateId: 0,
709
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
710
+ } as EmberNetworkParameters,
711
+ ]);
712
+
713
+ const result = adapter.start();
714
+
715
+ await vi.advanceTimersByTimeAsync(5000);
716
+ expect(mockEzspSetNWKFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.network_key.frame_counter);
717
+ // expect(mockEzspSetAPSFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.???.???);
718
+ expect(mockEzspFormNetwork).toHaveBeenCalledWith(expectedNetParams);
719
+ await expect(result).resolves.toStrictEqual("restored");
720
+ });
721
+
722
+ it("Starts with restored when network key mismatch but backup available", async () => {
723
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
724
+ const expectedNetParams: EmberNetworkParameters = {
725
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
726
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
727
+ radioTxPower: 5,
728
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
729
+ joinMethod: 0,
730
+ nwkManagerId: 0,
731
+ nwkUpdateId: 0,
732
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
733
+ };
734
+
735
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([SLStatus.OK, EmberNodeType.COORDINATOR, expectedNetParams]);
736
+
737
+ const contents = Buffer.from(DEFAULT_BACKUP.network_key.key, "hex").fill(0xff);
738
+
739
+ mockEzspExportKey.mockResolvedValueOnce([SLStatus.OK, {contents} as SecManKey]);
740
+
741
+ const result = adapter.start();
742
+
743
+ await vi.advanceTimersByTimeAsync(5000);
744
+ await expect(result).resolves.toStrictEqual("restored");
745
+ expect(mockEzspSetNWKFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.network_key.frame_counter);
746
+ // expect(mockEzspSetAPSFrameCounter).toHaveBeenCalledWith(DEFAULT_BACKUP.???.???);
747
+ expect(mockEzspFormNetwork).toHaveBeenCalledWith(expectedNetParams);
748
+ });
749
+
750
+ it("Starts with reset when networks mismatch but no backup available", async () => {
751
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
752
+
753
+ deleteCoordinatorBackup();
754
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([
755
+ SLStatus.OK,
756
+ EmberNodeType.COORDINATOR,
757
+ {
758
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
759
+ panId: 1234,
760
+ radioTxPower: 5,
761
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
762
+ joinMethod: 0,
763
+ nwkManagerId: 0,
764
+ nwkUpdateId: 0,
765
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
766
+ } as EmberNetworkParameters,
767
+ ]);
768
+
769
+ const result = adapter.start();
770
+
771
+ await vi.advanceTimersByTimeAsync(5000);
772
+ await expect(result).resolves.toStrictEqual("reset");
773
+ });
774
+
775
+ it("Starts with reset when backup/config mismatch", async () => {
776
+ adapter = new EmberAdapter(
777
+ Object.assign({}, DEFAULT_NETWORK_OPTIONS, {panID: 1234}),
778
+ DEFAULT_SERIAL_PORT_OPTIONS,
779
+ backupPath,
780
+ DEFAULT_ADAPTER_OPTIONS,
781
+ );
782
+
783
+ const result = adapter.start();
784
+
785
+ await vi.advanceTimersByTimeAsync(5000);
786
+ await expect(result).resolves.toStrictEqual("reset");
787
+ expect(mockEzspSetNWKFrameCounter).toHaveBeenCalledTimes(0);
788
+ // expect(mockEzspSetAPSFrameCounter).toHaveBeenCalledTimes(0);
789
+ expect(mockEzspFormNetwork).toHaveBeenCalledWith({
790
+ panId: 1234,
791
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
792
+ radioTxPower: 5, // default when setting `transmitPower` is null/zero
793
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
794
+ joinMethod: EmberJoinMethod.MAC_ASSOCIATION,
795
+ nwkManagerId: ZSpec.COORDINATOR_ADDRESS,
796
+ nwkUpdateId: 0,
797
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
798
+ } as EmberNetworkParameters);
799
+ });
800
+
801
+ it("Starts with reset and forms with given transmit power", async () => {
802
+ adapter = new EmberAdapter(
803
+ Object.assign({}, DEFAULT_NETWORK_OPTIONS, {panID: 1234}),
804
+ DEFAULT_SERIAL_PORT_OPTIONS,
805
+ backupPath,
806
+ Object.assign({}, DEFAULT_ADAPTER_OPTIONS, {transmitPower: 10}),
807
+ );
808
+
809
+ const result = adapter.start();
810
+
811
+ await vi.advanceTimersByTimeAsync(5000);
812
+ await expect(result).resolves.toStrictEqual("reset");
813
+ expect(mockEzspSetNWKFrameCounter).toHaveBeenCalledTimes(0);
814
+ // expect(mockEzspSetAPSFrameCounter).toHaveBeenCalledTimes(0);
815
+ expect(mockEzspFormNetwork).toHaveBeenCalledWith({
816
+ panId: 1234,
817
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
818
+ radioTxPower: 10,
819
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
820
+ joinMethod: EmberJoinMethod.MAC_ASSOCIATION,
821
+ nwkManagerId: ZSpec.COORDINATOR_ADDRESS,
822
+ nwkUpdateId: 0,
823
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
824
+ } as EmberNetworkParameters);
825
+ });
826
+
827
+ it("Starts with mismatching transmit power", async () => {
828
+ adapter = new EmberAdapter(
829
+ DEFAULT_NETWORK_OPTIONS,
830
+ DEFAULT_SERIAL_PORT_OPTIONS,
831
+ backupPath,
832
+ Object.assign({}, DEFAULT_ADAPTER_OPTIONS, {transmitPower: 10}),
833
+ );
834
+
835
+ const result = adapter.start();
836
+
837
+ await vi.advanceTimersByTimeAsync(5000);
838
+ await expect(result).resolves.toStrictEqual("resumed");
839
+ expect(mockEzspSetRadioPower).toHaveBeenCalledTimes(1);
840
+ expect(mockEzspSetRadioPower).toHaveBeenCalledWith(10);
841
+ });
842
+
843
+ it("Starts with matching transmit power after form", async () => {
844
+ adapter = new EmberAdapter(
845
+ DEFAULT_NETWORK_OPTIONS,
846
+ DEFAULT_SERIAL_PORT_OPTIONS,
847
+ backupPath,
848
+ Object.assign({}, DEFAULT_ADAPTER_OPTIONS, {transmitPower: 10}),
849
+ );
850
+ mockEzspNetworkInit.mockResolvedValueOnce(SLStatus.NOT_JOINED);
851
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([
852
+ SLStatus.OK,
853
+ EmberNodeType.COORDINATOR,
854
+ {
855
+ extendedPanId: DEFAULT_NETWORK_OPTIONS.extendedPanID!,
856
+ panId: DEFAULT_NETWORK_OPTIONS.panID,
857
+ radioTxPower: 10,
858
+ radioChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
859
+ joinMethod: 0,
860
+ nwkManagerId: 0,
861
+ nwkUpdateId: 0,
862
+ channels: ZSpec.ALL_802_15_4_CHANNELS_MASK,
863
+ } as EmberNetworkParameters,
864
+ ]);
865
+
866
+ const result = adapter.start();
867
+
868
+ await vi.advanceTimersByTimeAsync(5000);
869
+ await expect(result).resolves.toStrictEqual("restored");
870
+ expect(mockEzspSetRadioPower).toHaveBeenCalledTimes(0);
871
+ });
872
+
873
+ it("Starts with mismatching transmit power, failure does not present start", async () => {
874
+ adapter = new EmberAdapter(
875
+ DEFAULT_NETWORK_OPTIONS,
876
+ DEFAULT_SERIAL_PORT_OPTIONS,
877
+ backupPath,
878
+ Object.assign({}, DEFAULT_ADAPTER_OPTIONS, {transmitPower: 12}),
879
+ );
880
+ mockEzspSetRadioPower.mockResolvedValueOnce(SLStatus.FAIL);
881
+
882
+ const result = adapter.start();
883
+
884
+ await vi.advanceTimersByTimeAsync(5000);
885
+ await expect(result).resolves.toStrictEqual("resumed");
886
+ expect(mockEzspSetRadioPower).toHaveBeenCalledTimes(1);
887
+ expect(mockEzspSetRadioPower).toHaveBeenCalledWith(12);
888
+ expect(loggerSpies.error).toHaveBeenCalledWith("Failed to set transmit power to 12 status=FAIL.", "zh:ember");
889
+ });
890
+
891
+ it("Fails to start when EZSP layer fails to start", async () => {
892
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
893
+
894
+ mockEzspStart.mockResolvedValueOnce(EzspStatus.HOST_FATAL_ERROR);
895
+
896
+ const result = adapter.start();
897
+
898
+ await expect(result).rejects.toThrow(`Failed to start EZSP layer with status=${EzspStatus[EzspStatus.HOST_FATAL_ERROR]}.`);
899
+ });
900
+
901
+ it.each([
902
+ [
903
+ "if NCP has improper stack type",
904
+ () => {
905
+ mockEzspVersion.mockResolvedValueOnce([14, 1, 123]);
906
+ },
907
+ "Stack type 1 is not expected!",
908
+ ],
909
+ [
910
+ "if NCP version unsupported",
911
+ () => {
912
+ mockEzspVersion.mockResolvedValueOnce([12, EZSP_STACK_TYPE_MESH, 123]);
913
+ },
914
+ `Adapter EZSP protocol version (12) is not supported by Host [${EZSP_MIN_PROTOCOL_VERSION}-${EZSP_PROTOCOL_VERSION}].`,
915
+ ],
916
+ [
917
+ "if NCP has old style version number",
918
+ () => {
919
+ mockEzspGetVersionStruct.mockResolvedValueOnce([SLStatus.INVALID_PARAMETER, 0]);
920
+ },
921
+ "NCP has old-style version number. Not supported.",
922
+ ],
923
+ [
924
+ "if network is not valid by end of init sequence",
925
+ () => {
926
+ mockEzspGetNetworkParameters
927
+ .mockResolvedValueOnce([SLStatus.OK, EmberNodeType.COORDINATOR, deepClone(DEFAULT_ADAPTER_NETWORK_PARAMETERS)])
928
+ .mockResolvedValueOnce([SLStatus.FAIL, 0, {}]);
929
+ },
930
+ "Failed to get network parameters with status=FAIL.",
931
+ ],
932
+ [
933
+ "if could not set concentrator",
934
+ () => {
935
+ mockEzspSetConcentrator.mockResolvedValueOnce(SLStatus.FAIL);
936
+ },
937
+ "[CONCENTRATOR] Failed to set concentrator with status=FAIL.",
938
+ ],
939
+ [
940
+ "if could not add endpoint",
941
+ () => {
942
+ mockEzspAddEndpoint.mockResolvedValueOnce(SLStatus.FAIL);
943
+ },
944
+ `Failed to register endpoint '1' with status=FAIL.`,
945
+ ],
946
+ [
947
+ "if could not set multicast table entry",
948
+ () => {
949
+ mockEzspSetMulticastTableEntry.mockResolvedValueOnce(SLStatus.FAIL);
950
+ },
951
+ `Failed to register group '0' in multicast table with status=FAIL.`,
952
+ ],
953
+ [
954
+ "if could not set TC key request policy",
955
+ () => {
956
+ mockEzspSetPolicy
957
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.BINDING_MODIFICATION_POLICY
958
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY
959
+ .mockResolvedValueOnce(SLStatus.FAIL); // EzspPolicyId.TC_KEY_REQUEST_POLICY
960
+ },
961
+ "[INIT TC] Failed to set EzspPolicyId TC_KEY_REQUEST_POLICY to ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY with status=FAIL.",
962
+ ],
963
+ [
964
+ "if could not set app key request policy",
965
+ () => {
966
+ mockEzspSetPolicy
967
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.BINDING_MODIFICATION_POLICY
968
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY
969
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.TC_KEY_REQUEST_POLICY
970
+ .mockResolvedValueOnce(SLStatus.FAIL); // EzspPolicyId.APP_KEY_REQUEST_POLICY
971
+ },
972
+ "[INIT TC] Failed to set EzspPolicyId APP_KEY_REQUEST_POLICY to DENY_APP_KEY_REQUESTS with status=FAIL.",
973
+ ],
974
+ [
975
+ "if could not set app key request policy",
976
+ () => {
977
+ mockEzspSetPolicy
978
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.BINDING_MODIFICATION_POLICY
979
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY
980
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.TC_KEY_REQUEST_POLICY
981
+ .mockResolvedValueOnce(SLStatus.OK) // EzspPolicyId.APP_KEY_REQUEST_POLICY
982
+ .mockResolvedValueOnce(SLStatus.FAIL); // EzspPolicyId.TRUST_CENTER_POLICY
983
+ },
984
+ "[INIT TC] Failed to set join policy to USE_PRECONFIGURED_KEY with status=FAIL.",
985
+ ],
986
+ [
987
+ "if could not init network",
988
+ () => {
989
+ mockEzspNetworkInit.mockResolvedValueOnce(SLStatus.FAIL);
990
+ },
991
+ "[INIT TC] Failed network init request with status=FAIL.",
992
+ ],
993
+ [
994
+ "if could not export network key",
995
+ () => {
996
+ mockEzspExportKey.mockResolvedValueOnce([SLStatus.FAIL, Buffer.alloc(16)]);
997
+ },
998
+ "[INIT TC] Failed to export Network Key with status=FAIL.",
999
+ ],
1000
+ [
1001
+ "if could not leave network",
1002
+ () => {
1003
+ // force leave code path
1004
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([SLStatus.FAIL, 0, {}]);
1005
+ mockEzspLeaveNetwork.mockResolvedValueOnce(SLStatus.FAIL);
1006
+ },
1007
+ "[INIT TC] Failed leave network request with status=FAIL.",
1008
+ ],
1009
+ [
1010
+ "if form could not set NWK frame counter",
1011
+ () => {
1012
+ takeRestoredCodePath();
1013
+ mockEzspSetNWKFrameCounter.mockResolvedValueOnce(SLStatus.FAIL);
1014
+ },
1015
+ "[INIT FORM] Failed to set NWK frame counter with status=FAIL.",
1016
+ ],
1017
+ // [
1018
+ // 'if form could not set TC APS frame counter',
1019
+ // () => {
1020
+ // takeRestoredCodePath();
1021
+ // mockEzspSetAPSFrameCounter.mockResolvedValueOnce(SLStatus.FAIL);
1022
+ // },
1023
+ // `[INIT FORM] Failed to set TC APS frame counter with status=FAIL.`,
1024
+ // ],
1025
+ [
1026
+ "if form could not set initial security state",
1027
+ () => {
1028
+ takeResetCodePath();
1029
+ mockEzspSetInitialSecurityState.mockResolvedValueOnce(SLStatus.FAIL);
1030
+ },
1031
+ "[INIT FORM] Failed to set initial security state with status=FAIL.",
1032
+ ],
1033
+ [
1034
+ "if form could not set extended security bitmask",
1035
+ () => {
1036
+ takeResetCodePath();
1037
+ mockEzspSetExtendedSecurityBitmask.mockResolvedValueOnce(SLStatus.FAIL);
1038
+ },
1039
+ "[INIT FORM] Failed to set extended security bitmask to 272 with status=FAIL.",
1040
+ ],
1041
+ [
1042
+ "if could not form network",
1043
+ () => {
1044
+ takeResetCodePath();
1045
+ mockEzspFormNetwork.mockResolvedValueOnce(SLStatus.FAIL);
1046
+ },
1047
+ "[INIT FORM] Failed form network request with status=FAIL.",
1048
+ ],
1049
+ [
1050
+ "if backup corrupted",
1051
+ () => {
1052
+ writeFileSync(backupPath, "abcd");
1053
+ },
1054
+ "[BACKUP] Coordinator backup is corrupted.",
1055
+ ],
1056
+ [
1057
+ "if backup unsupported",
1058
+ () => {
1059
+ const customBackup = deepClone(DEFAULT_BACKUP);
1060
+ // @ts-expect-error mock override
1061
+ customBackup.metadata.version = 2;
1062
+
1063
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1064
+ },
1065
+ "[BACKUP] Unsupported open coordinator backup version (version=2).",
1066
+ ],
1067
+ [
1068
+ "if backup not EmberZNet stack specific",
1069
+ () => {
1070
+ const customBackup = deepClone(DEFAULT_BACKUP);
1071
+ customBackup.stack_specific!.ezsp = undefined;
1072
+
1073
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1074
+ },
1075
+ "[BACKUP] Current backup file is not for EmberZNet stack.",
1076
+ ],
1077
+ [
1078
+ "if backup not EmberZNet EZSP version",
1079
+ () => {
1080
+ const customBackup = deepClone(DEFAULT_BACKUP);
1081
+ customBackup.metadata.internal.ezspVersion = undefined;
1082
+
1083
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1084
+ },
1085
+ "[BACKUP] Current backup file is not for EmberZNet stack.",
1086
+ ],
1087
+ [
1088
+ "if backup unknown format",
1089
+ () => {
1090
+ const customBackup = deepClone(DEFAULT_BACKUP);
1091
+ // @ts-expect-error mock override
1092
+ customBackup.metadata.format = "unknown";
1093
+
1094
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1095
+ },
1096
+ "[BACKUP] Unknown backup format.",
1097
+ ],
1098
+ ])("Fails to start %s", async (_reason, setup, error) => {
1099
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1100
+
1101
+ setup();
1102
+
1103
+ const result = defuseRejection(adapter.start());
1104
+
1105
+ await vi.advanceTimersByTimeAsync(5000);
1106
+ await expect(result).rejects.toThrow(error);
1107
+ });
1108
+
1109
+ it("Warns if NCP has non-GA firmware", async () => {
1110
+ const type: EmberVersionType = EmberVersionType.ALPHA_1;
1111
+
1112
+ mockEzspGetVersionStruct.mockResolvedValueOnce([
1113
+ SLStatus.OK,
1114
+ {
1115
+ build: 135,
1116
+ major: 8,
1117
+ minor: 0,
1118
+ patch: 0,
1119
+ special: 0,
1120
+ type,
1121
+ } as EmberVersion,
1122
+ ]);
1123
+
1124
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1125
+
1126
+ const result = adapter.start();
1127
+
1128
+ await vi.advanceTimersByTimeAsync(5000);
1129
+ await expect(result).resolves.toStrictEqual("resumed");
1130
+
1131
+ expect(loggerSpies.warning).toHaveBeenCalledWith(`Adapter is running a non-GA version (${EmberVersionType[type]}).`, "zh:ember");
1132
+ });
1133
+
1134
+ it("Switches EZSP protocol when supported", async () => {
1135
+ mockEzspVersion.mockResolvedValueOnce([EZSP_MIN_PROTOCOL_VERSION, EZSP_STACK_TYPE_MESH, 123]);
1136
+
1137
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1138
+
1139
+ const result = adapter.start();
1140
+
1141
+ await vi.advanceTimersByTimeAsync(5000);
1142
+ await expect(result).resolves.toStrictEqual("resumed");
1143
+ expect(mockEzspVersion).toHaveBeenNthCalledWith(1, EZSP_PROTOCOL_VERSION);
1144
+ expect(mockEzspVersion).toHaveBeenNthCalledWith(2, EZSP_MIN_PROTOCOL_VERSION);
1145
+ expect(mockEzspSetProtocolVersion).toHaveBeenCalledWith(EZSP_MIN_PROTOCOL_VERSION);
1146
+ });
1147
+
1148
+ it("Logs failed set config value on start", async () => {
1149
+ mockEzspSetConfigurationValue.mockResolvedValueOnce(SLStatus.ALLOCATION_FAILED);
1150
+
1151
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1152
+
1153
+ const result = adapter.start();
1154
+
1155
+ await vi.advanceTimersByTimeAsync(5000);
1156
+ await expect(result).resolves.toStrictEqual("resumed");
1157
+
1158
+ expect(loggerSpies.info).toHaveBeenCalledWith(
1159
+ `[EzspConfigId] Failed to SET '${EzspConfigId[EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE]}' TO '2' with status=${SLStatus[SLStatus.ALLOCATION_FAILED]}. Firmware value will be used instead.`,
1160
+ "zh:ember",
1161
+ );
1162
+ });
1163
+
1164
+ it("Starts and skips adding endpoint if already present", async () => {
1165
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1166
+
1167
+ mockEzspGetEndpointFlags
1168
+ .mockResolvedValueOnce([SLStatus.NOT_FOUND, EzspEndpointFlag.DISABLED])
1169
+ .mockResolvedValueOnce([SLStatus.OK, EzspEndpointFlag.ENABLED]); // mock GP already registered
1170
+
1171
+ const result = adapter.start();
1172
+
1173
+ await vi.advanceTimersByTimeAsync(5000);
1174
+ await expect(result).resolves.toStrictEqual("resumed");
1175
+ expect(mockEzspAddEndpoint).toHaveBeenCalledTimes(1);
1176
+ const ep = FIXED_ENDPOINTS[0];
1177
+ expect(mockEzspAddEndpoint).toHaveBeenCalledWith(
1178
+ ep.endpoint,
1179
+ ep.profileId,
1180
+ ep.deviceId,
1181
+ ep.deviceVersion,
1182
+ ep.inClusterList.slice(), // copy
1183
+ ep.outClusterList.slice(), // copy
1184
+ );
1185
+ });
1186
+
1187
+ it("Starts and detects when network key frame counter will soon wrap to 0", async () => {
1188
+ const customBackup = deepClone(DEFAULT_BACKUP);
1189
+ customBackup.network_key.frame_counter = 0xfeeeeeef;
1190
+
1191
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1192
+
1193
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1194
+ const result = adapter.start();
1195
+
1196
+ await vi.advanceTimersByTimeAsync(5000);
1197
+ await expect(result).resolves.toStrictEqual("resumed");
1198
+ expect(logger.warning).toHaveBeenCalledWith(
1199
+ "[INIT TC] Network key frame counter is reaching its limit. A new network key will have to be instaured soon.",
1200
+ "zh:ember",
1201
+ );
1202
+ });
1203
+
1204
+ it("Starts and soft-fails if unable to clear key table", async () => {
1205
+ takeResetCodePath();
1206
+ mockEzspClearKeyTable.mockResolvedValueOnce(SLStatus.FAIL);
1207
+
1208
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1209
+ const result = adapter.start();
1210
+
1211
+ await vi.advanceTimersByTimeAsync(5000);
1212
+ await expect(result).resolves.toStrictEqual("reset");
1213
+ expect(loggerSpies.error).toHaveBeenCalledWith("[INIT FORM] Failed to clear key table with status=FAIL.", "zh:ember");
1214
+ });
1215
+
1216
+ it("Starts but ignores backup if unsupported version", async () => {
1217
+ const customBackup = deepClone(DEFAULT_BACKUP);
1218
+ customBackup.metadata.internal.ezspVersion = 11;
1219
+
1220
+ writeFileSync(backupPath, JSON.stringify(customBackup, undefined, 2));
1221
+
1222
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1223
+ const result = adapter.start();
1224
+ const old = `${backupPath}.old`;
1225
+
1226
+ await vi.advanceTimersByTimeAsync(5000);
1227
+ await expect(result).resolves.toStrictEqual("resumed");
1228
+ expect(existsSync(old)).toBeTruthy();
1229
+ expect(loggerSpies.warning).toHaveBeenCalledWith(
1230
+ "[BACKUP] Current backup file is from an unsupported EZSP version. Renaming and ignoring.",
1231
+ "zh:ember",
1232
+ );
1233
+
1234
+ // cleanup
1235
+ unlinkSync(old);
1236
+ });
1237
+
1238
+ describe("When started", () => {
1239
+ beforeEach(async () => {
1240
+ adapter = new EmberAdapter(DEFAULT_NETWORK_OPTIONS, DEFAULT_SERIAL_PORT_OPTIONS, backupPath, DEFAULT_ADAPTER_OPTIONS);
1241
+
1242
+ const result = adapter.start();
1243
+
1244
+ await vi.advanceTimersByTimeAsync(5000);
1245
+ await result;
1246
+
1247
+ // clean slate "post-start"
1248
+ clearMocks();
1249
+ });
1250
+
1251
+ it("Stops Ezsp layer on stop", async () => {
1252
+ // @ts-expect-error private
1253
+ const ezspStopSpy = vi.spyOn(adapter.ezsp, "stop");
1254
+ // @ts-expect-error private
1255
+ const ezspRemoveAllListenersSpy = vi.spyOn(adapter.ezsp, "removeAllListeners");
1256
+
1257
+ await adapter.stop();
1258
+
1259
+ expect(ezspStopSpy).toHaveBeenCalledTimes(1);
1260
+ expect(ezspRemoveAllListenersSpy).toHaveBeenCalledTimes(1);
1261
+ });
1262
+
1263
+ it("Retrieves parameters from cache when cache valid", async () => {
1264
+ await expect(adapter.emberGetEui64()).resolves.toStrictEqual(DEFAULT_COORDINATOR_IEEE);
1265
+ expect(mockEzspGetEui64).toHaveBeenCalledTimes(0);
1266
+
1267
+ await expect(adapter.emberGetPanId()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.panID);
1268
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(0);
1269
+
1270
+ await expect(adapter.emberGetExtendedPanId()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.extendedPanID!);
1271
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(0);
1272
+
1273
+ await expect(adapter.emberGetRadioChannel()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.channelList[0]);
1274
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(0);
1275
+ });
1276
+
1277
+ it("Retrieves parameters from NCP when cache invalid", async () => {
1278
+ adapter.clearNetworkCache();
1279
+ await expect(adapter.emberGetEui64()).resolves.toStrictEqual(DEFAULT_COORDINATOR_IEEE);
1280
+ expect(mockEzspGetEui64).toHaveBeenCalledTimes(1);
1281
+
1282
+ adapter.clearNetworkCache();
1283
+ await expect(adapter.emberGetPanId()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.panID);
1284
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(1);
1285
+
1286
+ adapter.clearNetworkCache();
1287
+ await expect(adapter.emberGetExtendedPanId()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.extendedPanID!);
1288
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(2);
1289
+
1290
+ adapter.clearNetworkCache();
1291
+ await expect(adapter.emberGetRadioChannel()).resolves.toStrictEqual(DEFAULT_NETWORK_OPTIONS.channelList[0]);
1292
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(3);
1293
+ });
1294
+
1295
+ it("Throws when failed to retrieve parameter from NCP", async () => {
1296
+ mockEzspGetNetworkParameters
1297
+ .mockResolvedValueOnce([SLStatus.FAIL, 0, {}])
1298
+ .mockResolvedValueOnce([SLStatus.FAIL, 0, {}])
1299
+ .mockResolvedValueOnce([SLStatus.FAIL, 0, {}]);
1300
+
1301
+ adapter.clearNetworkCache();
1302
+
1303
+ const p1 = defuseRejection(adapter.emberGetPanId());
1304
+
1305
+ await vi.advanceTimersByTimeAsync(5000);
1306
+ await expect(p1).rejects.toThrow("Failed to get PAN ID (via network parameters) with status=FAIL.");
1307
+
1308
+ adapter.clearNetworkCache();
1309
+
1310
+ const p2 = defuseRejection(adapter.emberGetExtendedPanId());
1311
+
1312
+ await vi.advanceTimersByTimeAsync(5000);
1313
+ await expect(p2).rejects.toThrow("Failed to get Extended PAN ID (via network parameters) with status=FAIL.");
1314
+
1315
+ adapter.clearNetworkCache();
1316
+
1317
+ const p3 = defuseRejection(adapter.emberGetRadioChannel());
1318
+
1319
+ await vi.advanceTimersByTimeAsync(5000);
1320
+ await expect(p3).rejects.toThrow("Failed to get radio channel (via network parameters) with status=FAIL.");
1321
+ });
1322
+
1323
+ it("Logs stack status change", async () => {
1324
+ mockEzspEmitter.emit("stackStatus", SLStatus.ZIGBEE_TRUST_CENTER_SWAP_EUI_HAS_CHANGED);
1325
+ await flushPromises();
1326
+
1327
+ expect(loggerSpies.debug).toHaveBeenCalledWith(
1328
+ `[STACK STATUS] ${SLStatus[SLStatus.ZIGBEE_TRUST_CENTER_SWAP_EUI_HAS_CHANGED]}.`,
1329
+ "zh:ember",
1330
+ );
1331
+ });
1332
+
1333
+ it("Handles message delivery failure", async () => {
1334
+ let apsFrame: EmberApsFrame = {
1335
+ profileId: ZSpec.HA_PROFILE_ID,
1336
+ clusterId: Zcl.Clusters.genBasic.ID,
1337
+ sourceEndpoint: 1,
1338
+ destinationEndpoint: 1,
1339
+ options: 0,
1340
+ groupId: 0,
1341
+ sequence: 0,
1342
+ };
1343
+
1344
+ mockEzspEmitter.emit("messageSent", SLStatus.ZIGBEE_DELIVERY_FAILED, EmberOutgoingMessageType.BROADCAST, 1234, apsFrame, 1);
1345
+ await flushPromises();
1346
+
1347
+ expect(loggerSpies.error).toHaveBeenCalledWith(`Delivery of BROADCAST failed for '1234'.`, "zh:ember");
1348
+
1349
+ const spyDeliveryFailedFor = vi.spyOn(
1350
+ // @ts-expect-error private
1351
+ adapter.oneWaitress,
1352
+ "deliveryFailedFor",
1353
+ );
1354
+
1355
+ apsFrame = {
1356
+ profileId: ZSpec.HA_PROFILE_ID,
1357
+ clusterId: Zcl.Clusters.genBasic.ID,
1358
+ sourceEndpoint: 1,
1359
+ destinationEndpoint: 1,
1360
+ options: 0,
1361
+ groupId: 0,
1362
+ sequence: 0,
1363
+ };
1364
+
1365
+ mockEzspEmitter.emit("messageSent", SLStatus.ZIGBEE_DELIVERY_FAILED, EmberOutgoingMessageType.DIRECT, 1234, apsFrame, 1);
1366
+ await flushPromises();
1367
+
1368
+ expect(spyDeliveryFailedFor).toHaveBeenCalledTimes(1);
1369
+ expect(spyDeliveryFailedFor).toHaveBeenCalledWith(1234, apsFrame);
1370
+ });
1371
+
1372
+ it("Registers message unknown group in multicast table", async () => {
1373
+ // @ts-expect-error private
1374
+ const tableIdx = adapter.multicastTable.length;
1375
+ const apsFrame = {
1376
+ profileId: ZSpec.HA_PROFILE_ID,
1377
+ clusterId: Zcl.Clusters.genBasic.ID,
1378
+ sourceEndpoint: 1,
1379
+ destinationEndpoint: 0xff,
1380
+ options: 0,
1381
+ groupId: 123,
1382
+ sequence: 0,
1383
+ };
1384
+
1385
+ mockEzspEmitter.emit("messageSent", SLStatus.OK, EmberOutgoingMessageType.MULTICAST, 1234, apsFrame, 1);
1386
+ await flushPromises();
1387
+
1388
+ expect(mockEzspSetMulticastTableEntry).toHaveBeenCalledTimes(1);
1389
+ expect(mockEzspSetMulticastTableEntry).toHaveBeenCalledWith(tableIdx, {
1390
+ multicastId: 123,
1391
+ endpoint: FIXED_ENDPOINTS[0].endpoint,
1392
+ networkIndex: FIXED_ENDPOINTS[0].networkIndex,
1393
+ } as EmberMulticastTableEntry);
1394
+ expect(
1395
+ // @ts-expect-error private
1396
+ adapter.multicastTable.length,
1397
+ ).toStrictEqual(tableIdx + 1);
1398
+ });
1399
+
1400
+ it("Fails to register message unknown group in multicast table", async () => {
1401
+ mockEzspSetMulticastTableEntry.mockResolvedValueOnce(SLStatus.FAIL);
1402
+
1403
+ // @ts-expect-error private
1404
+ const tableIdx = adapter.multicastTable.length;
1405
+ const apsFrame = {
1406
+ profileId: ZSpec.HA_PROFILE_ID,
1407
+ clusterId: Zcl.Clusters.genBasic.ID,
1408
+ sourceEndpoint: 1,
1409
+ destinationEndpoint: 0xff,
1410
+ options: 0,
1411
+ groupId: 123,
1412
+ sequence: 0,
1413
+ };
1414
+
1415
+ mockEzspEmitter.emit("messageSent", SLStatus.OK, EmberOutgoingMessageType.MULTICAST, 1234, apsFrame, 1);
1416
+ await flushPromises();
1417
+
1418
+ expect(mockEzspSetMulticastTableEntry).toHaveBeenCalledTimes(1);
1419
+ expect(mockEzspSetMulticastTableEntry).toHaveBeenCalledWith(tableIdx, {
1420
+ multicastId: 123,
1421
+ endpoint: FIXED_ENDPOINTS[0].endpoint,
1422
+ networkIndex: FIXED_ENDPOINTS[0].networkIndex,
1423
+ } as EmberMulticastTableEntry);
1424
+ expect(
1425
+ // @ts-expect-error private
1426
+ adapter.multicastTable.length,
1427
+ ).toStrictEqual(tableIdx); // not increased, entry was removed
1428
+ });
1429
+
1430
+ it("Emits network address event on ZDO NETWORK_ADDRESS_RESPONSE", async () => {
1431
+ const spyResolveZDO = vi.spyOn(
1432
+ // @ts-expect-error private
1433
+ adapter.oneWaitress,
1434
+ "resolveZDO",
1435
+ );
1436
+ const spyEmit = vi.spyOn(adapter, "emit");
1437
+ const sender = 1234;
1438
+ const apsFrame: EmberApsFrame = {
1439
+ profileId: Zdo.ZDO_PROFILE_ID,
1440
+ clusterId: Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE,
1441
+ sourceEndpoint: Zdo.ZDO_ENDPOINT,
1442
+ destinationEndpoint: Zdo.ZDO_ENDPOINT,
1443
+ options: 0,
1444
+ groupId: 0,
1445
+ sequence: 0,
1446
+ };
1447
+
1448
+ mockEzspEmitter.emit(
1449
+ "zdoResponse",
1450
+ apsFrame,
1451
+ sender,
1452
+ Buffer.from([1, Zdo.Status.SUCCESS, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11, 0x22, 0x33, 0xd2, 0x04]),
1453
+ );
1454
+ await flushPromises();
1455
+
1456
+ const zdoResponse = [
1457
+ Zdo.Status.SUCCESS,
1458
+ {
1459
+ eui64: "0x332211eeddccbbaa",
1460
+ nwkAddress: sender,
1461
+ startIndex: 0,
1462
+ assocDevList: [],
1463
+ } as ZdoTypes.NetworkAddressResponse,
1464
+ ];
1465
+
1466
+ expect(spyResolveZDO).toHaveBeenCalledTimes(1);
1467
+ expect(spyResolveZDO).toHaveBeenCalledWith("0x332211eeddccbbaa", apsFrame, zdoResponse);
1468
+ expect(spyEmit).toHaveBeenCalledWith("zdoResponse", Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE, zdoResponse);
1469
+ });
1470
+
1471
+ it("Emits device announce event on ZDO END_DEVICE_ANNOUNCE", async () => {
1472
+ const spyResolveZDO = vi.spyOn(
1473
+ // @ts-expect-error private
1474
+ adapter.oneWaitress,
1475
+ "resolveZDO",
1476
+ );
1477
+ const spyEmit = vi.spyOn(adapter, "emit");
1478
+ const sender = 1234;
1479
+ const apsFrame: EmberApsFrame = {
1480
+ profileId: Zdo.ZDO_PROFILE_ID,
1481
+ clusterId: Zdo.ClusterId.END_DEVICE_ANNOUNCE,
1482
+ sourceEndpoint: Zdo.ZDO_ENDPOINT,
1483
+ destinationEndpoint: Zdo.ZDO_ENDPOINT,
1484
+ options: 0,
1485
+ groupId: 0,
1486
+ sequence: 0,
1487
+ };
1488
+
1489
+ mockEzspEmitter.emit("zdoResponse", apsFrame, sender, Buffer.from([1, 0xd2, 0x04, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11, 0x22, 0x33, 6]));
1490
+
1491
+ await flushPromises();
1492
+
1493
+ const zdoResponse = [
1494
+ Zdo.Status.SUCCESS,
1495
+ {
1496
+ nwkAddress: sender,
1497
+ eui64: "0x332211eeddccbbaa",
1498
+ capabilities: {
1499
+ alternatePANCoordinator: 0,
1500
+ deviceType: 1,
1501
+ powerSource: 1,
1502
+ rxOnWhenIdle: 0,
1503
+ reserved1: 0,
1504
+ reserved2: 0,
1505
+ securityCapability: 0,
1506
+ allocateAddress: 0,
1507
+ },
1508
+ } as ZdoTypes.EndDeviceAnnounce,
1509
+ ];
1510
+ expect(spyResolveZDO).toHaveBeenCalledTimes(1);
1511
+ expect(spyResolveZDO).toHaveBeenCalledWith(sender, apsFrame, zdoResponse);
1512
+ expect(spyEmit).toHaveBeenCalledWith("zdoResponse", Zdo.ClusterId.END_DEVICE_ANNOUNCE, zdoResponse);
1513
+ });
1514
+
1515
+ it("Emits ZCL payload on incoming message", async () => {
1516
+ const spyResolveZCL = vi.spyOn(
1517
+ // @ts-expect-error private
1518
+ adapter.oneWaitress,
1519
+ "resolveZCL",
1520
+ );
1521
+ const spyEmit = vi.spyOn(adapter, "emit");
1522
+ const sender = 1234;
1523
+ const apsFrame: EmberApsFrame = {
1524
+ profileId: ZSpec.HA_PROFILE_ID,
1525
+ clusterId: Zcl.Clusters.genBasic.ID,
1526
+ sourceEndpoint: 2,
1527
+ destinationEndpoint: 1,
1528
+ options: 0,
1529
+ groupId: 0,
1530
+ sequence: 0,
1531
+ };
1532
+ const lastHopLqi = 252;
1533
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
1534
+ const messageContents = Buffer.from("1803010000002003", "hex");
1535
+
1536
+ mockEzspEmitter.emit("incomingMessage", EmberIncomingMessageType.UNICAST, apsFrame, lastHopLqi, sender, messageContents);
1537
+ await flushPromises();
1538
+
1539
+ const payload: ZclPayload = {
1540
+ clusterID: apsFrame.clusterId,
1541
+ header: Zcl.Header.fromBuffer(messageContents),
1542
+ address: sender,
1543
+ data: messageContents,
1544
+ endpoint: apsFrame.sourceEndpoint,
1545
+ linkquality: lastHopLqi,
1546
+ groupID: apsFrame.groupId,
1547
+ wasBroadcast: false,
1548
+ destinationEndpoint: apsFrame.destinationEndpoint,
1549
+ };
1550
+
1551
+ expect(spyResolveZCL).toHaveBeenCalledTimes(1);
1552
+ expect(spyResolveZCL).toHaveBeenCalledWith(payload);
1553
+ expect(spyEmit).toHaveBeenCalledWith("zclPayload", payload);
1554
+ });
1555
+
1556
+ it("Emits ZCL payload on touchlink message", async () => {
1557
+ const spyResolveZCL = vi.spyOn(
1558
+ // @ts-expect-error private
1559
+ adapter.oneWaitress,
1560
+ "resolveZCL",
1561
+ );
1562
+ const spyEmit = vi.spyOn(adapter, "emit");
1563
+ const sourcePanId: PanId = 0x1234;
1564
+ const sourceAddress: Eui64 = "0x1122334455aabbcc";
1565
+ const lastHopLqi = 252;
1566
+ const groupId: number = 0;
1567
+ const messageContents = Buffer.from("1803010000002003", "hex");
1568
+
1569
+ mockEzspEmitter.emit("touchlinkMessage", sourcePanId, sourceAddress, groupId, lastHopLqi, messageContents);
1570
+ await flushPromises();
1571
+
1572
+ const payload: ZclPayload = {
1573
+ clusterID: Zcl.Clusters.touchlink.ID,
1574
+ header: Zcl.Header.fromBuffer(messageContents),
1575
+ address: sourceAddress,
1576
+ data: messageContents,
1577
+ endpoint: 1,
1578
+ linkquality: lastHopLqi,
1579
+ groupID: groupId,
1580
+ wasBroadcast: true,
1581
+ destinationEndpoint: FIXED_ENDPOINTS[0].endpoint,
1582
+ };
1583
+
1584
+ expect(spyResolveZCL).toHaveBeenCalledTimes(1);
1585
+ expect(spyResolveZCL).toHaveBeenCalledWith(payload);
1586
+ expect(spyEmit).toHaveBeenCalledWith("zclPayload", payload);
1587
+ });
1588
+
1589
+ it("Emits ZCL payload on greenpower message", async () => {
1590
+ const spyResolveZCL = vi.spyOn(
1591
+ // @ts-expect-error private
1592
+ adapter.oneWaitress,
1593
+ "resolveZCL",
1594
+ );
1595
+ const spyEmit = vi.spyOn(adapter, "emit");
1596
+ const sourceId: number = 1234;
1597
+ const nwkAddress: NodeId = sourceId & 0xffff;
1598
+ const gpdLink: number = 123;
1599
+ const sequenceNumber: number = 1;
1600
+ const commandIdentifier: number = Zcl.Clusters.greenPower.commands.commissioningNotification.ID;
1601
+ const frameCounter: number = 102;
1602
+ const gpdCommandId: number = 0xe0;
1603
+ const gpdCommandPayload = Buffer.from([
1604
+ 0x02 /* deviceID */,
1605
+ 0x83 /* options */,
1606
+ 0xf2 /* extendedOptions */,
1607
+ ...[0xf1, 0xec, 0x92, 0xab, 0xff, 0x8f, 0x13, 0x63, 0xe1, 0x46, 0xbe, 0xb5, 0x18, 0xc9, 0x0c, 0xab] /* securityKey */,
1608
+ 0xa4,
1609
+ 0x46,
1610
+ 0xd4,
1611
+ 0xd5 /* keyMic */,
1612
+ 0xe4,
1613
+ 0x04,
1614
+ 0x00,
1615
+ 0x00 /* outgoingCounter */,
1616
+ ]);
1617
+ const gpdHeader = Buffer.alloc(15);
1618
+ gpdHeader.writeUInt8(0b00000001, 0);
1619
+ gpdHeader.writeUInt8(sequenceNumber, 1);
1620
+ gpdHeader.writeUInt8(commandIdentifier, 2);
1621
+ gpdHeader.writeUInt16LE(0, 3);
1622
+ gpdHeader.writeUInt32LE(sourceId, 5);
1623
+ gpdHeader.writeUInt32LE(frameCounter, 9);
1624
+ gpdHeader.writeUInt8(gpdCommandId, 13);
1625
+ gpdHeader.writeUInt8(gpdCommandPayload.length, 14);
1626
+ const messageContents = Buffer.concat([gpdHeader, gpdCommandPayload]);
1627
+ const apsFrame: EmberApsFrame = {
1628
+ profileId: ZSpec.GP_PROFILE_ID,
1629
+ clusterId: Zcl.Clusters.greenPower.ID,
1630
+ sourceEndpoint: ZSpec.GP_ENDPOINT,
1631
+ destinationEndpoint: ZSpec.GP_ENDPOINT,
1632
+ options: 0, // not used
1633
+ groupId: ZSpec.GP_GROUP_ID,
1634
+ sequence: 0, // not used
1635
+ };
1636
+
1637
+ mockEzspEmitter.emit("incomingMessage", EmberIncomingMessageType.BROADCAST, apsFrame, gpdLink, nwkAddress, messageContents);
1638
+ await flushPromises();
1639
+
1640
+ const payload: ZclPayload = {
1641
+ header: Zcl.Header.fromBuffer(messageContents),
1642
+ data: messageContents,
1643
+ clusterID: apsFrame.clusterId,
1644
+ address: nwkAddress,
1645
+ endpoint: apsFrame.sourceEndpoint,
1646
+ linkquality: gpdLink,
1647
+ groupID: apsFrame.groupId,
1648
+ wasBroadcast: true,
1649
+ destinationEndpoint: apsFrame.destinationEndpoint,
1650
+ };
1651
+
1652
+ expect(spyResolveZCL).toHaveBeenCalledTimes(1);
1653
+ expect(spyResolveZCL).toHaveBeenCalledWith(payload);
1654
+ expect(spyEmit).toHaveBeenCalledWith("zclPayload", payload);
1655
+ });
1656
+
1657
+ it("Emits device joined on trust center join", async () => {
1658
+ const spyEmit = vi.spyOn(adapter, "emit");
1659
+ const newNodeId: NodeId = 1234;
1660
+ const newNodeEui64: Eui64 = "0x11223344eebbccaa";
1661
+ const status: EmberDeviceUpdate = EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN;
1662
+ const policyDecision: EmberJoinDecision = EmberJoinDecision.USE_PRECONFIGURED_KEY;
1663
+ const parentOfNewNodeId: NodeId = 4321;
1664
+
1665
+ mockEzspEmitter.emit("trustCenterJoin", newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId);
1666
+ await flushPromises();
1667
+
1668
+ expect(spyEmit).toHaveBeenCalledWith("deviceJoined", {
1669
+ networkAddress: newNodeId,
1670
+ ieeeAddr: newNodeEui64,
1671
+ } as DeviceJoinedPayload);
1672
+ });
1673
+
1674
+ it("Emits device leave on trust center join", async () => {
1675
+ const spyEmit = vi.spyOn(adapter, "emit");
1676
+ const newNodeId: NodeId = 1234;
1677
+ const newNodeEui64: Eui64 = "0x11223344eebbccaa";
1678
+ const status: EmberDeviceUpdate = EmberDeviceUpdate.DEVICE_LEFT;
1679
+ const policyDecision: EmberJoinDecision = EmberJoinDecision.NO_ACTION;
1680
+ const parentOfNewNodeId: NodeId = 0xffff;
1681
+
1682
+ mockEzspEmitter.emit("trustCenterJoin", newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId);
1683
+ await flushPromises();
1684
+
1685
+ expect(spyEmit).toHaveBeenCalledWith("deviceLeave", {
1686
+ networkAddress: newNodeId,
1687
+ ieeeAddr: newNodeEui64,
1688
+ } as DeviceLeavePayload);
1689
+ });
1690
+
1691
+ it("Handles DENY_JOIN on trust center join", async () => {
1692
+ const newNodeId: NodeId = 1234;
1693
+ const newNodeEui64: Eui64 = "0x11223344eebbccaa";
1694
+ const status: EmberDeviceUpdate = EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN;
1695
+ const policyDecision: EmberJoinDecision = EmberJoinDecision.DENY_JOIN;
1696
+ const parentOfNewNodeId: NodeId = 4321;
1697
+
1698
+ mockEzspEmitter.emit("trustCenterJoin", newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId);
1699
+ await flushPromises();
1700
+
1701
+ expect(loggerSpies.warning).toHaveBeenCalledWith(
1702
+ `[TRUST CENTER] Device ${newNodeId}:${newNodeEui64} was denied joining via ${parentOfNewNodeId}.`,
1703
+ "zh:ember",
1704
+ );
1705
+ });
1706
+
1707
+ it("Handles device join workaround requiring specific manufacturer code", async () => {
1708
+ const spyEmit = vi.spyOn(adapter, "emit");
1709
+ const newNodeId: NodeId = 1234;
1710
+ const newNodeEui64: Eui64 = "0x54ef44ffeebbccaa";
1711
+ const status: EmberDeviceUpdate = EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN;
1712
+ const policyDecision: EmberJoinDecision = EmberJoinDecision.USE_PRECONFIGURED_KEY;
1713
+ const parentOfNewNodeId: NodeId = 4321;
1714
+
1715
+ mockEzspEmitter.emit("trustCenterJoin", newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId);
1716
+ await flushPromises();
1717
+
1718
+ expect(spyEmit).toHaveBeenCalledWith("deviceJoined", {
1719
+ networkAddress: newNodeId,
1720
+ ieeeAddr: newNodeEui64,
1721
+ } as DeviceJoinedPayload);
1722
+ expect(mockEzspSetManufacturerCode).toHaveBeenCalledWith(Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN);
1723
+ expect(mockManufCode).toStrictEqual(Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN);
1724
+ });
1725
+
1726
+ it("Triggers watchdog counters", async () => {
1727
+ await vi.advanceTimersByTimeAsync(3610000);
1728
+ expect(mockEzspReadAndClearCounters).toHaveBeenCalledTimes(1);
1729
+ expect(loggerSpies.info).toHaveBeenCalledTimes(2);
1730
+ expect(loggerSpies.info.mock.calls[0][0]).toMatch(/[NCP COUNTERS]/);
1731
+ expect(loggerSpies.info.mock.calls[1][0]).toMatch(/[ASH COUNTERS]/);
1732
+ });
1733
+
1734
+ it("Exports link keys", async () => {
1735
+ const k1Context: SecManContext = {
1736
+ coreKeyType: SecManKeyType.APP_LINK,
1737
+ keyIndex: 0,
1738
+ derivedType: SecManDerivedKeyType.NONE,
1739
+ eui64: "0x1122334455667788",
1740
+ multiNetworkIndex: 0,
1741
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1742
+ psaKeyAlgPermission: 0,
1743
+ };
1744
+ const k1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1745
+ const k1Hashed = ZSpec.Utils.aes128MmoHash(k1);
1746
+ const k1Metadata: SecManAPSKeyMetadata = {
1747
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1748
+ outgoingFrameCounter: 1,
1749
+ incomingFrameCounter: 2,
1750
+ ttlInSeconds: 0,
1751
+ };
1752
+ const k2Context: SecManContext = {
1753
+ coreKeyType: SecManKeyType.APP_LINK,
1754
+ keyIndex: 1,
1755
+ derivedType: SecManDerivedKeyType.NONE,
1756
+ eui64: "0x2233445566778899",
1757
+ multiNetworkIndex: 0,
1758
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1759
+ psaKeyAlgPermission: 0,
1760
+ };
1761
+ const k2 = Buffer.from([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
1762
+ const k2Hashed = ZSpec.Utils.aes128MmoHash(k2);
1763
+ const k2Metadata: SecManAPSKeyMetadata = {
1764
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1765
+ outgoingFrameCounter: 10,
1766
+ incomingFrameCounter: 20,
1767
+ ttlInSeconds: 0,
1768
+ };
1769
+ const k3Context: SecManContext = {
1770
+ coreKeyType: SecManKeyType.APP_LINK,
1771
+ keyIndex: 2,
1772
+ derivedType: SecManDerivedKeyType.NONE,
1773
+ eui64: "0x3344556677889900",
1774
+ multiNetworkIndex: 0,
1775
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1776
+ psaKeyAlgPermission: 0,
1777
+ };
1778
+ const k3 = Buffer.from([3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]);
1779
+ const k3Hashed = ZSpec.Utils.aes128MmoHash(k3);
1780
+ const k3Metadata: SecManAPSKeyMetadata = {
1781
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1782
+ outgoingFrameCounter: 100,
1783
+ incomingFrameCounter: 200,
1784
+ ttlInSeconds: 0,
1785
+ };
1786
+
1787
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 3]);
1788
+ mockEzspExportLinkKeyByIndex
1789
+ .mockResolvedValueOnce([SLStatus.OK, k1Context, {contents: k1} as SecManKey, k1Metadata])
1790
+ .mockResolvedValueOnce([SLStatus.OK, k2Context, {contents: k2} as SecManKey, k2Metadata])
1791
+ .mockResolvedValueOnce([SLStatus.OK, k3Context, {contents: k3} as SecManKey, k3Metadata]);
1792
+
1793
+ const keys = await adapter.exportLinkKeys();
1794
+
1795
+ expect(mockEzspExportLinkKeyByIndex).toHaveBeenCalledTimes(3);
1796
+ expect(keys).toStrictEqual([
1797
+ {
1798
+ deviceEui64: k1Context.eui64,
1799
+ key: {contents: k1Hashed},
1800
+ outgoingFrameCounter: k1Metadata.outgoingFrameCounter,
1801
+ incomingFrameCounter: k1Metadata.incomingFrameCounter,
1802
+ } as LinkKeyBackupData,
1803
+ {
1804
+ deviceEui64: k2Context.eui64,
1805
+ key: {contents: k2Hashed},
1806
+ outgoingFrameCounter: k2Metadata.outgoingFrameCounter,
1807
+ incomingFrameCounter: k2Metadata.incomingFrameCounter,
1808
+ } as LinkKeyBackupData,
1809
+ {
1810
+ deviceEui64: k3Context.eui64,
1811
+ key: {contents: k3Hashed},
1812
+ outgoingFrameCounter: k3Metadata.outgoingFrameCounter,
1813
+ incomingFrameCounter: k3Metadata.incomingFrameCounter,
1814
+ } as LinkKeyBackupData,
1815
+ ]);
1816
+ });
1817
+
1818
+ it("Exports zero link keys", async () => {
1819
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 0]);
1820
+ const keys = await adapter.exportLinkKeys();
1821
+
1822
+ expect(keys).toStrictEqual([]);
1823
+ });
1824
+
1825
+ it("Fails to export link keys due to failed table size retrieval", async () => {
1826
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.FAIL, 0]);
1827
+
1828
+ await expect(adapter.exportLinkKeys()).rejects.toThrow("[BACKUP] Failed to retrieve key table size from NCP with status=FAIL.");
1829
+ });
1830
+
1831
+ it("Imports link keys", async () => {
1832
+ const k1Context: SecManContext = {
1833
+ coreKeyType: SecManKeyType.APP_LINK,
1834
+ keyIndex: 0,
1835
+ derivedType: SecManDerivedKeyType.NONE,
1836
+ eui64: "0x1122334455667788",
1837
+ multiNetworkIndex: 0,
1838
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1839
+ psaKeyAlgPermission: 0,
1840
+ };
1841
+ const k1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1842
+ const k1Metadata: SecManAPSKeyMetadata = {
1843
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1844
+ outgoingFrameCounter: 1,
1845
+ incomingFrameCounter: 2,
1846
+ ttlInSeconds: 0,
1847
+ };
1848
+ const k2Context: SecManContext = {
1849
+ coreKeyType: SecManKeyType.APP_LINK,
1850
+ keyIndex: 1,
1851
+ derivedType: SecManDerivedKeyType.NONE,
1852
+ eui64: "0x2233445566778899",
1853
+ multiNetworkIndex: 0,
1854
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1855
+ psaKeyAlgPermission: 0,
1856
+ };
1857
+ const k2 = Buffer.from([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
1858
+ const k2Metadata: SecManAPSKeyMetadata = {
1859
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1860
+ outgoingFrameCounter: 10,
1861
+ incomingFrameCounter: 20,
1862
+ ttlInSeconds: 0,
1863
+ };
1864
+ const k3Context: SecManContext = {
1865
+ coreKeyType: SecManKeyType.APP_LINK,
1866
+ keyIndex: 2,
1867
+ derivedType: SecManDerivedKeyType.NONE,
1868
+ eui64: "0x3344556677889900",
1869
+ multiNetworkIndex: 0,
1870
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1871
+ psaKeyAlgPermission: 0,
1872
+ };
1873
+ const k3 = Buffer.from([3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]);
1874
+ const k3Metadata: SecManAPSKeyMetadata = {
1875
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1876
+ outgoingFrameCounter: 100,
1877
+ incomingFrameCounter: 200,
1878
+ ttlInSeconds: 0,
1879
+ };
1880
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 4]);
1881
+ mockEzspNetworkState.mockResolvedValueOnce(EmberNetworkStatus.NO_NETWORK);
1882
+
1883
+ await adapter.importLinkKeys([
1884
+ {
1885
+ deviceEui64: k1Context.eui64,
1886
+ key: {contents: k1},
1887
+ outgoingFrameCounter: k1Metadata.outgoingFrameCounter,
1888
+ incomingFrameCounter: k1Metadata.incomingFrameCounter,
1889
+ },
1890
+ {
1891
+ deviceEui64: k2Context.eui64,
1892
+ key: {contents: k2},
1893
+ outgoingFrameCounter: k2Metadata.outgoingFrameCounter,
1894
+ incomingFrameCounter: k2Metadata.incomingFrameCounter,
1895
+ },
1896
+ {
1897
+ deviceEui64: k3Context.eui64,
1898
+ key: {contents: k3},
1899
+ outgoingFrameCounter: k3Metadata.outgoingFrameCounter,
1900
+ incomingFrameCounter: k3Metadata.incomingFrameCounter,
1901
+ },
1902
+ ]);
1903
+
1904
+ expect(mockEzspImportLinkKey).toHaveBeenCalledTimes(3);
1905
+ expect(mockEzspEraseKeyTableEntry).toHaveBeenCalledTimes(1);
1906
+ });
1907
+
1908
+ it("Imports zero link keys", async () => {
1909
+ await expect(adapter.importLinkKeys([])).resolves.toStrictEqual(undefined);
1910
+ });
1911
+
1912
+ it("Failed to import link keys due to failed table size retrieval", async () => {
1913
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.FAIL, 0]);
1914
+
1915
+ await expect(
1916
+ adapter.importLinkKeys([
1917
+ // @ts-expect-error mock, unnecessary
1918
+ {},
1919
+ ]),
1920
+ ).rejects.toThrow("[BACKUP] Failed to retrieve key table size from NCP with status=FAIL.");
1921
+ });
1922
+
1923
+ it("Failed to import link keys due to insufficient table size", async () => {
1924
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 0]);
1925
+
1926
+ await expect(
1927
+ adapter.importLinkKeys([
1928
+ // @ts-expect-error mock, unnecessary
1929
+ {},
1930
+ ]),
1931
+ ).rejects.toThrow("[BACKUP] Current key table of 0 is too small to import backup of 1!");
1932
+ });
1933
+
1934
+ it("Failed to import link keys due to improper network state", async () => {
1935
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 3]);
1936
+ mockEzspNetworkState.mockResolvedValueOnce(EmberNetworkStatus.JOINED_NETWORK);
1937
+
1938
+ await expect(
1939
+ adapter.importLinkKeys([
1940
+ // @ts-expect-error mock, unnecessary
1941
+ {},
1942
+ ]),
1943
+ ).rejects.toThrow(
1944
+ `[BACKUP] Cannot import TC data while network is up, networkStatus=${EmberNetworkStatus[EmberNetworkStatus.JOINED_NETWORK]}.`,
1945
+ );
1946
+ });
1947
+
1948
+ it("Failed to import link keys due to failed key set", async () => {
1949
+ const k1Context: SecManContext = {
1950
+ coreKeyType: SecManKeyType.APP_LINK,
1951
+ keyIndex: 0,
1952
+ derivedType: SecManDerivedKeyType.NONE,
1953
+ eui64: "0x1122334455667788",
1954
+ multiNetworkIndex: 0,
1955
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1956
+ psaKeyAlgPermission: 0,
1957
+ };
1958
+ const k1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1959
+ const k1Metadata: SecManAPSKeyMetadata = {
1960
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1961
+ outgoingFrameCounter: 1,
1962
+ incomingFrameCounter: 2,
1963
+ ttlInSeconds: 0,
1964
+ };
1965
+
1966
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 3]);
1967
+ mockEzspNetworkState.mockResolvedValueOnce(EmberNetworkStatus.NO_NETWORK);
1968
+ mockEzspImportLinkKey.mockResolvedValueOnce(SLStatus.FAIL);
1969
+
1970
+ await expect(
1971
+ adapter.importLinkKeys([
1972
+ {
1973
+ deviceEui64: k1Context.eui64,
1974
+ key: {contents: k1},
1975
+ outgoingFrameCounter: k1Metadata.outgoingFrameCounter,
1976
+ incomingFrameCounter: k1Metadata.incomingFrameCounter,
1977
+ },
1978
+ ]),
1979
+ ).rejects.toThrow("[BACKUP] Failed to set key table entry at index 0 with status=FAIL.");
1980
+ });
1981
+
1982
+ it("Failed to import link keys due to failed key erase", async () => {
1983
+ const k1Context: SecManContext = {
1984
+ coreKeyType: SecManKeyType.APP_LINK,
1985
+ keyIndex: 0,
1986
+ derivedType: SecManDerivedKeyType.NONE,
1987
+ eui64: "0x1122334455667788",
1988
+ multiNetworkIndex: 0,
1989
+ flags: SecManFlag.EUI_IS_VALID | SecManFlag.KEY_INDEX_IS_VALID,
1990
+ psaKeyAlgPermission: 0,
1991
+ };
1992
+ const k1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1993
+ const k1Metadata: SecManAPSKeyMetadata = {
1994
+ bitmask: EmberKeyStructBitmask.HAS_INCOMING_FRAME_COUNTER | EmberKeyStructBitmask.HAS_OUTGOING_FRAME_COUNTER,
1995
+ outgoingFrameCounter: 1,
1996
+ incomingFrameCounter: 2,
1997
+ ttlInSeconds: 0,
1998
+ };
1999
+
2000
+ mockEzspGetConfigurationValue.mockResolvedValueOnce([SLStatus.OK, 3]);
2001
+ mockEzspNetworkState.mockResolvedValueOnce(EmberNetworkStatus.NO_NETWORK);
2002
+ mockEzspEraseKeyTableEntry.mockResolvedValueOnce(SLStatus.FAIL);
2003
+
2004
+ await expect(
2005
+ adapter.importLinkKeys([
2006
+ {
2007
+ deviceEui64: k1Context.eui64,
2008
+ key: {contents: k1},
2009
+ outgoingFrameCounter: k1Metadata.outgoingFrameCounter,
2010
+ incomingFrameCounter: k1Metadata.incomingFrameCounter,
2011
+ },
2012
+ ]),
2013
+ ).rejects.toThrow("[BACKUP] Failed to erase key table entry at index 1 with status=FAIL.");
2014
+ });
2015
+
2016
+ it("Broadcasts network key update", async () => {
2017
+ const p = adapter.broadcastNetworkKeyUpdate();
2018
+
2019
+ await vi.advanceTimersByTimeAsync(100000);
2020
+ await expect(p).resolves.toStrictEqual(undefined);
2021
+ expect(mockEzspBroadcastNextNetworkKey).toHaveBeenCalledTimes(1);
2022
+ expect(mockEzspBroadcastNetworkKeySwitch).toHaveBeenCalledTimes(1);
2023
+ });
2024
+
2025
+ it("Fails to broadcast network key update due to failed next key broadcast", async () => {
2026
+ mockEzspBroadcastNextNetworkKey.mockResolvedValueOnce(SLStatus.FAIL);
2027
+
2028
+ const p = defuseRejection(adapter.broadcastNetworkKeyUpdate());
2029
+
2030
+ await vi.advanceTimersByTimeAsync(100000);
2031
+ await expect(p).rejects.toThrow("[TRUST CENTER] Failed to broadcast next network key with status=FAIL.");
2032
+ expect(mockEzspBroadcastNextNetworkKey).toHaveBeenCalledTimes(1);
2033
+ expect(mockEzspBroadcastNetworkKeySwitch).toHaveBeenCalledTimes(0);
2034
+ });
2035
+
2036
+ it("Fails to broadcast network key update due to failed switch broadcast", async () => {
2037
+ mockEzspBroadcastNetworkKeySwitch.mockResolvedValueOnce(SLStatus.FAIL);
2038
+
2039
+ const p = defuseRejection(adapter.broadcastNetworkKeyUpdate());
2040
+
2041
+ await vi.advanceTimersByTimeAsync(100000);
2042
+ await expect(p).rejects.toThrow("[TRUST CENTER] Failed to broadcast network key switch with status=FAIL.");
2043
+ expect(mockEzspBroadcastNextNetworkKey).toHaveBeenCalledTimes(1);
2044
+ expect(mockEzspBroadcastNetworkKeySwitch).toHaveBeenCalledTimes(1);
2045
+ });
2046
+
2047
+ it("Handles NCP needing reset & init", async () => {
2048
+ const spyEmit = vi.spyOn(adapter, "emit");
2049
+
2050
+ mockEzspEmitter.emit("ncpNeedsResetAndInit", EzspStatus.ERROR_SERIAL_INIT);
2051
+ await vi.advanceTimersByTimeAsync(5000);
2052
+
2053
+ expect(spyEmit).toHaveBeenCalledTimes(1);
2054
+ expect(spyEmit).toHaveBeenCalledWith("disconnected");
2055
+ });
2056
+
2057
+ it("Emits adapter disconnected when NCP needs reset & init but queue is too high", async () => {
2058
+ vi.spyOn(
2059
+ // @ts-expect-error private
2060
+ adapter.queue,
2061
+ "count",
2062
+ ).mockReturnValueOnce(999);
2063
+ const spyEmit = vi.spyOn(adapter, "emit");
2064
+
2065
+ mockEzspEmitter.emit("ncpNeedsResetAndInit", EzspStatus.ERROR_SERIAL_INIT);
2066
+ await flushPromises();
2067
+
2068
+ expect(spyEmit).toHaveBeenCalledWith("disconnected");
2069
+ });
2070
+
2071
+ it("Emits adapter disconnected when failed to reset & init NCP", async () => {
2072
+ vi.spyOn(adapter, "stop").mockRejectedValueOnce(new Error("mock error"));
2073
+ const spyEmit = vi.spyOn(adapter, "emit");
2074
+
2075
+ mockEzspEmitter.emit("ncpNeedsResetAndInit", EzspStatus.ERROR_SERIAL_INIT);
2076
+ await flushPromises();
2077
+
2078
+ expect(spyEmit).toHaveBeenCalledWith("disconnected");
2079
+ });
2080
+
2081
+ it("Handles channel changed stack status", async () => {
2082
+ mockEzspEmitter.emit("stackStatus", SLStatus.ZIGBEE_CHANNEL_CHANGED);
2083
+ await flushPromises();
2084
+ expect(loggerSpies.info).toHaveBeenCalledWith("[STACK STATUS] Channel changed.", "zh:ember");
2085
+ });
2086
+
2087
+ it.each([
2088
+ ["getCoordinatorIEEE", []],
2089
+ ["getNetworkParameters", []],
2090
+ ["permitJoin", [250, 1234]],
2091
+ ["permitJoin", [250]],
2092
+ [
2093
+ "sendZclFrameToEndpoint",
2094
+ [
2095
+ "0x1122334455667788",
2096
+ 1234,
2097
+ 1,
2098
+ Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {}),
2099
+ 10000,
2100
+ true,
2101
+ false,
2102
+ 1,
2103
+ ],
2104
+ ],
2105
+ [
2106
+ "sendZclFrameToGroup",
2107
+ [32, Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {}), 1],
2108
+ ],
2109
+ [
2110
+ "sendZclFrameToAll",
2111
+ [
2112
+ 1,
2113
+ Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {}),
2114
+ 1,
2115
+ ZSpec.BroadcastAddress.DEFAULT,
2116
+ ],
2117
+ ],
2118
+ ])("Adapter impl: throws when using non-InterPAN function %s while in InterPAN mode", async (funcName, args) => {
2119
+ await adapter.setChannelInterPAN(15);
2120
+
2121
+ await expect(
2122
+ // @ts-expect-error mock
2123
+ adapter[funcName](...args),
2124
+ ).rejects.toThrow("[INTERPAN MODE] Cannot execute non-InterPAN commands.");
2125
+ });
2126
+
2127
+ it("Adapter impl: getCoordinatorIEEE", async () => {
2128
+ await expect(adapter.getCoordinatorIEEE()).resolves.toStrictEqual(DEFAULT_COORDINATOR_IEEE);
2129
+ });
2130
+
2131
+ it("Adapter impl: getCoordinatorVersion", async () => {
2132
+ await expect(adapter.getCoordinatorVersion()).resolves.toStrictEqual({
2133
+ type: "EmberZNet",
2134
+ meta: {
2135
+ ezsp: EZSP_PROTOCOL_VERSION,
2136
+ revision: `8.0.0 [${EmberVersionType[EmberVersionType.GA]}]`,
2137
+ build: 135,
2138
+ major: 8,
2139
+ minor: 0,
2140
+ patch: 0,
2141
+ special: 0,
2142
+ type: EmberVersionType.GA,
2143
+ },
2144
+ } as TsType.CoordinatorVersion);
2145
+ });
2146
+
2147
+ it("Adapter impl: reset soft", async () => {
2148
+ await expect(adapter.reset("soft")).rejects.toThrow(`Not supported 'soft'.`);
2149
+ });
2150
+
2151
+ it("Adapter impl: reset hard", async () => {
2152
+ await expect(adapter.reset("hard")).rejects.toThrow(`Not supported 'hard'.`);
2153
+ });
2154
+
2155
+ it("Adapter impl: supportsBackup", async () => {
2156
+ await expect(adapter.supportsBackup()).resolves.toStrictEqual(true);
2157
+ });
2158
+
2159
+ it("Adapter impl: backup", async () => {
2160
+ await expect(adapter.backup([])).resolves.toStrictEqual({
2161
+ networkOptions: {
2162
+ panId: DEFAULT_NETWORK_OPTIONS.panID, // uint16_t
2163
+ extendedPanId: Buffer.from(DEFAULT_NETWORK_OPTIONS.extendedPanID!),
2164
+ channelList: ZSpec.ALL_802_15_4_CHANNELS.slice(),
2165
+ networkKey: Buffer.from(DEFAULT_BACKUP.network_key.key, "hex"),
2166
+ networkKeyDistribute: false,
2167
+ },
2168
+ logicalChannel: DEFAULT_NETWORK_OPTIONS.channelList[0],
2169
+ networkKeyInfo: {
2170
+ sequenceNumber: DEFAULT_BACKUP.network_key.sequence_number,
2171
+ frameCounter: DEFAULT_BACKUP.network_key.frame_counter,
2172
+ },
2173
+ securityLevel: SECURITY_LEVEL_Z3,
2174
+ networkUpdateId: 0,
2175
+ coordinatorIeeeAddress: Buffer.from(DEFAULT_BACKUP.coordinator_ieee, "hex"),
2176
+ devices: [],
2177
+ ezsp: {
2178
+ version: EZSP_PROTOCOL_VERSION,
2179
+ hashed_tclk: Buffer.from(DEFAULT_BACKUP.stack_specific!.ezsp!.hashed_tclk!, "hex"),
2180
+ },
2181
+ } as Backup);
2182
+ });
2183
+
2184
+ it.each([
2185
+ [
2186
+ "failed get network parameters",
2187
+ () => {
2188
+ mockEzspGetNetworkParameters.mockResolvedValueOnce([SLStatus.FAIL, 0, {}]);
2189
+ },
2190
+ "[BACKUP] Failed to get network parameters with status=FAIL.",
2191
+ ],
2192
+ [
2193
+ "failed get network key info",
2194
+ () => {
2195
+ mockEzspGetNetworkKeyInfo.mockResolvedValueOnce([SLStatus.FAIL, {}]);
2196
+ },
2197
+ "[BACKUP] Failed to get network keys info with status=FAIL.",
2198
+ ],
2199
+ // [
2200
+ // 'failed get TC APS key info',
2201
+ // () => {
2202
+ // mockEzspGetNetworkKeyInfo.mockResolvedValueOnce([SLStatus.FAIL, {}]);
2203
+ // },
2204
+ // `[BACKUP] Failed to get TC APS key info with status=FAIL.`,
2205
+ // ],
2206
+ [
2207
+ "no network key set",
2208
+ () => {
2209
+ mockEzspGetNetworkKeyInfo.mockResolvedValueOnce([
2210
+ SLStatus.OK,
2211
+ {
2212
+ networkKeySet: false,
2213
+ alternateNetworkKeySet: false,
2214
+ networkKeySequenceNumber: 123,
2215
+ altNetworkKeySequenceNumber: 0,
2216
+ networkKeyFrameCounter: 456,
2217
+ } as SecManNetworkKeyInfo,
2218
+ ]);
2219
+ },
2220
+ "[BACKUP] No network key set.",
2221
+ ],
2222
+ [
2223
+ "failed export TC link key",
2224
+ () => {
2225
+ mockEzspExportKey.mockResolvedValueOnce([SLStatus.FAIL, {}]);
2226
+ },
2227
+ "[BACKUP] Failed to export TC Link Key with status=FAIL.",
2228
+ ],
2229
+ [
2230
+ "failed export network key",
2231
+ () => {
2232
+ mockEzspExportKey
2233
+ .mockResolvedValueOnce([
2234
+ SLStatus.OK,
2235
+ {contents: Buffer.from(DEFAULT_BACKUP.stack_specific!.ezsp!.hashed_tclk!, "hex")} as SecManKey,
2236
+ ])
2237
+ .mockResolvedValueOnce([SLStatus.FAIL, {}]);
2238
+ },
2239
+ "[BACKUP] Failed to export Network Key with status=FAIL.",
2240
+ ],
2241
+ ])("Adapter impl: throws when backup fails due to %s", async (_command, setup, error) => {
2242
+ setup();
2243
+
2244
+ await expect(adapter.backup([])).rejects.toThrow(error);
2245
+ });
2246
+
2247
+ it("Adapter impl: getNetworkParameters from cache", async () => {
2248
+ await expect(adapter.getNetworkParameters()).resolves.toStrictEqual({
2249
+ panID: DEFAULT_NETWORK_OPTIONS.panID,
2250
+ extendedPanID: ZSpec.Utils.eui64LEBufferToHex(Buffer.from(DEFAULT_NETWORK_OPTIONS.extendedPanID!)),
2251
+ channel: DEFAULT_NETWORK_OPTIONS.channelList[0],
2252
+ nwkUpdateID: 0,
2253
+ } as TsType.NetworkParameters);
2254
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(0);
2255
+ });
2256
+
2257
+ it("Adapter impl: getNetworkParameters from NCP", async () => {
2258
+ adapter.clearNetworkCache();
2259
+
2260
+ await expect(adapter.getNetworkParameters()).resolves.toStrictEqual({
2261
+ panID: DEFAULT_NETWORK_OPTIONS.panID,
2262
+ extendedPanID: ZSpec.Utils.eui64LEBufferToHex(Buffer.from(DEFAULT_NETWORK_OPTIONS.extendedPanID!)),
2263
+ channel: DEFAULT_NETWORK_OPTIONS.channelList[0],
2264
+ nwkUpdateID: 0,
2265
+ } as TsType.NetworkParameters);
2266
+ expect(mockEzspGetNetworkParameters).toHaveBeenCalledTimes(1);
2267
+ });
2268
+
2269
+ it("Adapter impl: addInstallCode", async () => {
2270
+ await expect(
2271
+ adapter.addInstallCode("0x1122334455667788", Buffer.from("DD7ED5CDAA8E2C708B67D2B1573DB6843A5F", "hex"), false),
2272
+ ).resolves.toStrictEqual(undefined);
2273
+ expect(mockEzspImportTransientKey).toHaveBeenCalledTimes(1);
2274
+ expect(loggerSpies.debug).toHaveBeenCalledWith(`[ADD INSTALL CODE] Success for '0x1122334455667788'.`, "zh:ember");
2275
+ });
2276
+
2277
+ it("Adapter impl: throw when addInstallCode fails import transient key", async () => {
2278
+ mockEzspImportTransientKey.mockResolvedValueOnce(SLStatus.FAIL);
2279
+
2280
+ await expect(adapter.addInstallCode("0x1122334455667788", Buffer.alloc(16), true)).rejects.toThrow(
2281
+ `[ADD INSTALL CODE] Failed for '0x1122334455667788' with status=FAIL.`,
2282
+ );
2283
+ expect(mockEzspImportTransientKey).toHaveBeenCalledTimes(1);
2284
+ });
2285
+
2286
+ it("Adapter impl: waitFor", () => {
2287
+ const waiter = adapter.waitFor(1234, 1, Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, 10, 0, 1, 15000);
2288
+ const spyCancel = vi.spyOn(waiter, "cancel");
2289
+
2290
+ expect(typeof waiter.cancel).toStrictEqual("function");
2291
+ expect(waiter.promise).toBeDefined();
2292
+
2293
+ waiter.cancel();
2294
+
2295
+ expect(spyCancel).toHaveReturned();
2296
+ });
2297
+
2298
+ it("Adapter impl: permitJoin on all", async () => {
2299
+ const spyResolveEvent = vi.spyOn(
2300
+ // @ts-expect-error private
2301
+ adapter.oneWaitress,
2302
+ "resolveEvent",
2303
+ );
2304
+
2305
+ await adapter.permitJoin(250);
2306
+ await vi.advanceTimersByTimeAsync(1000);
2307
+ expect(mockEzspPermitJoining).toHaveBeenCalledWith(250);
2308
+ expect(mockEzspSendBroadcast).toHaveBeenCalledTimes(1);
2309
+ expect(spyResolveEvent).toHaveBeenCalledWith(OneWaitressEvents.STACK_STATUS_NETWORK_OPENED);
2310
+
2311
+ await adapter.permitJoin(0);
2312
+ await vi.advanceTimersByTimeAsync(1000);
2313
+ expect(mockEzspPermitJoining).toHaveBeenCalledWith(0);
2314
+ expect(mockEzspSendBroadcast).toHaveBeenCalledTimes(2);
2315
+ expect(spyResolveEvent).toHaveBeenCalledWith(OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
2316
+
2317
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(
2318
+ 1,
2319
+ EzspPolicyId.TRUST_CENTER_POLICY,
2320
+ EzspDecisionBitmask.ALLOW_JOINS | EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS,
2321
+ );
2322
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(2, EzspPolicyId.TRUST_CENTER_POLICY, EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS);
2323
+ });
2324
+
2325
+ it("Adapter impl: permitJoin on coordinator", async () => {
2326
+ const spyResolveEvent = vi.spyOn(
2327
+ // @ts-expect-error private
2328
+ adapter.oneWaitress,
2329
+ "resolveEvent",
2330
+ );
2331
+
2332
+ await adapter.permitJoin(250, ZSpec.COORDINATOR_ADDRESS);
2333
+ await vi.advanceTimersByTimeAsync(1000);
2334
+ expect(mockEzspPermitJoining).toHaveBeenCalledWith(250);
2335
+ expect(mockEzspSendBroadcast).toHaveBeenCalledTimes(0);
2336
+ expect(spyResolveEvent).toHaveBeenCalledWith(OneWaitressEvents.STACK_STATUS_NETWORK_OPENED);
2337
+
2338
+ await adapter.permitJoin(0, ZSpec.COORDINATOR_ADDRESS);
2339
+ await vi.advanceTimersByTimeAsync(1000);
2340
+ expect(mockEzspPermitJoining).toHaveBeenCalledWith(0);
2341
+ expect(mockEzspSendBroadcast).toHaveBeenCalledTimes(0);
2342
+ expect(spyResolveEvent).toHaveBeenCalledWith(OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
2343
+
2344
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(
2345
+ 1,
2346
+ EzspPolicyId.TRUST_CENTER_POLICY,
2347
+ EzspDecisionBitmask.ALLOW_JOINS | EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS,
2348
+ );
2349
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(2, EzspPolicyId.TRUST_CENTER_POLICY, EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS);
2350
+ });
2351
+
2352
+ it("Adapter impl: permitJoin on router", async () => {
2353
+ const spyResolveZDO = vi.spyOn(
2354
+ // @ts-expect-error private
2355
+ adapter.oneWaitress,
2356
+ "resolveZDO",
2357
+ );
2358
+ const sender = 1234;
2359
+ const apsFrame: EmberApsFrame = {
2360
+ profileId: Zdo.ZDO_PROFILE_ID,
2361
+ clusterId: Zdo.ClusterId.PERMIT_JOINING_RESPONSE,
2362
+ sourceEndpoint: Zdo.ZDO_ENDPOINT,
2363
+ destinationEndpoint: Zdo.ZDO_ENDPOINT,
2364
+ options: 0,
2365
+ groupId: 0,
2366
+ sequence: 0,
2367
+ };
2368
+ const emitResponse = () => {
2369
+ setTimeout(async () => {
2370
+ mockEzspEmitter.emit("zdoResponse", apsFrame, sender, Buffer.from([1, Zdo.Status.SUCCESS]));
2371
+ await flushPromises();
2372
+ }, 300);
2373
+
2374
+ return [SLStatus.OK, ++mockAPSSequence];
2375
+ };
2376
+
2377
+ mockEzspSendUnicast.mockImplementationOnce(emitResponse).mockImplementationOnce(emitResponse);
2378
+
2379
+ const zdoResponse = [Zdo.Status.SUCCESS, undefined];
2380
+ let p = adapter.permitJoin(250, sender);
2381
+ await vi.advanceTimersByTimeAsync(1000);
2382
+ await p;
2383
+ expect(mockEzspSendUnicast).toHaveBeenCalledTimes(1);
2384
+ expect(spyResolveZDO).toHaveBeenCalledTimes(1);
2385
+ expect(spyResolveZDO).toHaveBeenCalledWith(sender, apsFrame, zdoResponse);
2386
+
2387
+ p = adapter.permitJoin(0, sender);
2388
+ await vi.advanceTimersByTimeAsync(1000);
2389
+ await p;
2390
+ expect(mockEzspSendUnicast).toHaveBeenCalledTimes(2);
2391
+ expect(spyResolveZDO).toHaveBeenCalledTimes(2);
2392
+ expect(spyResolveZDO).toHaveBeenCalledWith(sender, apsFrame, zdoResponse);
2393
+
2394
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(
2395
+ 1,
2396
+ EzspPolicyId.TRUST_CENTER_POLICY,
2397
+ EzspDecisionBitmask.ALLOW_JOINS | EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS,
2398
+ );
2399
+ expect(mockEzspSetPolicy).toHaveBeenNthCalledWith(2, EzspPolicyId.TRUST_CENTER_POLICY, EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS);
2400
+ });
2401
+
2402
+ it("Adapter impl: permitJoin restores temp manufacturer code", async () => {
2403
+ const spyResolveEvent = vi.spyOn(
2404
+ // @ts-expect-error private
2405
+ adapter.oneWaitress,
2406
+ "resolveEvent",
2407
+ );
2408
+
2409
+ const newNodeId: NodeId = 1234;
2410
+ const newNodeEui64: Eui64 = "0x54ef44ffeebbccaa";
2411
+ const status: EmberDeviceUpdate = EmberDeviceUpdate.STANDARD_SECURITY_UNSECURED_JOIN;
2412
+ const policyDecision: EmberJoinDecision = EmberJoinDecision.USE_PRECONFIGURED_KEY;
2413
+ const parentOfNewNodeId: NodeId = 4321;
2414
+
2415
+ mockEzspEmitter.emit("trustCenterJoin", newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId);
2416
+ await flushPromises();
2417
+
2418
+ expect(mockEzspSetManufacturerCode).toHaveBeenCalledWith(Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN);
2419
+ expect(mockManufCode).toStrictEqual(Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN);
2420
+
2421
+ await adapter.permitJoin(0, ZSpec.COORDINATOR_ADDRESS);
2422
+ await vi.advanceTimersByTimeAsync(1000);
2423
+ expect(mockEzspPermitJoining).toHaveBeenCalledWith(0);
2424
+ expect(mockEzspSendBroadcast).toHaveBeenCalledTimes(0);
2425
+ expect(spyResolveEvent).toHaveBeenCalledWith(OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
2426
+ expect(mockEzspSetManufacturerCode).toHaveBeenCalledWith(Zcl.ManufacturerCode.SILICON_LABORATORIES);
2427
+ expect(mockManufCode).toStrictEqual(Zcl.ManufacturerCode.SILICON_LABORATORIES);
2428
+ });
2429
+
2430
+ it("Adapter impl: throws when permitJoin request on coordinator fails", async () => {
2431
+ mockEzspPermitJoining.mockResolvedValueOnce(SLStatus.FAIL);
2432
+
2433
+ await expect(adapter.permitJoin(250, 0)).rejects.toThrow("[ZDO] Failed coordinator permit joining request with status=FAIL.");
2434
+ });
2435
+
2436
+ it("Adapter impl: throws when permitJoin broadcast request fails", async () => {
2437
+ mockEzspSendBroadcast.mockResolvedValueOnce([SLStatus.FAIL, 0]);
2438
+
2439
+ await expect(defuseRejection(adapter.permitJoin(250, undefined))).rejects.toThrow(
2440
+ "~x~> [ZDO PERMIT_JOINING_REQUEST BROADCAST to=65532 messageTag=1] Failed to send request with status=FAIL.",
2441
+ );
2442
+ });
2443
+
2444
+ it("Adapter impl: resolves undefined when permitJoin on router fails due to failed ZDO status", async () => {
2445
+ const spyResolveZDO = vi.spyOn(
2446
+ // @ts-expect-error private
2447
+ adapter.oneWaitress,
2448
+ "resolveZDO",
2449
+ );
2450
+ const sender = 1234;
2451
+ const apsFrame: EmberApsFrame = {
2452
+ profileId: Zdo.ZDO_PROFILE_ID,
2453
+ clusterId: Zdo.ClusterId.PERMIT_JOINING_RESPONSE,
2454
+ sourceEndpoint: Zdo.ZDO_ENDPOINT,
2455
+ destinationEndpoint: Zdo.ZDO_ENDPOINT,
2456
+ options: 0,
2457
+ groupId: 0,
2458
+ sequence: 0,
2459
+ };
2460
+
2461
+ mockEzspEmitter.emit("zdoResponse", apsFrame, sender, Buffer.from([1, Zdo.Status.NOT_AUTHORIZED]));
2462
+ await flushPromises();
2463
+
2464
+ const zdoResponse = [Zdo.Status.NOT_AUTHORIZED, undefined];
2465
+ expect(spyResolveZDO).toHaveBeenCalledTimes(1);
2466
+ expect(spyResolveZDO).toHaveBeenCalledWith(sender, apsFrame, zdoResponse);
2467
+ });
2468
+
2469
+ it("Adapter impl: throws when permitJoin request on router fails", async () => {
2470
+ mockEzspSendUnicast.mockResolvedValueOnce([SLStatus.FAIL, 0]);
2471
+
2472
+ await expect(adapter.permitJoin(250, 1234)).rejects.toThrow(
2473
+ "~x~> [ZDO PERMIT_JOINING_REQUEST UNICAST to=0xffffffffffffffff:1234 messageTag=1] Failed to send request with status=FAIL.",
2474
+ );
2475
+ });
2476
+
2477
+ it("Adapter impl: throws when permitJoin fails to import ZIGBEE_PROFILE_INTEROPERABILITY_LINK_KEY", async () => {
2478
+ mockEzspImportTransientKey.mockResolvedValueOnce(SLStatus.FAIL);
2479
+
2480
+ await expect(adapter.permitJoin(250)).rejects.toThrow("[ZDO] Failed import transient key with status=FAIL.");
2481
+ });
2482
+
2483
+ it("Adapter impl: throws when permitJoin fails to set TC policy", async () => {
2484
+ mockEzspSetPolicy.mockResolvedValueOnce(SLStatus.FAIL);
2485
+
2486
+ await expect(adapter.permitJoin(250)).rejects.toThrow("[ZDO] Failed set join policy with status=FAIL.");
2487
+ });
2488
+
2489
+ it("Adapter impl: throws when stop permitJoin fails to restore TC policy", async () => {
2490
+ mockEzspSetPolicy.mockResolvedValueOnce(SLStatus.FAIL);
2491
+
2492
+ await expect(adapter.permitJoin(0)).rejects.toThrow("[ZDO] Failed set join policy with status=FAIL.");
2493
+ });
2494
+
2495
+ it("Adapter impl: sendZclFrameToEndpoint with command response with fixed source endpoint", async () => {
2496
+ const networkAddress: NodeId = 1234;
2497
+ const endpoint: number = 1;
2498
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2499
+ const zclFrame = Zcl.Frame.create(
2500
+ Zcl.FrameType.GLOBAL,
2501
+ Zcl.Direction.CLIENT_TO_SERVER,
2502
+ true,
2503
+ undefined,
2504
+ 3,
2505
+ "read",
2506
+ "genBasic",
2507
+ [{attrId: 0}],
2508
+ {},
2509
+ );
2510
+ const apsFrame: EmberApsFrame = {
2511
+ profileId: FIXED_ENDPOINTS[0].profileId,
2512
+ clusterId: zclFrame.cluster.ID,
2513
+ sourceEndpoint,
2514
+ destinationEndpoint: endpoint,
2515
+ options: DEFAULT_APS_OPTIONS,
2516
+ groupId: 0,
2517
+ sequence: 0, // set by stack
2518
+ };
2519
+ const lastHopLqi: number = 234;
2520
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
2521
+ const messageContents = Buffer.from("1803010000002003", "hex");
2522
+
2523
+ mockEzspSend.mockImplementationOnce(() => {
2524
+ setTimeout(async () => {
2525
+ mockEzspEmitter.emit(
2526
+ "incomingMessage",
2527
+ EmberIncomingMessageType.UNICAST,
2528
+ reverseApsFrame(apsFrame),
2529
+ lastHopLqi,
2530
+ networkAddress,
2531
+ messageContents,
2532
+ );
2533
+ await flushPromises();
2534
+ }, 300);
2535
+
2536
+ return [SLStatus.OK, ++mockAPSSequence];
2537
+ });
2538
+
2539
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false, sourceEndpoint);
2540
+
2541
+ await vi.advanceTimersByTimeAsync(5000);
2542
+ await expect(p).resolves.toStrictEqual({
2543
+ clusterID: apsFrame.clusterId,
2544
+ header: Zcl.Header.fromBuffer(messageContents),
2545
+ address: networkAddress,
2546
+ data: messageContents,
2547
+ endpoint: apsFrame.destinationEndpoint,
2548
+ linkquality: lastHopLqi,
2549
+ groupID: apsFrame.groupId,
2550
+ wasBroadcast: false,
2551
+ destinationEndpoint: apsFrame.sourceEndpoint,
2552
+ } as ZclPayload);
2553
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2554
+ });
2555
+
2556
+ it("Adapter impl: sendZclFrameToEndpoint with command response with other source endpoint", async () => {
2557
+ const networkAddress: NodeId = 1234;
2558
+ const endpoint: number = 1;
2559
+ const sourceEndpoint = 3;
2560
+ const zclFrame = Zcl.Frame.create(
2561
+ Zcl.FrameType.GLOBAL,
2562
+ Zcl.Direction.CLIENT_TO_SERVER,
2563
+ true,
2564
+ undefined,
2565
+ 3,
2566
+ "read",
2567
+ "genBasic",
2568
+ [{attrId: 0}],
2569
+ {},
2570
+ );
2571
+ const apsFrame: EmberApsFrame = {
2572
+ profileId: FIXED_ENDPOINTS[0].profileId,
2573
+ clusterId: zclFrame.cluster.ID,
2574
+ sourceEndpoint,
2575
+ destinationEndpoint: endpoint,
2576
+ options: DEFAULT_APS_OPTIONS,
2577
+ groupId: 0,
2578
+ sequence: 0, // set by stack
2579
+ };
2580
+ const lastHopLqi: number = 234;
2581
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
2582
+ const messageContents = Buffer.from("1803010000002003", "hex");
2583
+
2584
+ mockEzspSend.mockImplementationOnce(() => {
2585
+ setTimeout(async () => {
2586
+ mockEzspEmitter.emit(
2587
+ "incomingMessage",
2588
+ EmberIncomingMessageType.UNICAST,
2589
+ reverseApsFrame(apsFrame),
2590
+ lastHopLqi,
2591
+ networkAddress,
2592
+ messageContents,
2593
+ );
2594
+ await flushPromises();
2595
+ }, 300);
2596
+
2597
+ return [SLStatus.OK, ++mockAPSSequence];
2598
+ });
2599
+
2600
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false, sourceEndpoint);
2601
+
2602
+ await vi.advanceTimersByTimeAsync(5000);
2603
+ await expect(p).resolves.toStrictEqual({
2604
+ clusterID: apsFrame.clusterId,
2605
+ header: Zcl.Header.fromBuffer(messageContents),
2606
+ address: networkAddress,
2607
+ data: messageContents,
2608
+ endpoint: apsFrame.destinationEndpoint,
2609
+ linkquality: lastHopLqi,
2610
+ groupID: apsFrame.groupId,
2611
+ wasBroadcast: false,
2612
+ destinationEndpoint: apsFrame.sourceEndpoint,
2613
+ } as ZclPayload);
2614
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2615
+ });
2616
+
2617
+ it("Adapter impl: sendZclFrameToEndpoint with command response with no source endpoint", async () => {
2618
+ const networkAddress: NodeId = 1234;
2619
+ const endpoint: number = 1;
2620
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2621
+ const zclFrame = Zcl.Frame.create(
2622
+ Zcl.FrameType.GLOBAL,
2623
+ Zcl.Direction.CLIENT_TO_SERVER,
2624
+ true,
2625
+ undefined,
2626
+ 3,
2627
+ "read",
2628
+ "genBasic",
2629
+ [{attrId: 0}],
2630
+ {},
2631
+ );
2632
+ const apsFrame: EmberApsFrame = {
2633
+ profileId: FIXED_ENDPOINTS[0].profileId,
2634
+ clusterId: zclFrame.cluster.ID,
2635
+ sourceEndpoint,
2636
+ destinationEndpoint: endpoint,
2637
+ options: DEFAULT_APS_OPTIONS,
2638
+ groupId: 0,
2639
+ sequence: 0, // set by stack
2640
+ };
2641
+ const lastHopLqi: number = 234;
2642
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
2643
+ const messageContents = Buffer.from("1803010000002003", "hex");
2644
+
2645
+ mockEzspSend.mockImplementationOnce(() => {
2646
+ setTimeout(async () => {
2647
+ mockEzspEmitter.emit(
2648
+ "incomingMessage",
2649
+ EmberIncomingMessageType.UNICAST,
2650
+ reverseApsFrame(apsFrame),
2651
+ lastHopLqi,
2652
+ networkAddress,
2653
+ messageContents,
2654
+ );
2655
+ await flushPromises();
2656
+ }, 300);
2657
+
2658
+ return [SLStatus.OK, ++mockAPSSequence];
2659
+ });
2660
+
2661
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false);
2662
+
2663
+ await vi.advanceTimersByTimeAsync(5000);
2664
+ await expect(p).resolves.toStrictEqual({
2665
+ clusterID: apsFrame.clusterId,
2666
+ header: Zcl.Header.fromBuffer(messageContents),
2667
+ address: networkAddress,
2668
+ data: messageContents,
2669
+ endpoint: apsFrame.destinationEndpoint,
2670
+ linkquality: lastHopLqi,
2671
+ groupID: apsFrame.groupId,
2672
+ wasBroadcast: false,
2673
+ destinationEndpoint: apsFrame.sourceEndpoint,
2674
+ } as ZclPayload);
2675
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2676
+ });
2677
+
2678
+ it.each([
2679
+ ["NO_TX_SPACE", EzspStatus.NO_TX_SPACE],
2680
+ ["NOT_CONNECTED", EzspStatus.NOT_CONNECTED],
2681
+ ])("Adapter impl: recovers when sendZclFrameToEndpoint throws %s status", async (_statusName, status) => {
2682
+ const networkAddress: NodeId = 1234;
2683
+ const endpoint: number = 1;
2684
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2685
+ const zclFrame = Zcl.Frame.create(
2686
+ Zcl.FrameType.GLOBAL,
2687
+ Zcl.Direction.CLIENT_TO_SERVER,
2688
+ true,
2689
+ undefined,
2690
+ 3,
2691
+ "read",
2692
+ "genBasic",
2693
+ [{attrId: 0}],
2694
+ {},
2695
+ );
2696
+ const apsFrame: EmberApsFrame = {
2697
+ profileId: FIXED_ENDPOINTS[0].profileId,
2698
+ clusterId: zclFrame.cluster.ID,
2699
+ sourceEndpoint,
2700
+ destinationEndpoint: endpoint,
2701
+ options: DEFAULT_APS_OPTIONS,
2702
+ groupId: 0,
2703
+ sequence: 0, // set by stack
2704
+ };
2705
+ const lastHopLqi: number = 234;
2706
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
2707
+ const messageContents = Buffer.from("1803010000002003", "hex");
2708
+
2709
+ mockEzspSend.mockRejectedValueOnce(new EzspError(status)).mockImplementationOnce(() => {
2710
+ setTimeout(async () => {
2711
+ mockEzspEmitter.emit(
2712
+ "incomingMessage",
2713
+ EmberIncomingMessageType.UNICAST,
2714
+ reverseApsFrame(apsFrame),
2715
+ lastHopLqi,
2716
+ networkAddress,
2717
+ messageContents,
2718
+ );
2719
+ await flushPromises();
2720
+ }, 300);
2721
+
2722
+ return [SLStatus.OK, ++mockAPSSequence];
2723
+ });
2724
+
2725
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false, sourceEndpoint);
2726
+
2727
+ await vi.advanceTimersByTimeAsync(10000);
2728
+ await expect(p).resolves.toStrictEqual({
2729
+ clusterID: apsFrame.clusterId,
2730
+ header: Zcl.Header.fromBuffer(messageContents),
2731
+ address: networkAddress,
2732
+ data: messageContents,
2733
+ endpoint: apsFrame.destinationEndpoint,
2734
+ linkquality: lastHopLqi,
2735
+ groupID: apsFrame.groupId,
2736
+ wasBroadcast: false,
2737
+ destinationEndpoint: apsFrame.sourceEndpoint,
2738
+ } as ZclPayload);
2739
+ expect(mockEzspSend).toHaveBeenCalledTimes(2);
2740
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2741
+ });
2742
+
2743
+ it.each([
2744
+ ["ZIGBEE_MAX_MESSAGE_LIMIT_REACHED", SLStatus.ZIGBEE_MAX_MESSAGE_LIMIT_REACHED],
2745
+ ["BUSY", SLStatus.BUSY],
2746
+ ["NETWORK_DOWN", SLStatus.NETWORK_DOWN],
2747
+ ])("Adapter impl: recovers when sendZclFrameToEndpoint get %s status from NCP", async (_statusName, status) => {
2748
+ const networkAddress: NodeId = 1234;
2749
+ const endpoint: number = 1;
2750
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2751
+ const zclFrame = Zcl.Frame.create(
2752
+ Zcl.FrameType.GLOBAL,
2753
+ Zcl.Direction.CLIENT_TO_SERVER,
2754
+ true,
2755
+ undefined,
2756
+ 3,
2757
+ "read",
2758
+ "genBasic",
2759
+ [{attrId: 0}],
2760
+ {},
2761
+ );
2762
+ const apsFrame: EmberApsFrame = {
2763
+ profileId: FIXED_ENDPOINTS[0].profileId,
2764
+ clusterId: zclFrame.cluster.ID,
2765
+ sourceEndpoint,
2766
+ destinationEndpoint: endpoint,
2767
+ options: DEFAULT_APS_OPTIONS,
2768
+ groupId: 0,
2769
+ sequence: 0, // set by stack
2770
+ };
2771
+ const lastHopLqi: number = 234;
2772
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
2773
+ const messageContents = Buffer.from("1803010000002003", "hex");
2774
+
2775
+ mockEzspSend.mockResolvedValueOnce([status, 0]).mockImplementationOnce(() => {
2776
+ setTimeout(async () => {
2777
+ mockEzspEmitter.emit(
2778
+ "incomingMessage",
2779
+ EmberIncomingMessageType.UNICAST,
2780
+ reverseApsFrame(apsFrame),
2781
+ lastHopLqi,
2782
+ networkAddress,
2783
+ messageContents,
2784
+ );
2785
+ await flushPromises();
2786
+ }, 300);
2787
+
2788
+ return [SLStatus.OK, ++mockAPSSequence];
2789
+ });
2790
+
2791
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false, sourceEndpoint);
2792
+
2793
+ await vi.advanceTimersByTimeAsync(10000);
2794
+ await expect(p).resolves.toStrictEqual({
2795
+ clusterID: apsFrame.clusterId,
2796
+ header: Zcl.Header.fromBuffer(messageContents),
2797
+ address: networkAddress,
2798
+ data: messageContents,
2799
+ endpoint: apsFrame.destinationEndpoint,
2800
+ linkquality: lastHopLqi,
2801
+ groupID: apsFrame.groupId,
2802
+ wasBroadcast: false,
2803
+ destinationEndpoint: apsFrame.sourceEndpoint,
2804
+ } as ZclPayload);
2805
+ expect(mockEzspSend).toHaveBeenCalledTimes(2);
2806
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2807
+ });
2808
+
2809
+ it("Adapter impl: throws when sendZclFrameToEndpoint throws NO_TX_SPACE status and recovery disabled", async () => {
2810
+ const networkAddress: NodeId = 1234;
2811
+ const endpoint: number = 1;
2812
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2813
+ const zclFrame = Zcl.Frame.create(
2814
+ Zcl.FrameType.GLOBAL,
2815
+ Zcl.Direction.CLIENT_TO_SERVER,
2816
+ true,
2817
+ undefined,
2818
+ 3,
2819
+ "read",
2820
+ "genBasic",
2821
+ [{attrId: 0}],
2822
+ {},
2823
+ );
2824
+ const apsFrame: EmberApsFrame = {
2825
+ profileId: FIXED_ENDPOINTS[0].profileId,
2826
+ clusterId: zclFrame.cluster.ID,
2827
+ sourceEndpoint,
2828
+ destinationEndpoint: endpoint,
2829
+ options: DEFAULT_APS_OPTIONS,
2830
+ groupId: 0,
2831
+ sequence: 0, // set by stack
2832
+ };
2833
+
2834
+ mockEzspSend.mockRejectedValueOnce(new EzspError(EzspStatus.NO_TX_SPACE));
2835
+
2836
+ const p = defuseRejection(
2837
+ adapter.sendZclFrameToEndpoint(
2838
+ "0x1122334455667788",
2839
+ networkAddress,
2840
+ endpoint,
2841
+ zclFrame,
2842
+ 10000,
2843
+ false,
2844
+ true, // disable recovery
2845
+ sourceEndpoint,
2846
+ ),
2847
+ );
2848
+
2849
+ await vi.advanceTimersByTimeAsync(10000);
2850
+ await expect(p).rejects.toThrow(
2851
+ `~x~> [ZCL to=0x1122334455667788:1234 apsFrame={"profileId":260,"clusterId":0,"sourceEndpoint":1,"destinationEndpoint":1,"options":4416,"groupId":0,"sequence":0}] Failed to send request with status=${SLStatus[SLStatus.BUSY]}.`,
2852
+ );
2853
+ expect(mockEzspSend).toHaveBeenCalledTimes(1);
2854
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2855
+ });
2856
+
2857
+ it("Adapter impl: throws when sendZclFrameToEndpoint get BUSY status from NCP and recovery disabled", async () => {
2858
+ const networkAddress: NodeId = 1234;
2859
+ const endpoint: number = 1;
2860
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2861
+ const zclFrame = Zcl.Frame.create(
2862
+ Zcl.FrameType.GLOBAL,
2863
+ Zcl.Direction.CLIENT_TO_SERVER,
2864
+ true,
2865
+ undefined,
2866
+ 3,
2867
+ "read",
2868
+ "genBasic",
2869
+ [{attrId: 0}],
2870
+ {},
2871
+ );
2872
+ const apsFrame: EmberApsFrame = {
2873
+ profileId: FIXED_ENDPOINTS[0].profileId,
2874
+ clusterId: zclFrame.cluster.ID,
2875
+ sourceEndpoint,
2876
+ destinationEndpoint: endpoint,
2877
+ options: DEFAULT_APS_OPTIONS,
2878
+ groupId: 0,
2879
+ sequence: 0, // set by stack
2880
+ };
2881
+
2882
+ mockEzspSend.mockResolvedValueOnce([SLStatus.BUSY, 0]);
2883
+
2884
+ const p = defuseRejection(
2885
+ adapter.sendZclFrameToEndpoint(
2886
+ "0x1122334455667788",
2887
+ networkAddress,
2888
+ endpoint,
2889
+ zclFrame,
2890
+ 10000,
2891
+ false,
2892
+ true, // disable recovery
2893
+ sourceEndpoint,
2894
+ ),
2895
+ );
2896
+
2897
+ await vi.advanceTimersByTimeAsync(10000);
2898
+ await expect(p).rejects.toThrow(
2899
+ `~x~> [ZCL to=0x1122334455667788:1234 apsFrame={"profileId":260,"clusterId":0,"sourceEndpoint":1,"destinationEndpoint":1,"options":4416,"groupId":0,"sequence":0}] Failed to send request with status=${SLStatus[SLStatus.BUSY]}.`,
2900
+ );
2901
+ expect(mockEzspSend).toHaveBeenCalledTimes(1);
2902
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2903
+ });
2904
+
2905
+ it("Adapter impl: throws when sendZclFrameToEndpoint get BUSY status from NCP and exceeded max attempts", async () => {
2906
+ const networkAddress: NodeId = 1234;
2907
+ const endpoint: number = 1;
2908
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2909
+ const zclFrame = Zcl.Frame.create(
2910
+ Zcl.FrameType.GLOBAL,
2911
+ Zcl.Direction.CLIENT_TO_SERVER,
2912
+ true,
2913
+ undefined,
2914
+ 3,
2915
+ "read",
2916
+ "genBasic",
2917
+ [{attrId: 0}],
2918
+ {},
2919
+ );
2920
+ const apsFrame: EmberApsFrame = {
2921
+ profileId: FIXED_ENDPOINTS[0].profileId,
2922
+ clusterId: zclFrame.cluster.ID,
2923
+ sourceEndpoint,
2924
+ destinationEndpoint: endpoint,
2925
+ options: DEFAULT_APS_OPTIONS,
2926
+ groupId: 0,
2927
+ sequence: 0, // set by stack
2928
+ };
2929
+
2930
+ mockEzspSend
2931
+ .mockResolvedValueOnce([SLStatus.BUSY, 0])
2932
+ .mockResolvedValueOnce([SLStatus.BUSY, 0])
2933
+ .mockResolvedValueOnce([SLStatus.BUSY, 0]);
2934
+
2935
+ const p = defuseRejection(
2936
+ adapter.sendZclFrameToEndpoint(
2937
+ "0x1122334455667788",
2938
+ networkAddress,
2939
+ endpoint,
2940
+ zclFrame,
2941
+ 10000,
2942
+ false,
2943
+ false, // disable recovery
2944
+ sourceEndpoint,
2945
+ ),
2946
+ );
2947
+
2948
+ await vi.advanceTimersByTimeAsync(10000);
2949
+ await expect(p).rejects.toThrow(
2950
+ `~x~> [ZCL to=0x1122334455667788:1234 apsFrame={"profileId":260,"clusterId":0,"sourceEndpoint":1,"destinationEndpoint":1,"options":4416,"groupId":0,"sequence":0}] Failed to send request with status=${SLStatus[SLStatus.BUSY]}.`,
2951
+ );
2952
+ expect(mockEzspSend).toHaveBeenCalledTimes(3);
2953
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
2954
+ });
2955
+
2956
+ it("Adapter impl: throws when sendZclFrameToEndpoint request fails", async () => {
2957
+ const networkAddress: NodeId = 1234;
2958
+ const endpoint: number = 1;
2959
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
2960
+ const zclFrame = Zcl.Frame.create(
2961
+ Zcl.FrameType.GLOBAL,
2962
+ Zcl.Direction.CLIENT_TO_SERVER,
2963
+ true,
2964
+ undefined,
2965
+ 3,
2966
+ "read",
2967
+ "genBasic",
2968
+ [{attrId: 0}],
2969
+ {},
2970
+ );
2971
+ const apsFrame: EmberApsFrame = {
2972
+ profileId: FIXED_ENDPOINTS[0].profileId,
2973
+ clusterId: zclFrame.cluster.ID,
2974
+ sourceEndpoint,
2975
+ destinationEndpoint: endpoint,
2976
+ options: DEFAULT_APS_OPTIONS,
2977
+ groupId: 0,
2978
+ sequence: 0, // set by stack
2979
+ };
2980
+
2981
+ mockEzspSend.mockResolvedValueOnce([SLStatus.FAIL, 0]);
2982
+
2983
+ const p = defuseRejection(
2984
+ adapter.sendZclFrameToEndpoint(
2985
+ "0x1122334455667788",
2986
+ networkAddress,
2987
+ endpoint,
2988
+ zclFrame,
2989
+ 10000,
2990
+ false,
2991
+ false, // disable recovery
2992
+ sourceEndpoint,
2993
+ ),
2994
+ );
2995
+
2996
+ await vi.advanceTimersByTimeAsync(10000);
2997
+ await expect(p).rejects.toThrow(
2998
+ `~x~> [ZCL to=0x1122334455667788:1234 apsFrame={"profileId":260,"clusterId":0,"sourceEndpoint":1,"destinationEndpoint":1,"options":4416,"groupId":0,"sequence":0}] Failed to send request with status=FAIL.`,
2999
+ );
3000
+ expect(mockEzspSend).toHaveBeenCalledTimes(1);
3001
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
3002
+ });
3003
+
3004
+ it("Adapter impl: sendZdo with EUI64", async () => {
3005
+ const sender: NodeId = 0x6789;
3006
+ const senderEUI64: Eui64 = "0x1122334455667788";
3007
+ const apsFrame: EmberApsFrame = {
3008
+ profileId: Zdo.ZDO_PROFILE_ID,
3009
+ clusterId: Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE,
3010
+ sourceEndpoint: Zdo.ZDO_ENDPOINT,
3011
+ destinationEndpoint: Zdo.ZDO_ENDPOINT,
3012
+ options: 0,
3013
+ groupId: 0,
3014
+ sequence: 0,
3015
+ };
3016
+
3017
+ mockEzspSendBroadcast.mockImplementationOnce(() => {
3018
+ setTimeout(async () => {
3019
+ mockEzspEmitter.emit(
3020
+ "zdoResponse",
3021
+ apsFrame,
3022
+ sender,
3023
+ Buffer.from([
3024
+ 1,
3025
+ Zdo.Status.SUCCESS,
3026
+ 0x88,
3027
+ 0x77,
3028
+ 0x66,
3029
+ 0x55,
3030
+ 0x44,
3031
+ 0x33,
3032
+ 0x22,
3033
+ 0x11,
3034
+ 0x89, // nwkAddress
3035
+ 0x67, // nwkAddress
3036
+ ]),
3037
+ );
3038
+ await flushPromises();
3039
+ }, 300);
3040
+
3041
+ return [SLStatus.OK, ++mockAPSSequence];
3042
+ });
3043
+
3044
+ const zdoPayload = Zdo.Buffalo.buildRequest(false, Zdo.ClusterId.NETWORK_ADDRESS_REQUEST, senderEUI64, false, 0);
3045
+ const p = adapter.sendZdo(
3046
+ senderEUI64,
3047
+ ZSpec.NULL_NODE_ID /* same as broadcast SLEEPY */,
3048
+ Zdo.ClusterId.NETWORK_ADDRESS_REQUEST,
3049
+ zdoPayload,
3050
+ false,
3051
+ );
3052
+
3053
+ await vi.advanceTimersByTimeAsync(1000);
3054
+ await expect(p).resolves.toStrictEqual([
3055
+ Zdo.Status.SUCCESS,
3056
+ {
3057
+ eui64: senderEUI64,
3058
+ nwkAddress: sender,
3059
+ startIndex: 0,
3060
+ assocDevList: [],
3061
+ } as ZdoTypes.NetworkAddressResponse,
3062
+ ]);
3063
+ });
3064
+
3065
+ it("Adapter impl: sendZclFrameToEndpoint with default response", async () => {
3066
+ const networkAddress: NodeId = 1234;
3067
+ const endpoint: number = 3;
3068
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
3069
+ const zclFrame = Zcl.Frame.create(
3070
+ Zcl.FrameType.GLOBAL,
3071
+ Zcl.Direction.CLIENT_TO_SERVER,
3072
+ false,
3073
+ undefined,
3074
+ 3,
3075
+ "read",
3076
+ "genBasic",
3077
+ [{attrId: 0}],
3078
+ {},
3079
+ );
3080
+ const apsFrame: EmberApsFrame = {
3081
+ profileId: FIXED_ENDPOINTS[0].profileId,
3082
+ clusterId: zclFrame.cluster.ID,
3083
+ sourceEndpoint,
3084
+ destinationEndpoint: endpoint,
3085
+ options: DEFAULT_APS_OPTIONS,
3086
+ groupId: 0,
3087
+ sequence: 0, // set by stack
3088
+ };
3089
+ const lastHopLqi: number = 234;
3090
+ // defaultRsp with cmdId=0, status=0
3091
+ const messageContents = Buffer.from("18030b0000", "hex");
3092
+
3093
+ mockEzspSend.mockImplementationOnce(() => {
3094
+ setTimeout(async () => {
3095
+ mockEzspEmitter.emit(
3096
+ "incomingMessage",
3097
+ EmberIncomingMessageType.UNICAST,
3098
+ reverseApsFrame(apsFrame),
3099
+ lastHopLqi,
3100
+ networkAddress,
3101
+ messageContents,
3102
+ );
3103
+ await flushPromises();
3104
+ }, 300);
3105
+
3106
+ return [SLStatus.OK, ++mockAPSSequence];
3107
+ });
3108
+
3109
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, true, false, sourceEndpoint);
3110
+
3111
+ await vi.advanceTimersByTimeAsync(5000);
3112
+ await expect(p).resolves.toStrictEqual({
3113
+ clusterID: apsFrame.clusterId,
3114
+ header: Zcl.Header.fromBuffer(messageContents),
3115
+ address: networkAddress,
3116
+ data: messageContents,
3117
+ endpoint: apsFrame.destinationEndpoint,
3118
+ linkquality: lastHopLqi,
3119
+ groupID: apsFrame.groupId,
3120
+ wasBroadcast: false,
3121
+ destinationEndpoint: apsFrame.sourceEndpoint,
3122
+ } as ZclPayload);
3123
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
3124
+ });
3125
+
3126
+ it("Adapter impl: sendZclFrameToEndpoint without response", async () => {
3127
+ const networkAddress: NodeId = 1234;
3128
+ const endpoint: number = 3;
3129
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
3130
+ const zclFrame = Zcl.Frame.create(
3131
+ Zcl.FrameType.GLOBAL,
3132
+ Zcl.Direction.CLIENT_TO_SERVER,
3133
+ true,
3134
+ undefined,
3135
+ 3,
3136
+ "read",
3137
+ "genBasic",
3138
+ [{attrId: 0}],
3139
+ {},
3140
+ );
3141
+
3142
+ const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, true, false, sourceEndpoint);
3143
+
3144
+ await vi.advanceTimersByTimeAsync(5000);
3145
+ await expect(p).resolves.toStrictEqual(undefined);
3146
+
3147
+ const apsFrame: EmberApsFrame = {
3148
+ profileId: FIXED_ENDPOINTS[0].profileId,
3149
+ clusterId: zclFrame.cluster.ID,
3150
+ sourceEndpoint,
3151
+ destinationEndpoint: endpoint,
3152
+ options: DEFAULT_APS_OPTIONS & ~EmberApsOption.RETRY,
3153
+ groupId: 0,
3154
+ sequence: 0, // set by stack
3155
+ };
3156
+
3157
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
3158
+ });
3159
+
3160
+ it("Adapter impl: sendZclFrameToGroup with source endpoint", async () => {
3161
+ const groupId: number = 32;
3162
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3163
+ const p = adapter.sendZclFrameToGroup(groupId, zclFrame, 2);
3164
+
3165
+ await vi.advanceTimersByTimeAsync(5000);
3166
+ await expect(p).resolves.toStrictEqual(undefined);
3167
+
3168
+ const apsFrame: EmberApsFrame = {
3169
+ profileId: FIXED_ENDPOINTS[0].profileId,
3170
+ clusterId: zclFrame.cluster.ID,
3171
+ sourceEndpoint: 2,
3172
+ destinationEndpoint: 0xff,
3173
+ options: DEFAULT_APS_OPTIONS,
3174
+ groupId,
3175
+ sequence: 0, // set by stack
3176
+ };
3177
+
3178
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.MULTICAST, groupId, apsFrame, zclFrame.toBuffer(), 0, 0);
3179
+ });
3180
+
3181
+ it("Adapter impl: sendZclFrameToGroup with default source endpoint", async () => {
3182
+ const groupId: number = 32;
3183
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3184
+ const p = adapter.sendZclFrameToGroup(groupId, zclFrame);
3185
+
3186
+ await vi.advanceTimersByTimeAsync(5000);
3187
+ await expect(p).resolves.toStrictEqual(undefined);
3188
+
3189
+ const apsFrame: EmberApsFrame = {
3190
+ profileId: FIXED_ENDPOINTS[0].profileId,
3191
+ clusterId: zclFrame.cluster.ID,
3192
+ sourceEndpoint: FIXED_ENDPOINTS[0].endpoint,
3193
+ destinationEndpoint: 0xff,
3194
+ options: DEFAULT_APS_OPTIONS,
3195
+ groupId,
3196
+ sequence: 0, // set by stack
3197
+ };
3198
+
3199
+ expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.MULTICAST, groupId, apsFrame, zclFrame.toBuffer(), 0, 0);
3200
+ });
3201
+
3202
+ it("Adapter impl: throws when sendZclFrameToGroup fails request", async () => {
3203
+ mockEzspSend.mockResolvedValueOnce([SLStatus.FAIL, 0]);
3204
+
3205
+ const groupId: number = 32;
3206
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3207
+ const p = defuseRejection(adapter.sendZclFrameToGroup(groupId, zclFrame, 1));
3208
+
3209
+ await vi.advanceTimersByTimeAsync(5000);
3210
+ await expect(p).rejects.toThrow("~x~> [ZCL GROUP groupId=32] Failed to send with status=FAIL.");
3211
+ expect(mockEzspSend).toHaveBeenCalledTimes(1);
3212
+ });
3213
+
3214
+ it("Adapter impl: sendZclFrameToAll with fixed endpoint", async () => {
3215
+ const endpoint: number = 32;
3216
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3217
+ const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
3218
+ const p = adapter.sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, ZSpec.BroadcastAddress.DEFAULT);
3219
+
3220
+ await vi.advanceTimersByTimeAsync(5000);
3221
+ await expect(p).resolves.toStrictEqual(undefined);
3222
+
3223
+ const apsFrame: EmberApsFrame = {
3224
+ profileId: FIXED_ENDPOINTS[0].profileId,
3225
+ clusterId: zclFrame.cluster.ID,
3226
+ sourceEndpoint,
3227
+ destinationEndpoint: endpoint,
3228
+ options: DEFAULT_APS_OPTIONS,
3229
+ groupId: ZSpec.BroadcastAddress.DEFAULT,
3230
+ sequence: 0, // set by stack
3231
+ };
3232
+
3233
+ expect(mockEzspSend).toHaveBeenCalledWith(
3234
+ EmberOutgoingMessageType.BROADCAST,
3235
+ ZSpec.BroadcastAddress.DEFAULT,
3236
+ apsFrame,
3237
+ zclFrame.toBuffer(),
3238
+ 0,
3239
+ 0,
3240
+ );
3241
+ });
3242
+
3243
+ it("Adapter impl: sendZclFrameToAll with other endpoint", async () => {
3244
+ const endpoint: number = 32;
3245
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3246
+ const sourceEndpoint = 3;
3247
+ const p = adapter.sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, ZSpec.BroadcastAddress.DEFAULT);
3248
+
3249
+ await vi.advanceTimersByTimeAsync(5000);
3250
+ await expect(p).resolves.toStrictEqual(undefined);
3251
+
3252
+ const apsFrame: EmberApsFrame = {
3253
+ profileId: FIXED_ENDPOINTS[0].profileId,
3254
+ clusterId: zclFrame.cluster.ID,
3255
+ sourceEndpoint,
3256
+ destinationEndpoint: endpoint,
3257
+ options: DEFAULT_APS_OPTIONS,
3258
+ groupId: ZSpec.BroadcastAddress.DEFAULT,
3259
+ sequence: 0, // set by stack
3260
+ };
3261
+
3262
+ expect(mockEzspSend).toHaveBeenCalledWith(
3263
+ EmberOutgoingMessageType.BROADCAST,
3264
+ ZSpec.BroadcastAddress.DEFAULT,
3265
+ apsFrame,
3266
+ zclFrame.toBuffer(),
3267
+ 0,
3268
+ 0,
3269
+ );
3270
+ });
3271
+
3272
+ it("Adapter impl: throws when sendZclFrameToAll fails request", async () => {
3273
+ mockEzspSend.mockResolvedValueOnce([SLStatus.FAIL, 0]);
3274
+
3275
+ const endpoint: number = 32;
3276
+ const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
3277
+ const p = defuseRejection(adapter.sendZclFrameToAll(endpoint, zclFrame, 1, ZSpec.BroadcastAddress.DEFAULT));
3278
+
3279
+ await vi.advanceTimersByTimeAsync(5000);
3280
+ await expect(p).rejects.toThrow("~x~> [ZCL BROADCAST destination=65532] Failed to send with status=FAIL.");
3281
+ expect(mockEzspSend).toHaveBeenCalledTimes(1);
3282
+ });
3283
+
3284
+ it("Adapter impl: setChannelInterPAN", async () => {
3285
+ await expect(adapter.setChannelInterPAN(15)).resolves.toStrictEqual(undefined);
3286
+ expect(mockEzspSetLogicalAndRadioChannel).toHaveBeenCalledWith(15);
3287
+ });
3288
+
3289
+ it("Adapter impl: throws when setChannelInterPAN fails request", async () => {
3290
+ mockEzspSetLogicalAndRadioChannel.mockResolvedValueOnce(SLStatus.FAIL);
3291
+
3292
+ await expect(adapter.setChannelInterPAN(15)).rejects.toThrow(`Failed to set InterPAN channel to '15' with status=FAIL.`);
3293
+ expect(mockEzspSetLogicalAndRadioChannel).toHaveBeenCalledWith(15);
3294
+ });
3295
+
3296
+ it("Adapter impl: sendZclFrameInterPANToIeeeAddr", async () => {
3297
+ const ieee: Eui64 = "0x1122334455667788";
3298
+ const zclFrame = Zcl.Frame.create(
3299
+ Zcl.FrameType.GLOBAL,
3300
+ Zcl.Direction.CLIENT_TO_SERVER,
3301
+ false,
3302
+ undefined,
3303
+ 3,
3304
+ "read",
3305
+ "genBasic",
3306
+ [{attrId: 0}],
3307
+ {},
3308
+ );
3309
+
3310
+ await expect(adapter.sendZclFrameInterPANToIeeeAddr(zclFrame, ieee)).resolves.toStrictEqual(undefined);
3311
+ expect(mockEzspSendRawMessage).toHaveBeenCalledTimes(1);
3312
+ expect(mockEzspSendRawMessage).toHaveBeenCalledWith(expect.any(Buffer), 1, true);
3313
+ });
3314
+
3315
+ it("Adapter impl: throws when sendZclFrameInterPANToIeeeAddr request fails", async () => {
3316
+ mockEzspSendRawMessage.mockResolvedValueOnce(SLStatus.BUSY);
3317
+
3318
+ const ieee: Eui64 = "0x1122334455667788";
3319
+ const zclFrame = Zcl.Frame.create(
3320
+ Zcl.FrameType.GLOBAL,
3321
+ Zcl.Direction.CLIENT_TO_SERVER,
3322
+ false,
3323
+ undefined,
3324
+ 3,
3325
+ "read",
3326
+ "genBasic",
3327
+ [{attrId: 0}],
3328
+ {},
3329
+ );
3330
+
3331
+ await expect(adapter.sendZclFrameInterPANToIeeeAddr(zclFrame, ieee)).rejects.toThrow(
3332
+ `~x~> [ZCL TOUCHLINK to=${ieee}] Failed to send with status=${SLStatus[SLStatus.BUSY]}.`,
3333
+ );
3334
+ expect(mockEzspSendRawMessage).toHaveBeenCalledTimes(1);
3335
+ expect(mockEzspSendRawMessage).toHaveBeenCalledWith(expect.any(Buffer), 1, true);
3336
+ });
3337
+
3338
+ it("Adapter impl: sendZclFrameInterPANBroadcast", async () => {
3339
+ const zclFrame = Zcl.Frame.create(
3340
+ Zcl.FrameType.SPECIFIC,
3341
+ Zcl.Direction.CLIENT_TO_SERVER,
3342
+ true,
3343
+ undefined,
3344
+ 0,
3345
+ "scanRequest",
3346
+ Zcl.Clusters.touchlink.ID,
3347
+ {transactionID: 1, zigbeeInformation: 4, touchlinkInformation: 18},
3348
+ {},
3349
+ );
3350
+ const sourcePanId: PanId = 0x1234;
3351
+ const sourceAddress: Eui64 = "0x1122334455aabbcc";
3352
+ const groupId: number = ZSpec.BroadcastAddress.SLEEPY;
3353
+ const lastHopLqi = 252;
3354
+ // Received Zigbee message from '0x', type 'readResponse', cluster 'genBasic', data '{"zclVersion":3}' from endpoint 1 with groupID 0
3355
+ const messageContents = Buffer.from("1800010000000100000000000000000088776655443322110154466341200", "hex");
3356
+
3357
+ mockEzspSendRawMessage.mockImplementationOnce(() => {
3358
+ setTimeout(async () => {
3359
+ mockEzspEmitter.emit("touchlinkMessage", sourcePanId, sourceAddress, groupId, lastHopLqi, messageContents);
3360
+ await flushPromises();
3361
+ }, 300);
3362
+
3363
+ return SLStatus.OK;
3364
+ });
3365
+
3366
+ const p = adapter.sendZclFrameInterPANBroadcast(zclFrame, 10000, false);
3367
+
3368
+ await vi.advanceTimersByTimeAsync(5000);
3369
+
3370
+ const payload: ZclPayload = {
3371
+ clusterID: Zcl.Clusters.touchlink.ID,
3372
+ header: Zcl.Header.fromBuffer(messageContents),
3373
+ address: sourceAddress,
3374
+ data: messageContents,
3375
+ endpoint: FIXED_ENDPOINTS[0].endpoint,
3376
+ linkquality: lastHopLqi,
3377
+ groupID: groupId,
3378
+ wasBroadcast: true,
3379
+ destinationEndpoint: FIXED_ENDPOINTS[0].endpoint,
3380
+ };
3381
+
3382
+ await expect(p).resolves.toStrictEqual(payload);
3383
+ expect(mockEzspSendRawMessage).toHaveBeenCalledTimes(1);
3384
+ expect(mockEzspSendRawMessage).toHaveBeenCalledWith(expect.any(Buffer), 1, true);
3385
+ });
3386
+
3387
+ it("Adapter impl: throws when sendZclFrameInterPANBroadcast command has no response", async () => {
3388
+ const commandName = "readRsp";
3389
+ const zclFrame = Zcl.Frame.create(
3390
+ Zcl.FrameType.GLOBAL,
3391
+ Zcl.Direction.CLIENT_TO_SERVER,
3392
+ false,
3393
+ undefined,
3394
+ 3,
3395
+ commandName,
3396
+ "genBasic",
3397
+ [{attrId: 0}],
3398
+ {},
3399
+ );
3400
+
3401
+ await expect(adapter.sendZclFrameInterPANBroadcast(zclFrame, 10000, false)).rejects.toThrow(
3402
+ `Command '${commandName}' has no response, cannot wait for response.`,
3403
+ );
3404
+ expect(mockEzspSendRawMessage).toHaveBeenCalledTimes(0);
3405
+ });
3406
+
3407
+ it("Adapter impl: throws when sendZclFrameInterPANBroadcast request fails", async () => {
3408
+ mockEzspSendRawMessage.mockResolvedValueOnce(SLStatus.BUSY);
3409
+
3410
+ const zclFrame = Zcl.Frame.create(
3411
+ Zcl.FrameType.GLOBAL,
3412
+ Zcl.Direction.CLIENT_TO_SERVER,
3413
+ false,
3414
+ undefined,
3415
+ 3,
3416
+ "read",
3417
+ "genBasic",
3418
+ [{attrId: 0}],
3419
+ {},
3420
+ );
3421
+
3422
+ await expect(adapter.sendZclFrameInterPANBroadcast(zclFrame, 10000, false)).rejects.toThrow(
3423
+ `~x~> [ZCL TOUCHLINK BROADCAST] Failed to send with status=${SLStatus[SLStatus.BUSY]}.`,
3424
+ );
3425
+ expect(mockEzspSendRawMessage).toHaveBeenCalledTimes(1);
3426
+ expect(mockEzspSendRawMessage).toHaveBeenCalledWith(expect.any(Buffer), 1, true);
3427
+ });
3428
+
3429
+ it("Adapter impl: restoreChannelInterPAN", async () => {
3430
+ const p = adapter.restoreChannelInterPAN();
3431
+
3432
+ await vi.advanceTimersByTimeAsync(10000);
3433
+ await expect(p).resolves.toStrictEqual(undefined);
3434
+ expect(mockEzspSetLogicalAndRadioChannel).toHaveBeenCalledWith(DEFAULT_NETWORK_OPTIONS.channelList[0]);
3435
+ });
3436
+
3437
+ it("Adapter impl: throws when restoreChannelInterPAN fails request", async () => {
3438
+ mockEzspSetLogicalAndRadioChannel.mockResolvedValueOnce(SLStatus.FAIL);
3439
+
3440
+ const p = defuseRejection(adapter.restoreChannelInterPAN());
3441
+
3442
+ await vi.advanceTimersByTimeAsync(10000);
3443
+ await expect(p).rejects.toThrow(`Failed to restore InterPAN channel to '${DEFAULT_NETWORK_OPTIONS.channelList[0]}' with status=FAIL.`);
3444
+ expect(mockEzspSetLogicalAndRadioChannel).toHaveBeenCalledWith(DEFAULT_NETWORK_OPTIONS.channelList[0]);
3445
+ });
3446
+ });
3447
+ });