@willieee802/zigbee-herdsman 0.19.2 → 0.34.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (530) hide show
  1. package/.babelrc.js +0 -4
  2. package/.release-please-manifest.json +1 -2
  3. package/CHANGELOG.md +376 -0
  4. package/README.md +1 -1
  5. package/dist/adapter/adapter.d.ts +61 -61
  6. package/dist/adapter/adapter.d.ts.map +1 -1
  7. package/dist/adapter/adapter.js +158 -146
  8. package/dist/adapter/adapter.js.map +1 -1
  9. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +68 -68
  10. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  11. package/dist/adapter/deconz/adapter/deconzAdapter.js +1081 -1060
  12. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  13. package/dist/adapter/deconz/adapter/index.d.ts +2 -2
  14. package/dist/adapter/deconz/adapter/index.js +10 -10
  15. package/dist/adapter/deconz/driver/constants.d.ts +104 -104
  16. package/dist/adapter/deconz/driver/constants.js +55 -55
  17. package/dist/adapter/deconz/driver/driver.d.ts +81 -81
  18. package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
  19. package/dist/adapter/deconz/driver/driver.js +750 -732
  20. package/dist/adapter/deconz/driver/driver.js.map +1 -1
  21. package/dist/adapter/deconz/driver/frame.d.ts +6 -6
  22. package/dist/adapter/deconz/driver/frame.js +13 -13
  23. package/dist/adapter/deconz/driver/frameParser.d.ts +2 -2
  24. package/dist/adapter/deconz/driver/frameParser.js +443 -443
  25. package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
  26. package/dist/adapter/deconz/driver/parser.d.ts +12 -12
  27. package/dist/adapter/deconz/driver/parser.js +63 -61
  28. package/dist/adapter/deconz/driver/parser.js.map +1 -1
  29. package/dist/adapter/deconz/driver/writer.d.ts +8 -8
  30. package/dist/adapter/deconz/driver/writer.js +44 -44
  31. package/dist/adapter/ember/adapter/emberAdapter.d.ts +817 -0
  32. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -0
  33. package/dist/adapter/ember/adapter/emberAdapter.js +2981 -0
  34. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -0
  35. package/dist/adapter/ember/adapter/endpoints.d.ts +25 -0
  36. package/dist/adapter/ember/adapter/endpoints.d.ts.map +1 -0
  37. package/dist/adapter/ember/adapter/endpoints.js +66 -0
  38. package/dist/adapter/ember/adapter/endpoints.js.map +1 -0
  39. package/dist/adapter/ember/adapter/index.d.ts +3 -0
  40. package/dist/adapter/ember/adapter/index.d.ts.map +1 -0
  41. package/dist/adapter/ember/adapter/index.js +6 -0
  42. package/dist/adapter/ember/adapter/index.js.map +1 -0
  43. package/dist/adapter/ember/adapter/oneWaitress.d.ts +97 -0
  44. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -0
  45. package/dist/adapter/ember/adapter/oneWaitress.js +226 -0
  46. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -0
  47. package/dist/adapter/ember/adapter/requestQueue.d.ts +59 -0
  48. package/dist/adapter/ember/adapter/requestQueue.d.ts.map +1 -0
  49. package/dist/adapter/ember/adapter/requestQueue.js +144 -0
  50. package/dist/adapter/ember/adapter/requestQueue.js.map +1 -0
  51. package/dist/adapter/ember/adapter/tokensManager.d.ts +69 -0
  52. package/dist/adapter/ember/adapter/tokensManager.d.ts.map +1 -0
  53. package/dist/adapter/ember/adapter/tokensManager.js +685 -0
  54. package/dist/adapter/ember/adapter/tokensManager.js.map +1 -0
  55. package/dist/adapter/ember/consts.d.ts +198 -0
  56. package/dist/adapter/ember/consts.d.ts.map +1 -0
  57. package/dist/adapter/ember/consts.js +253 -0
  58. package/dist/adapter/ember/consts.js.map +1 -0
  59. package/dist/adapter/ember/enums.d.ts +2184 -0
  60. package/dist/adapter/ember/enums.d.ts.map +1 -0
  61. package/dist/adapter/ember/enums.js +2391 -0
  62. package/dist/adapter/ember/enums.js.map +1 -0
  63. package/dist/adapter/ember/ezsp/buffalo.d.ts +156 -0
  64. package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -0
  65. package/dist/adapter/ember/ezsp/buffalo.js +1033 -0
  66. package/dist/adapter/ember/ezsp/buffalo.js.map +1 -0
  67. package/dist/adapter/ember/ezsp/consts.d.ts +116 -0
  68. package/dist/adapter/ember/ezsp/consts.d.ts.map +1 -0
  69. package/dist/adapter/ember/ezsp/consts.js +128 -0
  70. package/dist/adapter/ember/ezsp/consts.js.map +1 -0
  71. package/dist/adapter/ember/ezsp/enums.d.ts +879 -0
  72. package/dist/adapter/ember/ezsp/enums.d.ts.map +1 -0
  73. package/dist/adapter/ember/ezsp/enums.js +948 -0
  74. package/dist/adapter/ember/ezsp/enums.js.map +1 -0
  75. package/dist/adapter/ember/ezsp/ezsp.d.ts +2664 -0
  76. package/dist/adapter/ember/ezsp/ezsp.d.ts.map +1 -0
  77. package/dist/adapter/ember/ezsp/ezsp.js +6438 -0
  78. package/dist/adapter/ember/ezsp/ezsp.js.map +1 -0
  79. package/dist/adapter/ember/types.d.ts +733 -0
  80. package/dist/adapter/ember/types.d.ts.map +1 -0
  81. package/dist/adapter/ember/types.js +3 -0
  82. package/dist/adapter/ember/types.js.map +1 -0
  83. package/dist/adapter/ember/uart/ash.d.ts +451 -0
  84. package/dist/adapter/ember/uart/ash.d.ts.map +1 -0
  85. package/dist/adapter/ember/uart/ash.js +1584 -0
  86. package/dist/adapter/ember/uart/ash.js.map +1 -0
  87. package/dist/adapter/ember/uart/consts.d.ts +91 -0
  88. package/dist/adapter/ember/uart/consts.d.ts.map +1 -0
  89. package/dist/adapter/ember/uart/consts.js +100 -0
  90. package/dist/adapter/ember/uart/consts.js.map +1 -0
  91. package/dist/adapter/ember/uart/enums.d.ts +191 -0
  92. package/dist/adapter/ember/uart/enums.d.ts.map +1 -0
  93. package/dist/adapter/ember/uart/enums.js +197 -0
  94. package/dist/adapter/ember/uart/enums.js.map +1 -0
  95. package/dist/adapter/ember/uart/parser.d.ts +10 -0
  96. package/dist/adapter/ember/uart/parser.d.ts.map +1 -0
  97. package/dist/adapter/ember/uart/parser.js +41 -0
  98. package/dist/adapter/ember/uart/parser.js.map +1 -0
  99. package/dist/adapter/ember/uart/queues.d.ts +85 -0
  100. package/dist/adapter/ember/uart/queues.d.ts.map +1 -0
  101. package/dist/adapter/ember/uart/queues.js +212 -0
  102. package/dist/adapter/ember/uart/queues.js.map +1 -0
  103. package/dist/adapter/ember/uart/writer.d.ts +15 -0
  104. package/dist/adapter/ember/uart/writer.d.ts.map +1 -0
  105. package/dist/adapter/ember/uart/writer.js +48 -0
  106. package/dist/adapter/ember/uart/writer.js.map +1 -0
  107. package/dist/adapter/ember/utils/initters.d.ts +20 -0
  108. package/dist/adapter/ember/utils/initters.d.ts.map +1 -0
  109. package/dist/adapter/ember/utils/initters.js +58 -0
  110. package/dist/adapter/ember/utils/initters.js.map +1 -0
  111. package/dist/adapter/ember/utils/math.d.ts +51 -0
  112. package/dist/adapter/ember/utils/math.d.ts.map +1 -0
  113. package/dist/adapter/ember/utils/math.js +102 -0
  114. package/dist/adapter/ember/utils/math.js.map +1 -0
  115. package/dist/adapter/ember/zdo.d.ts +921 -0
  116. package/dist/adapter/ember/zdo.d.ts.map +1 -0
  117. package/dist/adapter/ember/zdo.js +723 -0
  118. package/dist/adapter/ember/zdo.js.map +1 -0
  119. package/dist/adapter/events.d.ts +47 -47
  120. package/dist/adapter/events.js +13 -14
  121. package/dist/adapter/events.js.map +1 -1
  122. package/dist/adapter/ezsp/adapter/backup.d.ts +9 -9
  123. package/dist/adapter/ezsp/adapter/backup.d.ts.map +1 -1
  124. package/dist/adapter/ezsp/adapter/backup.js +72 -53
  125. package/dist/adapter/ezsp/adapter/backup.js.map +1 -1
  126. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +61 -59
  127. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  128. package/dist/adapter/ezsp/adapter/ezspAdapter.js +629 -603
  129. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  130. package/dist/adapter/ezsp/adapter/index.d.ts +2 -2
  131. package/dist/adapter/ezsp/adapter/index.js +10 -10
  132. package/dist/adapter/ezsp/driver/commands.d.ts +36 -36
  133. package/dist/adapter/ezsp/driver/commands.d.ts.map +1 -1
  134. package/dist/adapter/ezsp/driver/commands.js +2388 -2359
  135. package/dist/adapter/ezsp/driver/commands.js.map +1 -1
  136. package/dist/adapter/ezsp/driver/consts.d.ts +10 -10
  137. package/dist/adapter/ezsp/driver/consts.js +13 -13
  138. package/dist/adapter/ezsp/driver/driver.d.ts +106 -103
  139. package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
  140. package/dist/adapter/ezsp/driver/driver.js +731 -639
  141. package/dist/adapter/ezsp/driver/driver.js.map +1 -1
  142. package/dist/adapter/ezsp/driver/ezsp.d.ts +105 -96
  143. package/dist/adapter/ezsp/driver/ezsp.d.ts.map +1 -1
  144. package/dist/adapter/ezsp/driver/ezsp.js +651 -586
  145. package/dist/adapter/ezsp/driver/ezsp.js.map +1 -1
  146. package/dist/adapter/ezsp/driver/frame.d.ts +40 -0
  147. package/dist/adapter/ezsp/driver/frame.d.ts.map +1 -0
  148. package/dist/adapter/ezsp/driver/frame.js +101 -0
  149. package/dist/adapter/ezsp/driver/frame.js.map +1 -0
  150. package/dist/adapter/ezsp/driver/index.d.ts +3 -3
  151. package/dist/adapter/ezsp/driver/index.js +8 -8
  152. package/dist/adapter/ezsp/driver/multicast.d.ts +12 -12
  153. package/dist/adapter/ezsp/driver/multicast.d.ts.map +1 -1
  154. package/dist/adapter/ezsp/driver/multicast.js +77 -74
  155. package/dist/adapter/ezsp/driver/multicast.js.map +1 -1
  156. package/dist/adapter/ezsp/driver/parser.d.ts +11 -12
  157. package/dist/adapter/ezsp/driver/parser.d.ts.map +1 -1
  158. package/dist/adapter/ezsp/driver/parser.js +104 -111
  159. package/dist/adapter/ezsp/driver/parser.js.map +1 -1
  160. package/dist/adapter/ezsp/driver/types/basic.d.ts +62 -62
  161. package/dist/adapter/ezsp/driver/types/basic.js +208 -208
  162. package/dist/adapter/ezsp/driver/types/basic.js.map +1 -1
  163. package/dist/adapter/ezsp/driver/types/index.d.ts +9 -9
  164. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  165. package/dist/adapter/ezsp/driver/types/index.js +138 -133
  166. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  167. package/dist/adapter/ezsp/driver/types/named.d.ts +1287 -697
  168. package/dist/adapter/ezsp/driver/types/named.d.ts.map +1 -1
  169. package/dist/adapter/ezsp/driver/types/named.js +2329 -1726
  170. package/dist/adapter/ezsp/driver/types/named.js.map +1 -1
  171. package/dist/adapter/ezsp/driver/types/struct.d.ts +270 -251
  172. package/dist/adapter/ezsp/driver/types/struct.d.ts.map +1 -1
  173. package/dist/adapter/ezsp/driver/types/struct.js +803 -708
  174. package/dist/adapter/ezsp/driver/types/struct.js.map +1 -1
  175. package/dist/adapter/ezsp/driver/uart.d.ts +48 -44
  176. package/dist/adapter/ezsp/driver/uart.d.ts.map +1 -1
  177. package/dist/adapter/ezsp/driver/uart.js +382 -368
  178. package/dist/adapter/ezsp/driver/uart.js.map +1 -1
  179. package/dist/adapter/ezsp/driver/utils/crc16ccitt.d.ts +2 -2
  180. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js +55 -55
  181. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js.map +1 -1
  182. package/dist/adapter/ezsp/driver/utils/index.d.ts +18 -18
  183. package/dist/adapter/ezsp/driver/utils/index.js +72 -67
  184. package/dist/adapter/ezsp/driver/utils/index.js.map +1 -1
  185. package/dist/adapter/ezsp/driver/writer.d.ts +13 -13
  186. package/dist/adapter/ezsp/driver/writer.d.ts.map +1 -1
  187. package/dist/adapter/ezsp/driver/writer.js +85 -88
  188. package/dist/adapter/ezsp/driver/writer.js.map +1 -1
  189. package/dist/adapter/index.d.ts +4 -4
  190. package/dist/adapter/index.js +35 -35
  191. package/dist/adapter/serialPort.d.ts +10 -8
  192. package/dist/adapter/serialPort.d.ts.map +1 -1
  193. package/dist/adapter/serialPort.js +53 -22
  194. package/dist/adapter/serialPort.js.map +1 -1
  195. package/dist/adapter/serialPortUtils.d.ts +12 -12
  196. package/dist/adapter/serialPortUtils.js +18 -18
  197. package/dist/adapter/serialPortUtils.js.map +1 -1
  198. package/dist/adapter/socketPortUtils.d.ts +10 -10
  199. package/dist/adapter/socketPortUtils.js +16 -16
  200. package/dist/adapter/tstype.d.ts +85 -85
  201. package/dist/adapter/tstype.d.ts.map +1 -1
  202. package/dist/adapter/tstype.js +2 -2
  203. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts +62 -62
  204. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts.map +1 -1
  205. package/dist/adapter/z-stack/adapter/adapter-backup.js +462 -460
  206. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
  207. package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts +150 -150
  208. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +258 -258
  209. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
  210. package/dist/adapter/z-stack/adapter/endpoints.d.ts +11 -11
  211. package/dist/adapter/z-stack/adapter/endpoints.js +73 -73
  212. package/dist/adapter/z-stack/adapter/index.d.ts +2 -2
  213. package/dist/adapter/z-stack/adapter/index.js +8 -8
  214. package/dist/adapter/z-stack/adapter/manager.d.ts +86 -86
  215. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  216. package/dist/adapter/z-stack/adapter/manager.js +482 -476
  217. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  218. package/dist/adapter/z-stack/adapter/tstype.d.ts +6 -6
  219. package/dist/adapter/z-stack/adapter/tstype.js +9 -10
  220. package/dist/adapter/z-stack/adapter/tstype.js.map +1 -1
  221. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +81 -81
  222. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  223. package/dist/adapter/z-stack/adapter/zStackAdapter.js +891 -868
  224. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  225. package/dist/adapter/z-stack/constants/af.d.ts +23 -23
  226. package/dist/adapter/z-stack/constants/af.js +27 -27
  227. package/dist/adapter/z-stack/constants/common.d.ts +278 -278
  228. package/dist/adapter/z-stack/constants/common.d.ts.map +1 -1
  229. package/dist/adapter/z-stack/constants/common.js +292 -289
  230. package/dist/adapter/z-stack/constants/common.js.map +1 -1
  231. package/dist/adapter/z-stack/constants/dbg.d.ts +22 -22
  232. package/dist/adapter/z-stack/constants/dbg.js +24 -24
  233. package/dist/adapter/z-stack/constants/index.d.ts +10 -10
  234. package/dist/adapter/z-stack/constants/index.js +47 -47
  235. package/dist/adapter/z-stack/constants/mac.d.ts +127 -127
  236. package/dist/adapter/z-stack/constants/mac.js +129 -129
  237. package/dist/adapter/z-stack/constants/sapi.d.ts +24 -24
  238. package/dist/adapter/z-stack/constants/sapi.js +26 -26
  239. package/dist/adapter/z-stack/constants/sys.d.ts +71 -71
  240. package/dist/adapter/z-stack/constants/sys.js +73 -73
  241. package/dist/adapter/z-stack/constants/util.d.ts +81 -81
  242. package/dist/adapter/z-stack/constants/util.js +83 -83
  243. package/dist/adapter/z-stack/constants/utils.d.ts +4 -4
  244. package/dist/adapter/z-stack/constants/utils.js +14 -14
  245. package/dist/adapter/z-stack/constants/zdo.d.ts +102 -102
  246. package/dist/adapter/z-stack/constants/zdo.js +104 -104
  247. package/dist/adapter/z-stack/models/index.d.ts +1 -1
  248. package/dist/adapter/z-stack/models/index.js +17 -17
  249. package/dist/adapter/z-stack/models/startup-options.d.ts +12 -12
  250. package/dist/adapter/z-stack/models/startup-options.js +2 -2
  251. package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts +23 -23
  252. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js +45 -45
  253. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js.map +1 -1
  254. package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts +10 -10
  255. package/dist/adapter/z-stack/structs/entries/address-manager-table.js +22 -22
  256. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts +10 -10
  257. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js +21 -21
  258. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts +10 -10
  259. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js +23 -23
  260. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts +10 -10
  261. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js +24 -24
  262. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts +10 -10
  263. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js +23 -23
  264. package/dist/adapter/z-stack/structs/entries/channel-list.d.ts +8 -8
  265. package/dist/adapter/z-stack/structs/entries/channel-list.js +15 -15
  266. package/dist/adapter/z-stack/structs/entries/has-configured.d.ts +8 -8
  267. package/dist/adapter/z-stack/structs/entries/has-configured.js +16 -16
  268. package/dist/adapter/z-stack/structs/entries/index.d.ts +16 -16
  269. package/dist/adapter/z-stack/structs/entries/index.js +32 -32
  270. package/dist/adapter/z-stack/structs/entries/nib.d.ts +10 -10
  271. package/dist/adapter/z-stack/structs/entries/nib.js +68 -68
  272. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts +10 -10
  273. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js +18 -18
  274. package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts +8 -8
  275. package/dist/adapter/z-stack/structs/entries/nwk-key.js +15 -15
  276. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts +8 -8
  277. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js +15 -15
  278. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts +13 -13
  279. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js +23 -23
  280. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts +10 -10
  281. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js +22 -22
  282. package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts +20 -20
  283. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js +36 -36
  284. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js.map +1 -1
  285. package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts +10 -10
  286. package/dist/adapter/z-stack/structs/entries/security-manager-table.js +24 -24
  287. package/dist/adapter/z-stack/structs/index.d.ts +4 -4
  288. package/dist/adapter/z-stack/structs/index.js +20 -20
  289. package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts +13 -13
  290. package/dist/adapter/z-stack/structs/serializable-memory-object.js +2 -2
  291. package/dist/adapter/z-stack/structs/struct.d.ts +99 -99
  292. package/dist/adapter/z-stack/structs/struct.js +296 -295
  293. package/dist/adapter/z-stack/structs/struct.js.map +1 -1
  294. package/dist/adapter/z-stack/structs/table.d.ts +94 -94
  295. package/dist/adapter/z-stack/structs/table.js +163 -161
  296. package/dist/adapter/z-stack/structs/table.js.map +1 -1
  297. package/dist/adapter/z-stack/unpi/constants.d.ts +28 -28
  298. package/dist/adapter/z-stack/unpi/constants.js +39 -41
  299. package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
  300. package/dist/adapter/z-stack/unpi/frame.d.ts +16 -16
  301. package/dist/adapter/z-stack/unpi/frame.js +54 -48
  302. package/dist/adapter/z-stack/unpi/frame.js.map +1 -1
  303. package/dist/adapter/z-stack/unpi/index.d.ts +5 -5
  304. package/dist/adapter/z-stack/unpi/index.js +37 -37
  305. package/dist/adapter/z-stack/unpi/parser.d.ts +10 -10
  306. package/dist/adapter/z-stack/unpi/parser.js +75 -74
  307. package/dist/adapter/z-stack/unpi/parser.js.map +1 -1
  308. package/dist/adapter/z-stack/unpi/writer.d.ts +10 -10
  309. package/dist/adapter/z-stack/unpi/writer.js +44 -44
  310. package/dist/adapter/z-stack/utils/channel-list.d.ts +20 -20
  311. package/dist/adapter/z-stack/utils/channel-list.js +40 -40
  312. package/dist/adapter/z-stack/utils/channel-list.js.map +1 -1
  313. package/dist/adapter/z-stack/utils/index.d.ts +2 -2
  314. package/dist/adapter/z-stack/utils/index.js +18 -18
  315. package/dist/adapter/z-stack/utils/network-options.d.ts +8 -8
  316. package/dist/adapter/z-stack/utils/network-options.js +22 -22
  317. package/dist/adapter/z-stack/znp/buffaloZnp.d.ts +11 -11
  318. package/dist/adapter/z-stack/znp/buffaloZnp.js +113 -113
  319. package/dist/adapter/z-stack/znp/buffaloZnp.js.map +1 -1
  320. package/dist/adapter/z-stack/znp/definition.d.ts +5 -5
  321. package/dist/adapter/z-stack/znp/definition.js +3050 -3050
  322. package/dist/adapter/z-stack/znp/index.d.ts +3 -3
  323. package/dist/adapter/z-stack/znp/index.js +10 -10
  324. package/dist/adapter/z-stack/znp/parameterType.d.ts +22 -22
  325. package/dist/adapter/z-stack/znp/parameterType.js +25 -25
  326. package/dist/adapter/z-stack/znp/tstype.d.ts +21 -21
  327. package/dist/adapter/z-stack/znp/tstype.js +2 -2
  328. package/dist/adapter/z-stack/znp/znp.d.ts +44 -43
  329. package/dist/adapter/z-stack/znp/znp.d.ts.map +1 -1
  330. package/dist/adapter/z-stack/znp/znp.js +326 -325
  331. package/dist/adapter/z-stack/znp/znp.js.map +1 -1
  332. package/dist/adapter/z-stack/znp/zpiObject.d.ts +19 -19
  333. package/dist/adapter/z-stack/znp/zpiObject.js +102 -96
  334. package/dist/adapter/z-stack/znp/zpiObject.js.map +1 -1
  335. package/dist/adapter/zigate/adapter/index.d.ts +2 -2
  336. package/dist/adapter/zigate/adapter/index.js +10 -10
  337. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +70 -69
  338. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  339. package/dist/adapter/zigate/adapter/zigateAdapter.js +689 -678
  340. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  341. package/dist/adapter/zigate/debug.d.ts +7 -7
  342. package/dist/adapter/zigate/debug.d.ts.map +1 -1
  343. package/dist/adapter/zigate/debug.js +19 -22
  344. package/dist/adapter/zigate/debug.js.map +1 -1
  345. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts +18 -18
  346. package/dist/adapter/zigate/driver/buffaloZiGate.js +139 -139
  347. package/dist/adapter/zigate/driver/buffaloZiGate.js.map +1 -1
  348. package/dist/adapter/zigate/driver/commandType.d.ts +41 -41
  349. package/dist/adapter/zigate/driver/commandType.js +385 -385
  350. package/dist/adapter/zigate/driver/commandType.js.map +1 -1
  351. package/dist/adapter/zigate/driver/constants.d.ts +276 -276
  352. package/dist/adapter/zigate/driver/constants.d.ts.map +1 -1
  353. package/dist/adapter/zigate/driver/constants.js +371 -371
  354. package/dist/adapter/zigate/driver/constants.js.map +1 -1
  355. package/dist/adapter/zigate/driver/frame.d.ts +26 -26
  356. package/dist/adapter/zigate/driver/frame.js +172 -172
  357. package/dist/adapter/zigate/driver/frame.js.map +1 -1
  358. package/dist/adapter/zigate/driver/messageType.d.ts +11 -11
  359. package/dist/adapter/zigate/driver/messageType.js +278 -278
  360. package/dist/adapter/zigate/driver/messageType.js.map +1 -1
  361. package/dist/adapter/zigate/driver/parameterType.d.ts +20 -20
  362. package/dist/adapter/zigate/driver/parameterType.js +23 -23
  363. package/dist/adapter/zigate/driver/ziGateObject.d.ts +23 -23
  364. package/dist/adapter/zigate/driver/ziGateObject.js +110 -106
  365. package/dist/adapter/zigate/driver/ziGateObject.js.map +1 -1
  366. package/dist/adapter/zigate/driver/zigate.d.ts +49 -49
  367. package/dist/adapter/zigate/driver/zigate.d.ts.map +1 -1
  368. package/dist/adapter/zigate/driver/zigate.js +296 -303
  369. package/dist/adapter/zigate/driver/zigate.js.map +1 -1
  370. package/dist/buffalo/buffalo.d.ts +50 -50
  371. package/dist/buffalo/buffalo.js +324 -322
  372. package/dist/buffalo/buffalo.js.map +1 -1
  373. package/dist/buffalo/index.d.ts +3 -3
  374. package/dist/buffalo/index.js +33 -33
  375. package/dist/buffalo/tstype.d.ts +8 -8
  376. package/dist/buffalo/tstype.js +2 -2
  377. package/dist/controller/controller.d.ts +113 -113
  378. package/dist/controller/controller.d.ts.map +1 -1
  379. package/dist/controller/controller.js +641 -619
  380. package/dist/controller/controller.js.map +1 -1
  381. package/dist/controller/database.d.ts +18 -18
  382. package/dist/controller/database.js +96 -93
  383. package/dist/controller/database.js.map +1 -1
  384. package/dist/controller/events.d.ts +58 -58
  385. package/dist/controller/events.d.ts.map +1 -1
  386. package/dist/controller/events.js +108 -101
  387. package/dist/controller/events.js.map +1 -1
  388. package/dist/controller/greenPower.d.ts +12 -12
  389. package/dist/controller/greenPower.js +221 -220
  390. package/dist/controller/greenPower.js.map +1 -1
  391. package/dist/controller/helpers/index.d.ts +2 -2
  392. package/dist/controller/helpers/index.js +28 -28
  393. package/dist/controller/helpers/request.d.ts +21 -22
  394. package/dist/controller/helpers/request.d.ts.map +1 -1
  395. package/dist/controller/helpers/request.js +77 -71
  396. package/dist/controller/helpers/request.js.map +1 -1
  397. package/dist/controller/helpers/requestQueue.d.ts +13 -0
  398. package/dist/controller/helpers/requestQueue.d.ts.map +1 -0
  399. package/dist/controller/helpers/requestQueue.js +116 -0
  400. package/dist/controller/helpers/requestQueue.js.map +1 -0
  401. package/dist/controller/helpers/zclFrameConverter.d.ts +7 -7
  402. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  403. package/dist/controller/helpers/zclFrameConverter.js +50 -31
  404. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  405. package/dist/controller/helpers/zclTransactionSequenceNumber.d.ts +5 -5
  406. package/dist/controller/helpers/zclTransactionSequenceNumber.js +13 -13
  407. package/dist/controller/helpers/zclTransactionSequenceNumber.js.map +1 -1
  408. package/dist/controller/index.d.ts +5 -5
  409. package/dist/controller/index.js +8 -8
  410. package/dist/controller/logger-stub.d.ts +6 -6
  411. package/dist/controller/logger-stub.js +2 -2
  412. package/dist/controller/model/device.d.ts +132 -133
  413. package/dist/controller/model/device.d.ts.map +1 -1
  414. package/dist/controller/model/device.js +724 -717
  415. package/dist/controller/model/device.js.map +1 -1
  416. package/dist/controller/model/endpoint.d.ts +128 -131
  417. package/dist/controller/model/endpoint.d.ts.map +1 -1
  418. package/dist/controller/model/endpoint.js +755 -816
  419. package/dist/controller/model/endpoint.js.map +1 -1
  420. package/dist/controller/model/entity.d.ts +14 -14
  421. package/dist/controller/model/entity.js +26 -26
  422. package/dist/controller/model/entity.js.map +1 -1
  423. package/dist/controller/model/group.d.ts +38 -38
  424. package/dist/controller/model/group.d.ts.map +1 -1
  425. package/dist/controller/model/group.js +225 -221
  426. package/dist/controller/model/group.js.map +1 -1
  427. package/dist/controller/model/index.d.ts +5 -5
  428. package/dist/controller/model/index.js +14 -14
  429. package/dist/controller/touchlink.d.ts +19 -19
  430. package/dist/controller/touchlink.js +159 -157
  431. package/dist/controller/touchlink.js.map +1 -1
  432. package/dist/controller/tstype.d.ts +20 -21
  433. package/dist/controller/tstype.d.ts.map +1 -1
  434. package/dist/controller/tstype.js +8 -9
  435. package/dist/controller/tstype.js.map +1 -1
  436. package/dist/index.d.ts +3 -3
  437. package/dist/index.js +33 -33
  438. package/dist/models/backup-storage-legacy.d.ts +26 -26
  439. package/dist/models/backup-storage-legacy.js +2 -2
  440. package/dist/models/backup-storage-unified.d.ts +49 -49
  441. package/dist/models/backup-storage-unified.js +2 -2
  442. package/dist/models/backup.d.ts +37 -37
  443. package/dist/models/backup.js +2 -2
  444. package/dist/models/index.d.ts +4 -4
  445. package/dist/models/index.js +20 -20
  446. package/dist/models/network-options.d.ts +12 -12
  447. package/dist/models/network-options.js +2 -2
  448. package/dist/utils/assertString.d.ts +2 -2
  449. package/dist/utils/assertString.js +8 -8
  450. package/dist/utils/assertString.js.map +1 -1
  451. package/dist/utils/backup.d.ts +20 -20
  452. package/dist/utils/backup.d.ts.map +1 -1
  453. package/dist/utils/backup.js +189 -187
  454. package/dist/utils/backup.js.map +1 -1
  455. package/dist/utils/equalsPartial.d.ts +2 -2
  456. package/dist/utils/equalsPartial.js +11 -11
  457. package/dist/utils/index.d.ts +9 -9
  458. package/dist/utils/index.js +45 -45
  459. package/dist/utils/isNumberArray.d.ts +2 -2
  460. package/dist/utils/isNumberArray.js +6 -6
  461. package/dist/utils/queue.d.ts +11 -11
  462. package/dist/utils/queue.d.ts.map +1 -1
  463. package/dist/utils/queue.js +61 -50
  464. package/dist/utils/queue.js.map +1 -1
  465. package/dist/utils/realpathSync.d.ts +2 -2
  466. package/dist/utils/realpathSync.js +12 -12
  467. package/dist/utils/wait.d.ts +2 -2
  468. package/dist/utils/wait.js +8 -8
  469. package/dist/utils/waitress.d.ts +21 -21
  470. package/dist/utils/waitress.d.ts.map +1 -1
  471. package/dist/utils/waitress.js +68 -61
  472. package/dist/utils/waitress.js.map +1 -1
  473. package/dist/zcl/buffaloZcl.d.ts +41 -41
  474. package/dist/zcl/buffaloZcl.d.ts.map +1 -1
  475. package/dist/zcl/buffaloZcl.js +594 -591
  476. package/dist/zcl/buffaloZcl.js.map +1 -1
  477. package/dist/zcl/definition/buffaloZclDataType.d.ts +17 -17
  478. package/dist/zcl/definition/buffaloZclDataType.js +20 -20
  479. package/dist/zcl/definition/cluster.d.ts +29 -29
  480. package/dist/zcl/definition/cluster.d.ts.map +1 -1
  481. package/dist/zcl/definition/cluster.js +5520 -5335
  482. package/dist/zcl/definition/cluster.js.map +1 -1
  483. package/dist/zcl/definition/dataType.d.ts +59 -59
  484. package/dist/zcl/definition/dataType.js +64 -64
  485. package/dist/zcl/definition/direction.d.ts +5 -5
  486. package/dist/zcl/definition/direction.js +8 -8
  487. package/dist/zcl/definition/endpointDeviceType.d.ts +4 -4
  488. package/dist/zcl/definition/endpointDeviceType.js +15 -15
  489. package/dist/zcl/definition/foundation.d.ts +11 -11
  490. package/dist/zcl/definition/foundation.js +167 -167
  491. package/dist/zcl/definition/frameControl.d.ts +10 -10
  492. package/dist/zcl/definition/frameControl.js +2 -2
  493. package/dist/zcl/definition/frameType.d.ts +5 -5
  494. package/dist/zcl/definition/frameType.js +8 -8
  495. package/dist/zcl/definition/index.d.ts +13 -13
  496. package/dist/zcl/definition/index.js +51 -51
  497. package/dist/zcl/definition/manufacturerCode.d.ts +1077 -1074
  498. package/dist/zcl/definition/manufacturerCode.d.ts.map +1 -1
  499. package/dist/zcl/definition/manufacturerCode.js +1082 -1079
  500. package/dist/zcl/definition/manufacturerCode.js.map +1 -1
  501. package/dist/zcl/definition/powerSource.d.ts +4 -4
  502. package/dist/zcl/definition/powerSource.js +12 -12
  503. package/dist/zcl/definition/status.d.ts +38 -38
  504. package/dist/zcl/definition/status.js +41 -41
  505. package/dist/zcl/definition/tstype.d.ts +16 -16
  506. package/dist/zcl/definition/tstype.js +2 -2
  507. package/dist/zcl/index.d.ts +16 -15
  508. package/dist/zcl/index.d.ts.map +1 -1
  509. package/dist/zcl/index.js +55 -55
  510. package/dist/zcl/index.js.map +1 -1
  511. package/dist/zcl/tstype.d.ts +56 -56
  512. package/dist/zcl/tstype.js +9 -10
  513. package/dist/zcl/tstype.js.map +1 -1
  514. package/dist/zcl/utils.d.ts +6 -6
  515. package/dist/zcl/utils.js +164 -165
  516. package/dist/zcl/utils.js.map +1 -1
  517. package/dist/zcl/zclFrame.d.ts +40 -45
  518. package/dist/zcl/zclFrame.d.ts.map +1 -1
  519. package/dist/zcl/zclFrame.js +351 -347
  520. package/dist/zcl/zclFrame.js.map +1 -1
  521. package/dist/zcl/zclHeader.d.ts +9 -0
  522. package/dist/zcl/zclHeader.d.ts.map +1 -0
  523. package/dist/zcl/zclHeader.js +3 -0
  524. package/dist/zcl/zclHeader.js.map +1 -0
  525. package/dist/zcl/zclStatusError.d.ts +5 -5
  526. package/dist/zcl/zclStatusError.js +14 -13
  527. package/dist/zcl/zclStatusError.js.map +1 -1
  528. package/package.json +11 -11
  529. package/release-please-config.json +1 -5
  530. package/tsconfig.json +4 -2
@@ -0,0 +1,2981 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EmberAdapter = void 0;
7
+ /* istanbul ignore file */
8
+ const debug_1 = __importDefault(require("debug"));
9
+ const es6_1 = __importDefault(require("fast-deep-equal/es6"));
10
+ const mz_1 = require("mz");
11
+ const serialPortUtils_1 = __importDefault(require("../../serialPortUtils"));
12
+ const socketPortUtils_1 = __importDefault(require("../../socketPortUtils"));
13
+ const utils_1 = require("../../../utils");
14
+ const __1 = require("../..");
15
+ const zcl_1 = require("../../../zcl");
16
+ const cluster_1 = __importDefault(require("../../../zcl/definition/cluster"));
17
+ const events_1 = require("../../events");
18
+ const math_1 = require("../utils/math");
19
+ const ezsp_1 = require("../ezsp/ezsp");
20
+ const consts_1 = require("../ezsp/consts");
21
+ const enums_1 = require("../ezsp/enums");
22
+ const buffalo_1 = require("../ezsp/buffalo");
23
+ const enums_2 = require("../enums");
24
+ const zdo_1 = require("../zdo");
25
+ const consts_2 = require("../consts");
26
+ const requestQueue_1 = require("./requestQueue");
27
+ const endpoints_1 = require("./endpoints");
28
+ const initters_1 = require("../utils/initters");
29
+ const crypto_1 = require("crypto");
30
+ const oneWaitress_1 = require("./oneWaitress");
31
+ const debug = (0, debug_1.default)('zigbee-herdsman:adapter:ember:adapter');
32
+ /** Enum to pass strings from numbers up to Z2M. */
33
+ var RoutingTableStatus;
34
+ (function (RoutingTableStatus) {
35
+ RoutingTableStatus[RoutingTableStatus["ACTIVE"] = 0] = "ACTIVE";
36
+ RoutingTableStatus[RoutingTableStatus["DISCOVERY_UNDERWAY"] = 1] = "DISCOVERY_UNDERWAY";
37
+ RoutingTableStatus[RoutingTableStatus["DISCOVERY_FAILED"] = 2] = "DISCOVERY_FAILED";
38
+ RoutingTableStatus[RoutingTableStatus["INACTIVE"] = 3] = "INACTIVE";
39
+ RoutingTableStatus[RoutingTableStatus["VALIDATION_UNDERWAY"] = 4] = "VALIDATION_UNDERWAY";
40
+ RoutingTableStatus[RoutingTableStatus["RESERVED1"] = 5] = "RESERVED1";
41
+ RoutingTableStatus[RoutingTableStatus["RESERVED2"] = 6] = "RESERVED2";
42
+ RoutingTableStatus[RoutingTableStatus["RESERVED3"] = 7] = "RESERVED3";
43
+ })(RoutingTableStatus || (RoutingTableStatus = {}));
44
+ ;
45
+ /** Events specific to OneWaitress usage. */
46
+ var OneWaitressEvents;
47
+ (function (OneWaitressEvents) {
48
+ OneWaitressEvents["STACK_STATUS_NETWORK_UP"] = "STACK_STATUS_NETWORK_UP";
49
+ OneWaitressEvents["STACK_STATUS_NETWORK_DOWN"] = "STACK_STATUS_NETWORK_DOWN";
50
+ OneWaitressEvents["STACK_STATUS_NETWORK_OPENED"] = "STACK_STATUS_NETWORK_OPENED";
51
+ OneWaitressEvents["STACK_STATUS_NETWORK_CLOSED"] = "STACK_STATUS_NETWORK_CLOSED";
52
+ })(OneWaitressEvents || (OneWaitressEvents = {}));
53
+ ;
54
+ var NetworkInitAction;
55
+ (function (NetworkInitAction) {
56
+ /** Ain't that nice! */
57
+ NetworkInitAction[NetworkInitAction["DONE"] = 0] = "DONE";
58
+ /** Config mismatch, must leave network. */
59
+ NetworkInitAction[NetworkInitAction["LEAVE"] = 1] = "LEAVE";
60
+ /** Config mismatched, left network. Will evaluate forming from backup or config next. */
61
+ NetworkInitAction[NetworkInitAction["LEFT"] = 2] = "LEFT";
62
+ /** Form the network using config. No backup, or backup mismatch. */
63
+ NetworkInitAction[NetworkInitAction["FORM_CONFIG"] = 3] = "FORM_CONFIG";
64
+ /** Re-form the network using full backed-up data. */
65
+ NetworkInitAction[NetworkInitAction["FORM_BACKUP"] = 4] = "FORM_BACKUP";
66
+ })(NetworkInitAction || (NetworkInitAction = {}));
67
+ ;
68
+ /** NOTE: Drivers can override `manufacturer`. Verify logic doesn't work in most cases anyway. */
69
+ const autoDetectDefinitions = [
70
+ /** NOTE: Manuf code "0x1321" for "Shenzhen Sonoff Technologies Co., Ltd." */
71
+ { manufacturer: 'ITEAD', vendorId: '1a86', productId: '55d4' }, // Sonoff ZBDongle-E
72
+ /** NOTE: Manuf code "0x134B" for "Nabu Casa, Inc." */
73
+ { manufacturer: 'Nabu Casa', vendorId: '10c4', productId: 'ea60' }, // Home Assistant SkyConnect
74
+ ];
75
+ /**
76
+ * Config for EMBER_LOW_RAM_CONCENTRATOR type concentrator.
77
+ *
78
+ * Based on ZigbeeMinimalHost/zigpc
79
+ */
80
+ const LOW_RAM_CONCENTRATOR_CONFIG = {
81
+ minTime: 5, // zigpc: 10
82
+ maxTime: 60, // zigpc: 60
83
+ routeErrorThreshold: 3, // zigpc: 3
84
+ deliveryFailureThreshold: 1, // zigpc: 1, ZigbeeMinimalHost: 3
85
+ mapHops: 0, // zigpc: 0
86
+ };
87
+ /**
88
+ * Config for EMBER_HIGH_RAM_CONCENTRATOR type concentrator.
89
+ *
90
+ * XXX: For now, same as low, until proper values can be determined.
91
+ */
92
+ const HIGH_RAM_CONCENTRATOR_CONFIG = {
93
+ minTime: 5,
94
+ maxTime: 60,
95
+ routeErrorThreshold: 3,
96
+ deliveryFailureThreshold: 1,
97
+ mapHops: 0,
98
+ };
99
+ /**
100
+ * Application generated ZDO messages use sequence numbers 0-127, and the stack
101
+ * uses sequence numbers 128-255. This simplifies life by eliminating the need
102
+ * for coordination between the two entities, and allows both to send ZDO
103
+ * messages with non-conflicting sequence numbers.
104
+ */
105
+ const APPLICATION_ZDO_SEQUENCE_MASK = 0x7F;
106
+ /** Current revision of the spec by zigbee alliance. XXX: what are `Zigbee Pro 2023` devices reporting?? */
107
+ const CURRENT_ZIGBEE_SPEC_REVISION = 23;
108
+ /** Each scan period is 15.36ms. Scan for at least 200ms (2^4 + 1 periods) to pick up WiFi beacon frames. */
109
+ const ENERGY_SCAN_DURATION = 4;
110
+ /** Oldest supported EZSP version for backups. Don't take the risk to restore a broken network until older backup versions can be investigated. */
111
+ const BACKUP_OLDEST_SUPPORTED_EZSP_VERSION = 12;
112
+ /**
113
+ * 9sec is minimum recommended for `ezspBroadcastNextNetworkKey` to have propagated throughout network.
114
+ * NOTE: This is blocking the request queue, so we shouldn't go crazy high.
115
+ */
116
+ const BROADCAST_NETWORK_KEY_SWITCH_WAIT_TIME = 15000;
117
+ /**
118
+ * Stack configuration values for various supported stacks.
119
+ */
120
+ const STACK_CONFIGS = {
121
+ "default": {
122
+ /** <1-250> (Default: 2) @see EzspConfigId.ADDRESS_TABLE_SIZE */
123
+ ADDRESS_TABLE_SIZE: 16, // zigpc: 32, darkxst: 16
124
+ /** <0-4> (Default: 2) @see EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE */
125
+ TRUST_CENTER_ADDRESS_CACHE_SIZE: 2,
126
+ /** (Default: USE_TOKEN) @see EzspConfigId.TX_POWER_MODE */
127
+ TX_POWER_MODE: enums_2.EmberTXPowerMode.USE_TOKEN,
128
+ /** <-> (Default: 1) @see EzspConfigId.SUPPORTED_NETWORKS */
129
+ SUPPORTED_NETWORKS: 1,
130
+ /** <-> (Default: ) @see EzspConfigId.STACK_PROFILE */
131
+ STACK_PROFILE: consts_2.STACK_PROFILE_ZIGBEE_PRO,
132
+ /** <-> (Default: ) @see EzspConfigId.SECURITY_LEVEL */
133
+ SECURITY_LEVEL: consts_2.SECURITY_LEVEL_Z3,
134
+ /** (Default: KEEP_ALIVE_SUPPORT_ALL) @see EzspValueId.END_DEVICE_KEEP_ALIVE_SUPPORT_MODE */
135
+ END_DEVICE_KEEP_ALIVE_SUPPORT_MODE: enums_2.EmberKeepAliveMode.KEEP_ALIVE_SUPPORT_ALL, // zigpc: KEEP_ALIVE_SUPPORT_ALL
136
+ /** <-> (Default: MAXIMUM_APS_PAYLOAD_LENGTH) @see EzspValueId.MAXIMUM_INCOMING_TRANSFER_SIZE */
137
+ MAXIMUM_INCOMING_TRANSFER_SIZE: consts_2.MAXIMUM_APS_PAYLOAD_LENGTH,
138
+ /** <-> (Default: MAXIMUM_APS_PAYLOAD_LENGTH) @see EzspValueId.MAXIMUM_OUTGOING_TRANSFER_SIZE */
139
+ MAXIMUM_OUTGOING_TRANSFER_SIZE: consts_2.MAXIMUM_APS_PAYLOAD_LENGTH,
140
+ /** <-> (Default: 10000) @see EzspValueId.TRANSIENT_DEVICE_TIMEOUT */
141
+ TRANSIENT_DEVICE_TIMEOUT: 10000,
142
+ /** <0-127> (Default: 2) @see EzspConfigId.BINDING_TABLE_SIZE */
143
+ BINDING_TABLE_SIZE: 5, // zigpc: 2, Z3GatewayGPCombo: 5
144
+ /** <0-127> (Default: 0) @see EzspConfigId.KEY_TABLE_SIZE */
145
+ KEY_TABLE_SIZE: 0, // zigpc: 4
146
+ /** <6-64> (Default: 6) @see EzspConfigId.MAX_END_DEVICE_CHILDREN */
147
+ MAX_END_DEVICE_CHILDREN: 6, // zigpc: 6
148
+ /** <1-255> (Default: 10) @see EzspConfigId.APS_UNICAST_MESSAGE_COUNT */
149
+ APS_UNICAST_MESSAGE_COUNT: 20, // zigpc: 10, darkxst: 20
150
+ /** <15-254> (Default: 15) @see EzspConfigId.BROADCAST_TABLE_SIZE */
151
+ BROADCAST_TABLE_SIZE: 15, // zigpc: 15, Z3GatewayGPCombo: 35 - NOTE: Sonoff Dongle-E fails at 35
152
+ /** [1, 16, 26] (Default: 16). @see EzspConfigId.NEIGHBOR_TABLE_SIZE */
153
+ NEIGHBOR_TABLE_SIZE: 26, // zigpc: 16, darkxst: 26
154
+ /** (Default: 8) @see EzspConfigId.END_DEVICE_POLL_TIMEOUT */
155
+ END_DEVICE_POLL_TIMEOUT: 8, // zigpc: 8
156
+ /** <0-65535> (Default: 300) @see EzspConfigId.TRANSIENT_KEY_TIMEOUT_S */
157
+ TRANSIENT_KEY_TIMEOUT_S: 300, // zigpc: 65535
158
+ /** <-> (Default: 16) @see EzspConfigId.RETRY_QUEUE_SIZE */
159
+ RETRY_QUEUE_SIZE: 16,
160
+ /** <0-255> (Default: 0) @see EzspConfigId.SOURCE_ROUTE_TABLE_SIZE */
161
+ SOURCE_ROUTE_TABLE_SIZE: 200, // Z3GatewayGPCombo: 100, darkxst: 200
162
+ /** <1-250> (Default: 8) @see EzspConfigId.MULTICAST_TABLE_SIZE */
163
+ MULTICAST_TABLE_SIZE: 16, // darkxst: 16
164
+ },
165
+ "zigbeed": {
166
+ ADDRESS_TABLE_SIZE: 128,
167
+ TRUST_CENTER_ADDRESS_CACHE_SIZE: 2,
168
+ TX_POWER_MODE: enums_2.EmberTXPowerMode.USE_TOKEN,
169
+ SUPPORTED_NETWORKS: 1,
170
+ STACK_PROFILE: consts_2.STACK_PROFILE_ZIGBEE_PRO,
171
+ SECURITY_LEVEL: consts_2.SECURITY_LEVEL_Z3,
172
+ END_DEVICE_KEEP_ALIVE_SUPPORT_MODE: enums_2.EmberKeepAliveMode.KEEP_ALIVE_SUPPORT_ALL,
173
+ MAXIMUM_INCOMING_TRANSFER_SIZE: consts_2.MAXIMUM_APS_PAYLOAD_LENGTH,
174
+ MAXIMUM_OUTGOING_TRANSFER_SIZE: consts_2.MAXIMUM_APS_PAYLOAD_LENGTH,
175
+ TRANSIENT_DEVICE_TIMEOUT: 10000,
176
+ BINDING_TABLE_SIZE: 128,
177
+ KEY_TABLE_SIZE: 0, // zigbeed 128
178
+ MAX_END_DEVICE_CHILDREN: 64,
179
+ APS_UNICAST_MESSAGE_COUNT: 32,
180
+ BROADCAST_TABLE_SIZE: 15,
181
+ NEIGHBOR_TABLE_SIZE: 26,
182
+ END_DEVICE_POLL_TIMEOUT: 8,
183
+ TRANSIENT_KEY_TIMEOUT_S: 300,
184
+ RETRY_QUEUE_SIZE: 16,
185
+ SOURCE_ROUTE_TABLE_SIZE: 254,
186
+ MULTICAST_TABLE_SIZE: 128,
187
+ /*
188
+ ROUTE_TABLE_SIZE: 254,
189
+ DISCOVERY_TABLE_SIZE: 64,
190
+ PACKET_BUFFER_COUNT: 255,
191
+ CUSTOM_MAC_FILTER_TABLE_SIZE: 64,
192
+ MAC_FILTER_TABLE_SIZE: 32,
193
+ CHILD_TABLE_SIZE: 64,
194
+ PLUGIN_ZIGBEE_PRO_STACK_CHILD_TABLE_SIZE: 64,
195
+ APS_MESSAGE_COUNT: 64,
196
+ */
197
+ },
198
+ };
199
+ /**
200
+ * Enabling this allows to immediately reject requests that won't be able to get to their destination.
201
+ * However, it causes more NCP calls, notably to get the source route overhead.
202
+ * XXX: Needs further testing before enabling
203
+ */
204
+ const CHECK_APS_PAYLOAD_LENGTH = false;
205
+ /** Time for a ZDO request to get a callback response. ASH is 2400*6 for ACK timeout. */
206
+ const DEFAULT_ZDO_REQUEST_TIMEOUT = 15000; // msec
207
+ /** Time for a ZCL request to get a callback response. ASH is 2400*6 for ACK timeout. */
208
+ const DEFAULT_ZCL_REQUEST_TIMEOUT = 15000; //msec
209
+ /** Time for a network-related request to get a response (usually via event). */
210
+ const DEFAULT_NETWORK_REQUEST_TIMEOUT = 10000; // nothing on the network to bother requests, should be much faster than this
211
+ /** Time between watchdog counters reading/clearing */
212
+ const WATCHDOG_COUNTERS_FEED_INTERVAL = 3600000; // every hour...
213
+ /**
214
+ * Relay calls between Z2M and EZSP-layer and handle any error that might occur via queue & waitress.
215
+ *
216
+ * Anything post `start` that requests anything from the EZSP layer must run through the request queue for proper execution flow.
217
+ */
218
+ class EmberAdapter extends __1.Adapter {
219
+ /** Key in STACK_CONFIGS */
220
+ stackConfig;
221
+ /** EMBER_LOW_RAM_CONCENTRATOR or EMBER_HIGH_RAM_CONCENTRATOR. */
222
+ concentratorType;
223
+ ezsp;
224
+ version;
225
+ requestQueue;
226
+ oneWaitress;
227
+ /** Periodically retrieve counters then clear them. */
228
+ watchdogCountersHandle;
229
+ /** Hold ZDO request in process. */
230
+ zdoRequestBuffalo;
231
+ /** Sequence number used for ZDO requests. static uint8_t */
232
+ zdoRequestSequence;
233
+ /** Default radius used for broadcast ZDO requests. uint8_t */
234
+ zdoRequestRadius;
235
+ interpanLock;
236
+ /**
237
+ * Cached network params to avoid NCP calls. Prevents frequent EZSP transactions.
238
+ * NOTE: Do not use directly, use getter functions for it that check if valid or need retrieval from NCP.
239
+ */
240
+ networkCache;
241
+ defaultApsOptions;
242
+ /**
243
+ * Mirrors the NCP multicast table. null === not in use.
244
+ * Index 0 is Green Power and must always remain there.
245
+ */
246
+ multicastTable;
247
+ constructor(networkOptions, serialPortOptions, backupPath, adapterOptions, logger) {
248
+ super(networkOptions, serialPortOptions, backupPath, adapterOptions, logger);
249
+ // TODO config, should be fine like this for now?
250
+ this.stackConfig = socketPortUtils_1.default.isTcpPath(serialPortOptions.path) ? 'zigbeed' : 'default';
251
+ // TODO config
252
+ this.concentratorType = consts_2.EMBER_HIGH_RAM_CONCENTRATOR;
253
+ // TODO: config dispatch interval, tested at 100, 80, 60
254
+ this.requestQueue = new requestQueue_1.EmberRequestQueue(60);
255
+ this.oneWaitress = new oneWaitress_1.EmberOneWaitress();
256
+ this.zdoRequestBuffalo = new buffalo_1.EzspBuffalo(Buffer.alloc(consts_1.EZSP_MAX_FRAME_LENGTH));
257
+ // TODO: config tick interval, tested at 500, 300, 100, 60, 30, all work fine and only really noticeable with interviews
258
+ this.ezsp = new ezsp_1.Ezsp(60, serialPortOptions);
259
+ this.ezsp.on(ezsp_1.EzspEvents.STACK_STATUS, this.onStackStatus.bind(this));
260
+ this.ezsp.on(ezsp_1.EzspEvents.MESSAGE_SENT_DELIVERY_FAILED, this.onMessageSentDeliveryFailed.bind(this));
261
+ this.ezsp.on(ezsp_1.EzspEvents.ZDO_RESPONSE, this.onZDOResponse.bind(this));
262
+ this.ezsp.on(ezsp_1.EzspEvents.END_DEVICE_ANNOUNCE, this.onEndDeviceAnnounce.bind(this));
263
+ this.ezsp.on(ezsp_1.EzspEvents.INCOMING_MESSAGE, this.onIncomingMessage.bind(this));
264
+ this.ezsp.on(ezsp_1.EzspEvents.TOUCHLINK_MESSAGE, this.onTouchlinkMessage.bind(this));
265
+ this.ezsp.on(ezsp_1.EzspEvents.GREENPOWER_MESSAGE, this.onGreenpowerMessage.bind(this));
266
+ this.ezsp.on(ezsp_1.EzspEvents.TRUST_CENTER_JOIN, this.onTrustCenterJoin.bind(this));
267
+ }
268
+ /**
269
+ * Emitted from @see Ezsp.ezspStackStatusHandler
270
+ * @param status
271
+ */
272
+ async onStackStatus(status) {
273
+ // to be extra careful, should clear network cache upon receiving this.
274
+ this.clearNetworkCache();
275
+ switch (status) {
276
+ case enums_2.EmberStatus.NETWORK_UP: {
277
+ this.oneWaitress.resolveEvent(OneWaitressEvents.STACK_STATUS_NETWORK_UP);
278
+ console.log(`[STACK STATUS] Network up.`);
279
+ break;
280
+ }
281
+ case enums_2.EmberStatus.NETWORK_DOWN: {
282
+ this.oneWaitress.resolveEvent(OneWaitressEvents.STACK_STATUS_NETWORK_DOWN);
283
+ console.log(`[STACK STATUS] Network down.`);
284
+ break;
285
+ }
286
+ case enums_2.EmberStatus.NETWORK_OPENED: {
287
+ this.oneWaitress.resolveEvent(OneWaitressEvents.STACK_STATUS_NETWORK_OPENED);
288
+ this.requestQueue.enqueue(async () => {
289
+ const setJPstatus = (await this.emberSetJoinPolicy(enums_2.EmberJoinDecision.USE_PRECONFIGURED_KEY));
290
+ if (setJPstatus !== enums_2.EzspStatus.SUCCESS) {
291
+ console.error(`[ZDO] Failed set join policy for with status=${enums_2.EzspStatus[setJPstatus]}.`);
292
+ return enums_2.EmberStatus.ERR_FATAL;
293
+ }
294
+ return enums_2.EmberStatus.SUCCESS;
295
+ }, console.error, // no reject, just log error if any
296
+ true);
297
+ console.log(`[STACK STATUS] Network opened.`);
298
+ break;
299
+ }
300
+ case enums_2.EmberStatus.NETWORK_CLOSED: {
301
+ this.oneWaitress.resolveEvent(OneWaitressEvents.STACK_STATUS_NETWORK_CLOSED);
302
+ console.log(`[STACK STATUS] Network closed.`);
303
+ break;
304
+ }
305
+ default: {
306
+ debug(`[STACK STATUS] ${enums_2.EmberStatus[status]}.`);
307
+ break;
308
+ }
309
+ }
310
+ }
311
+ /**
312
+ * Emitted from @see Ezsp.ezspMessageSentHandler
313
+ * WARNING: Cannot rely on `ezspMessageSentHandler` > `ezspIncomingMessageHandler` order, some devices mix it up!
314
+ *
315
+ * @param type
316
+ * @param indexOrDestination
317
+ * @param apsFrame
318
+ * @param messageTag
319
+ */
320
+ async onMessageSentDeliveryFailed(type, indexOrDestination, apsFrame, messageTag) {
321
+ switch (type) {
322
+ case enums_2.EmberOutgoingMessageType.BROADCAST:
323
+ case enums_2.EmberOutgoingMessageType.BROADCAST_WITH_ALIAS:
324
+ case enums_2.EmberOutgoingMessageType.MULTICAST:
325
+ case enums_2.EmberOutgoingMessageType.MULTICAST_WITH_ALIAS: {
326
+ // BC/MC not checking for message sent, avoid unnecessary waitress lookups
327
+ console.error(`Delivery of ${enums_2.EmberOutgoingMessageType[type]} failed for "${indexOrDestination}" `
328
+ + `[apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag}]`);
329
+ break;
330
+ }
331
+ default: {
332
+ // reject any waitress early (don't wait for timeout if we know we're gonna get there eventually)
333
+ this.oneWaitress.deliveryFailedFor(indexOrDestination, apsFrame);
334
+ break;
335
+ }
336
+ }
337
+ }
338
+ /**
339
+ * Emitted from @see Ezsp.ezspIncomingMessageHandler
340
+ *
341
+ * @param clusterId The ZDO response cluster ID.
342
+ * @param sender The sender of the response. Should match `payload.nodeId` in many responses.
343
+ * @param payload If null, the response indicated a failure.
344
+ */
345
+ async onZDOResponse(status, sender, apsFrame, payload) {
346
+ this.oneWaitress.resolveZDO(status, sender, apsFrame, payload);
347
+ }
348
+ /**
349
+ * Emitted from @see Ezsp.ezspIncomingMessageHandler
350
+ *
351
+ * @param sender
352
+ * @param nodeId
353
+ * @param eui64
354
+ * @param macCapFlags
355
+ */
356
+ async onEndDeviceAnnounce(sender, apsFrame, payload) {
357
+ // reduced function device
358
+ // if ((payload.capabilities.deviceType === 0)) {
359
+ // }
360
+ this.emit(events_1.Events.deviceAnnounce, { networkAddress: payload.nodeId, ieeeAddr: payload.eui64 });
361
+ }
362
+ /**
363
+ * Emitted from @see Ezsp.ezspIncomingMessageHandler
364
+ *
365
+ * @param type
366
+ * @param apsFrame
367
+ * @param lastHopLqi
368
+ * @param sender
369
+ * @param messageContents
370
+ */
371
+ async onIncomingMessage(type, apsFrame, lastHopLqi, sender, messageContents) {
372
+ try {
373
+ const payload = {
374
+ address: sender,
375
+ frame: zcl_1.ZclFrame.fromBuffer(apsFrame.clusterId, messageContents),
376
+ endpoint: apsFrame.sourceEndpoint,
377
+ linkquality: lastHopLqi,
378
+ groupID: apsFrame.groupId,
379
+ wasBroadcast: ((type === enums_2.EmberIncomingMessageType.BROADCAST) || (type === enums_2.EmberIncomingMessageType.BROADCAST_LOOPBACK)),
380
+ destinationEndpoint: apsFrame.destinationEndpoint,
381
+ };
382
+ this.oneWaitress.resolveZCL(payload);
383
+ this.emit(events_1.Events.zclData, payload);
384
+ }
385
+ catch (error) {
386
+ const payload = {
387
+ clusterID: apsFrame.clusterId,
388
+ address: sender,
389
+ data: messageContents,
390
+ endpoint: apsFrame.sourceEndpoint,
391
+ linkquality: lastHopLqi,
392
+ groupID: apsFrame.groupId,
393
+ wasBroadcast: ((type === enums_2.EmberIncomingMessageType.BROADCAST) || (type === enums_2.EmberIncomingMessageType.BROADCAST_LOOPBACK)),
394
+ destinationEndpoint: apsFrame.destinationEndpoint,
395
+ };
396
+ this.emit(events_1.Events.rawData, payload);
397
+ }
398
+ }
399
+ /**
400
+ * Emitted from @see Ezsp.ezspMacFilterMatchMessageHandler when the message is a valid InterPAN touchlink message.
401
+ *
402
+ * @param sourcePanId
403
+ * @param sourceAddress
404
+ * @param groupId
405
+ * @param lastHopLqi
406
+ * @param messageContents
407
+ */
408
+ async onTouchlinkMessage(sourcePanId, sourceAddress, groupId, lastHopLqi, messageContents) {
409
+ const payload = {
410
+ frame: zcl_1.ZclFrame.fromBuffer(cluster_1.default.touchlink.ID, messageContents),
411
+ address: sourceAddress,
412
+ endpoint: 1, // arbitrary since not sent over-the-air
413
+ linkquality: lastHopLqi,
414
+ groupID: groupId,
415
+ wasBroadcast: true, // XXX: since always sent broadcast atm...
416
+ destinationEndpoint: endpoints_1.FIXED_ENDPOINTS[0].endpoint,
417
+ };
418
+ this.oneWaitress.resolveZCL(payload);
419
+ this.emit(events_1.Events.zclData, payload);
420
+ }
421
+ /**
422
+ * Emitted from @see Ezsp.ezspGpepIncomingMessageHandler
423
+ *
424
+ * @param sequenceNumber
425
+ * @param commandIdentifier
426
+ * @param sourceId
427
+ * @param frameCounter
428
+ * @param gpdCommandId
429
+ * @param gpdCommandPayload
430
+ * @param gpdLink
431
+ */
432
+ async onGreenpowerMessage(sequenceNumber, commandIdentifier, sourceId, frameCounter, gpdCommandId, gpdCommandPayload, gpdLink) {
433
+ try {
434
+ const gpdHeader = Buffer.alloc(15);
435
+ gpdHeader.writeUInt8(0b00000001, 0); // frameControl: FrameType.SPECIFIC + Direction.CLIENT_TO_SERVER + disableDefaultResponse=false
436
+ gpdHeader.writeUInt8(sequenceNumber, 1); // transactionSequenceNumber
437
+ gpdHeader.writeUInt8(commandIdentifier, 2); // commandIdentifier
438
+ gpdHeader.writeUInt16LE(0, 3); // options XXX: bypassed, same as deconz https://github.com/Koenkk/zigbee-herdsman/pull/536
439
+ gpdHeader.writeUInt32LE(sourceId, 5); // srcID
440
+ // omitted: gpdIEEEAddr ieeeAddr
441
+ // omitted: gpdEndpoint uint8
442
+ gpdHeader.writeUInt32LE(frameCounter, 9); // frameCounter
443
+ gpdHeader.writeUInt8(gpdCommandId, 13); // commandID
444
+ gpdHeader.writeUInt8(gpdCommandPayload.length, 14); // payloadSize
445
+ const gpFrame = zcl_1.ZclFrame.fromBuffer(cluster_1.default.greenPower.ID, Buffer.concat([gpdHeader, gpdCommandPayload]));
446
+ const payload = {
447
+ frame: gpFrame,
448
+ address: sourceId,
449
+ endpoint: consts_2.GP_ENDPOINT,
450
+ linkquality: gpdLink,
451
+ groupID: this.greenPowerGroup,
452
+ // XXX: upstream sends to `gppNwkAddr` if `wasBroadcast` is false, even if `gppNwkAddr` is null
453
+ wasBroadcast: (gpFrame.Payload.gppNwkAddr != null) ? false : true,
454
+ destinationEndpoint: consts_2.GP_ENDPOINT,
455
+ };
456
+ this.oneWaitress.resolveZCL(payload);
457
+ this.emit(events_1.Events.zclData, payload);
458
+ }
459
+ catch (err) {
460
+ console.error(`<~x~ [GP] Failed creating ZCL payload. Skipping. ${err}`);
461
+ return;
462
+ }
463
+ }
464
+ /**
465
+ * Emitted from @see Ezsp.ezspTrustCenterJoinHandler
466
+ *
467
+ * @param newNodeId
468
+ * @param newNodeEui64
469
+ * @param status
470
+ * @param policyDecision
471
+ * @param parentOfNewNodeId
472
+ */
473
+ async onTrustCenterJoin(newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId) {
474
+ if (status === enums_2.EmberDeviceUpdate.DEVICE_LEFT) {
475
+ // NOTE: `policyDecision` here is NO_ACTION and `parentOfNewNodeId` is 65535
476
+ const payload = {
477
+ networkAddress: newNodeId,
478
+ ieeeAddr: newNodeEui64,
479
+ };
480
+ this.emit(events_1.Events.deviceLeave, payload);
481
+ }
482
+ else {
483
+ if (policyDecision !== enums_2.EmberJoinDecision.DENY_JOIN) {
484
+ const payload = {
485
+ networkAddress: newNodeId,
486
+ ieeeAddr: newNodeEui64,
487
+ };
488
+ this.emit(events_1.Events.deviceJoined, payload);
489
+ }
490
+ else {
491
+ console.log(`[TRUST CENTER] Device ${newNodeId}:${newNodeEui64} was denied joining via ${parentOfNewNodeId}.`);
492
+ }
493
+ }
494
+ }
495
+ async watchdogCounters() {
496
+ this.requestQueue.enqueue(async () => {
497
+ // listed as per EmberCounterType
498
+ const counters = (await this.ezsp.ezspReadAndClearCounters());
499
+ let countersLogString = "[NCP COUNTERS] ";
500
+ for (let i = 0; i < enums_2.EmberCounterType.COUNT; i++) {
501
+ countersLogString += `${enums_2.EmberCounterType[i]}: ${counters[i]} | `;
502
+ }
503
+ console.log(countersLogString);
504
+ return enums_2.EmberStatus.SUCCESS;
505
+ }, console.error);
506
+ }
507
+ initVariables() {
508
+ this.ezsp.removeAllListeners(ezsp_1.EzspEvents.ncpNeedsResetAndInit);
509
+ clearInterval(this.watchdogCountersHandle);
510
+ this.zdoRequestBuffalo.setPosition(0);
511
+ this.zdoRequestSequence = 0; // start at 1
512
+ this.zdoRequestRadius = 255;
513
+ this.interpanLock = false;
514
+ this.networkCache = (0, initters_1.initNetworkCache)();
515
+ this.defaultApsOptions = (enums_2.EmberApsOption.RETRY | enums_2.EmberApsOption.ENABLE_ROUTE_DISCOVERY | enums_2.EmberApsOption.ENABLE_ADDRESS_DISCOVERY);
516
+ // always at least length==1 because of allowed MULTICAST_TABLE_SIZE range
517
+ this.multicastTable = new Array(STACK_CONFIGS[this.stackConfig].MULTICAST_TABLE_SIZE).fill(null);
518
+ this.ezsp.once(ezsp_1.EzspEvents.ncpNeedsResetAndInit, this.onNcpNeedsResetAndInit.bind(this));
519
+ }
520
+ /**
521
+ * Proceed to execute the long list of commands required to setup comms between Host<>NCP.
522
+ * This is called by start and on internal reset.
523
+ */
524
+ async initEzsp() {
525
+ let result = "resumed";
526
+ await this.onNCPPreReset();
527
+ try {
528
+ // NOTE: something deep in this call can throw too
529
+ const result = (await this.ezsp.start());
530
+ if (result !== enums_2.EzspStatus.SUCCESS) {
531
+ throw new Error(`Failed to start EZSP layer with status=${enums_2.EzspStatus[result]}.`);
532
+ }
533
+ }
534
+ catch (err) {
535
+ throw err;
536
+ }
537
+ // call before any other command, else fails
538
+ await this.emberVersion();
539
+ await this.initNCPPreConfiguration();
540
+ await this.initNCPAddressTable();
541
+ await this.initNCPConfiguration();
542
+ // WARNING: From here on EZSP commands that affect memory allocation on the NCP should no longer be called (like resizing tables)
543
+ await this.onNCPPostReset();
544
+ await this.registerFixedEndpoints();
545
+ this.clearNetworkCache();
546
+ result = (await this.initTrustCenter());
547
+ // after network UP, as per SDK, ensures clean slate
548
+ await this.initNCPConcentrator();
549
+ // await (this.emberStartEnergyScan());// TODO: via config of some kind, better off waiting for UI supports though
550
+ // populate network cache info
551
+ const [status, , parameters] = (await this.ezsp.ezspGetNetworkParameters());
552
+ if (status !== enums_2.EmberStatus.SUCCESS) {
553
+ throw new Error(`Failed to get network parameters with status=${enums_2.EmberStatus[status]}.`);
554
+ }
555
+ this.networkCache.parameters = parameters;
556
+ this.networkCache.status = (await this.ezsp.ezspNetworkState());
557
+ this.networkCache.eui64 = (await this.ezsp.ezspGetEui64());
558
+ debug(`[INIT] Network Ready! ${JSON.stringify(this.networkCache)}`);
559
+ return result;
560
+ }
561
+ /**
562
+ * NCP Config init. Should always be called first in the init stack (after version cmd).
563
+ * @returns
564
+ */
565
+ async initNCPPreConfiguration() {
566
+ // this can only decrease, not increase, NCP-side value
567
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.ADDRESS_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].ADDRESS_TABLE_SIZE);
568
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.TRUST_CENTER_ADDRESS_CACHE_SIZE, STACK_CONFIGS[this.stackConfig].TRUST_CENTER_ADDRESS_CACHE_SIZE);
569
+ if (STACK_CONFIGS[this.stackConfig].STACK_PROFILE === consts_2.STACK_PROFILE_ZIGBEE_PRO) {
570
+ // BUG 14222: If stack profile is 2 (ZigBee Pro), we need to enforce
571
+ // the standard stack configuration values for that feature set.
572
+ /** MAC indirect timeout should be 7.68 secs */
573
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.INDIRECT_TRANSMISSION_TIMEOUT, 7680);
574
+ /** Max hops should be 2 * nwkMaxDepth, where nwkMaxDepth is 15 */
575
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.MAX_HOPS, 30);
576
+ }
577
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.TX_POWER_MODE, STACK_CONFIGS[this.stackConfig].TX_POWER_MODE);
578
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.SUPPORTED_NETWORKS, STACK_CONFIGS[this.stackConfig].SUPPORTED_NETWORKS);
579
+ await this.emberSetEzspValue(enums_1.EzspValueId.END_DEVICE_KEEP_ALIVE_SUPPORT_MODE, 1, [STACK_CONFIGS[this.stackConfig].END_DEVICE_KEEP_ALIVE_SUPPORT_MODE]);
580
+ // allow other devices to modify the binding table
581
+ await this.emberSetEzspPolicy(enums_1.EzspPolicyId.BINDING_MODIFICATION_POLICY, enums_1.EzspDecisionId.CHECK_BINDING_MODIFICATIONS_ARE_VALID_ENDPOINT_CLUSTERS);
582
+ // return message tag and message contents in ezspMessageSentHandler()
583
+ await this.emberSetEzspPolicy(enums_1.EzspPolicyId.MESSAGE_CONTENTS_IN_CALLBACK_POLICY, enums_1.EzspDecisionId.MESSAGE_TAG_AND_CONTENTS_IN_CALLBACK);
584
+ await this.emberSetEzspValue(enums_1.EzspValueId.MAXIMUM_INCOMING_TRANSFER_SIZE, 2, (0, math_1.lowHighBytes)(STACK_CONFIGS[this.stackConfig].MAXIMUM_INCOMING_TRANSFER_SIZE));
585
+ await this.emberSetEzspValue(enums_1.EzspValueId.MAXIMUM_OUTGOING_TRANSFER_SIZE, 2, (0, math_1.lowHighBytes)(STACK_CONFIGS[this.stackConfig].MAXIMUM_OUTGOING_TRANSFER_SIZE));
586
+ await this.emberSetEzspValue(enums_1.EzspValueId.TRANSIENT_DEVICE_TIMEOUT, 2, (0, math_1.lowHighBytes)(STACK_CONFIGS[this.stackConfig].TRANSIENT_DEVICE_TIMEOUT));
587
+ // Set the manufacturing code. This is defined by ZigBee document 053874r10
588
+ // Ember's ID is 0x1002 and is the default, but this can be overridden in App Builder.
589
+ await this.ezsp.ezspSetManufacturerCode(consts_2.MANUFACTURER_CODE);
590
+ // network security init
591
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.STACK_PROFILE, STACK_CONFIGS[this.stackConfig].STACK_PROFILE);
592
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.SECURITY_LEVEL, STACK_CONFIGS[this.stackConfig].SECURITY_LEVEL);
593
+ }
594
+ /**
595
+ * NCP Address table init.
596
+ * @returns
597
+ */
598
+ async initNCPAddressTable() {
599
+ const desiredTableSize = STACK_CONFIGS[this.stackConfig].ADDRESS_TABLE_SIZE;
600
+ // If the host and the ncp disagree on the address table size, explode.
601
+ const [status, addressTableSize] = (await this.ezsp.ezspGetConfigurationValue(enums_1.EzspConfigId.ADDRESS_TABLE_SIZE));
602
+ // After the change of ncp memory model in UC, we can not increase the default NCP table sizes anymore.
603
+ // Therefore, checking for desiredTableSize == (ncp)addressTableSize might not be always true anymore
604
+ // assert(desiredTableSize <= addressTableSize);
605
+ if ((status !== enums_2.EzspStatus.SUCCESS) || (addressTableSize > desiredTableSize)) {
606
+ throw new Error(`[INIT] NCP (${addressTableSize}) disagrees with Host (min ${desiredTableSize}) on table size. status=${enums_2.EzspStatus[status]}`);
607
+ }
608
+ }
609
+ /**
610
+ * NCP configuration init
611
+ */
612
+ async initNCPConfiguration() {
613
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.BINDING_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].BINDING_TABLE_SIZE);
614
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.KEY_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].KEY_TABLE_SIZE);
615
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.MAX_END_DEVICE_CHILDREN, STACK_CONFIGS[this.stackConfig].MAX_END_DEVICE_CHILDREN);
616
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.APS_UNICAST_MESSAGE_COUNT, STACK_CONFIGS[this.stackConfig].APS_UNICAST_MESSAGE_COUNT);
617
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.BROADCAST_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].BROADCAST_TABLE_SIZE);
618
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.NEIGHBOR_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].NEIGHBOR_TABLE_SIZE);
619
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.END_DEVICE_POLL_TIMEOUT, STACK_CONFIGS[this.stackConfig].END_DEVICE_POLL_TIMEOUT);
620
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.TRANSIENT_KEY_TIMEOUT_S, STACK_CONFIGS[this.stackConfig].TRANSIENT_KEY_TIMEOUT_S);
621
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.RETRY_QUEUE_SIZE, STACK_CONFIGS[this.stackConfig].RETRY_QUEUE_SIZE);
622
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.SOURCE_ROUTE_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].SOURCE_ROUTE_TABLE_SIZE);
623
+ await this.emberSetEzspConfigValue(enums_1.EzspConfigId.MULTICAST_TABLE_SIZE, STACK_CONFIGS[this.stackConfig].MULTICAST_TABLE_SIZE);
624
+ }
625
+ /**
626
+ * NCP concentrator init. Also enables source route discovery mode with RESCHEDULE.
627
+ *
628
+ * From AN1233:
629
+ * To function correctly in a Zigbee PRO network, a trust center also requires that:
630
+ *
631
+ * 1. The trust center application must act as a concentrator (either high or low RAM).
632
+ * 2. The trust center application must have support for source routing.
633
+ * It must record the source routes and properly handle requests by the stack for a particular source route.
634
+ * 3. The trust center application must use an address cache for security, in order to maintain a mapping of IEEE address to short ID.
635
+ *
636
+ * Failure to satisfy all of the above requirements may result in failures when joining/rejoining devices to the network across multiple hops
637
+ * (through a target node that is neither the trust center nor one of its neighboring routers.)
638
+ */
639
+ async initNCPConcentrator() {
640
+ const config = (this.concentratorType === consts_2.EMBER_HIGH_RAM_CONCENTRATOR) ? HIGH_RAM_CONCENTRATOR_CONFIG : LOW_RAM_CONCENTRATOR_CONFIG;
641
+ const status = (await this.ezsp.ezspSetConcentrator(true, this.concentratorType, config.minTime, config.maxTime, config.routeErrorThreshold, config.deliveryFailureThreshold, config.mapHops));
642
+ if (status !== enums_2.EmberStatus.SUCCESS) {
643
+ throw new Error(`[CONCENTRATOR] Failed to set concentrator with status=${status}.`);
644
+ }
645
+ const remainTilMTORR = (await this.ezsp.ezspSetSourceRouteDiscoveryMode(enums_2.EmberSourceRouteDiscoveryMode.RESCHEDULE));
646
+ console.log(`[CONCENTRATOR] Started source route discovery. ${remainTilMTORR}ms until next broadcast.`);
647
+ }
648
+ /**
649
+ * Register fixed endpoints and set any related multicast entries that need to be.
650
+ */
651
+ async registerFixedEndpoints() {
652
+ for (const ep of endpoints_1.FIXED_ENDPOINTS) {
653
+ if (ep.networkIndex !== 0x00) {
654
+ debug(`Multi-network not currently supported. Skipping endpoint ${JSON.stringify(ep)}.`);
655
+ continue;
656
+ }
657
+ const [epStatus,] = (await this.ezsp.ezspGetEndpointFlags(ep.endpoint));
658
+ // endpoint not already registered
659
+ if (epStatus !== enums_2.EzspStatus.SUCCESS) {
660
+ // check to see if ezspAddEndpoint needs to be called
661
+ // if ezspInit is called without NCP reset, ezspAddEndpoint is not necessary and will return an error
662
+ const status = (await this.ezsp.ezspAddEndpoint(ep.endpoint, ep.profileId, ep.deviceId, ep.deviceVersion, ep.inClusterList, ep.outClusterList));
663
+ if (status === enums_2.EzspStatus.SUCCESS) {
664
+ debug(`Registered endpoint "${ep.endpoint}" with status=${enums_2.EzspStatus[status]}.`);
665
+ }
666
+ else {
667
+ throw new Error(`Failed to register endpoint "${ep.endpoint}" with status=${enums_2.EzspStatus[status]}.`);
668
+ }
669
+ }
670
+ else {
671
+ debug(`Endpoint "${ep.endpoint}" already registered.`);
672
+ }
673
+ if (ep.endpoint === consts_2.GP_ENDPOINT) {
674
+ const gpMulticastEntry = {
675
+ multicastId: this.greenPowerGroup,
676
+ endpoint: ep.endpoint,
677
+ networkIndex: ep.networkIndex,
678
+ };
679
+ const status = (await this.ezsp.ezspSetMulticastTableEntry(0, gpMulticastEntry));
680
+ if (status !== enums_2.EmberStatus.SUCCESS) {
681
+ throw new Error(`Failed to register group "Green Power" in multicast table with status=${enums_2.EmberStatus[status]}.`);
682
+ }
683
+ // NOTE: ensure GP is always added first in the table
684
+ this.multicastTable[0] = gpMulticastEntry;
685
+ debug(`Registered multicast table entry: ${JSON.stringify(gpMulticastEntry)}.`);
686
+ }
687
+ }
688
+ }
689
+ /**
690
+ *
691
+ * @returns True if the network needed to be formed.
692
+ */
693
+ async initTrustCenter() {
694
+ // init TC policies
695
+ {
696
+ let status = (await this.emberSetEzspPolicy(enums_1.EzspPolicyId.TC_KEY_REQUEST_POLICY, enums_1.EzspDecisionId.ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY));
697
+ if (status !== enums_2.EzspStatus.SUCCESS) {
698
+ throw new Error(`[INIT TC] Failed to set EzspPolicyId TC_KEY_REQUEST_POLICY to ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY `
699
+ + `with status=${enums_2.EzspStatus[status]}.`);
700
+ }
701
+ const appKeyPolicy = STACK_CONFIGS[this.stackConfig].KEY_TABLE_SIZE
702
+ ? enums_1.EzspDecisionId.ALLOW_APP_KEY_REQUESTS : enums_1.EzspDecisionId.DENY_APP_KEY_REQUESTS;
703
+ status = (await this.emberSetEzspPolicy(enums_1.EzspPolicyId.APP_KEY_REQUEST_POLICY, appKeyPolicy));
704
+ if (status !== enums_2.EzspStatus.SUCCESS) {
705
+ throw new Error(`[INIT TC] Failed to set EzspPolicyId APP_KEY_REQUEST_POLICY to ${enums_1.EzspDecisionId[appKeyPolicy]} `
706
+ + `with status=${enums_2.EzspStatus[status]}.`);
707
+ }
708
+ status = (await this.emberSetJoinPolicy(enums_2.EmberJoinDecision.USE_PRECONFIGURED_KEY));
709
+ if (status !== enums_2.EzspStatus.SUCCESS) {
710
+ throw new Error(`[INIT TC] Failed to set join policy to USE_PRECONFIGURED_KEY with status=${enums_2.EzspStatus[status]}.`);
711
+ }
712
+ }
713
+ const configNetworkKey = Buffer.from(this.networkOptions.networkKey);
714
+ const networkInitStruct = {
715
+ bitmask: (enums_2.EmberNetworkInitBitmask.PARENT_INFO_IN_TOKEN | enums_2.EmberNetworkInitBitmask.END_DEVICE_REJOIN_ON_REBOOT)
716
+ };
717
+ const initStatus = (await this.ezsp.ezspNetworkInit(networkInitStruct));
718
+ debug(`[INIT TC] Network init status=${enums_2.EmberStatus[initStatus]}.`);
719
+ if ((initStatus !== enums_2.EmberStatus.SUCCESS) && (initStatus !== enums_2.EmberStatus.NOT_JOINED)) {
720
+ throw new Error(`[INIT TC] Failed network init request with status=${enums_2.EmberStatus[initStatus]}.`);
721
+ }
722
+ let action = NetworkInitAction.DONE;
723
+ if (initStatus === enums_2.EmberStatus.SUCCESS) {
724
+ // network
725
+ await this.oneWaitress.startWaitingForEvent({ eventName: OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Network init');
726
+ const [npStatus, nodeType, netParams] = (await this.ezsp.ezspGetNetworkParameters());
727
+ debug(`[INIT TC] Current network config=${JSON.stringify(this.networkOptions)}`);
728
+ debug(`[INIT TC] Current NCP network: nodeType=${enums_2.EmberNodeType[nodeType]} params=${JSON.stringify(netParams)}`);
729
+ // XXX: should not force a form when it's only a channel change, just change the channel, wait a sec, then continue the logic
730
+ if ((npStatus === enums_2.EmberStatus.SUCCESS) && (nodeType === enums_2.EmberNodeType.COORDINATOR) && (this.networkOptions.panID === netParams.panId)
731
+ && ((0, es6_1.default)(this.networkOptions.extendedPanID, netParams.extendedPanId))
732
+ && (this.networkOptions.channelList.includes(netParams.radioChannel))) {
733
+ // config matches adapter so far, no error, we can check the network key
734
+ const context = (0, initters_1.initSecurityManagerContext)();
735
+ context.coreKeyType = enums_2.SecManKeyType.NETWORK;
736
+ context.keyIndex = 0;
737
+ const [networkKey, nkStatus] = (await this.ezsp.ezspExportKey(context));
738
+ if (nkStatus !== enums_2.SLStatus.OK) {
739
+ throw new Error(`[BACKUP] Failed to export Network Key with status=${enums_2.SLStatus[nkStatus]}.`);
740
+ }
741
+ debug(`[INIT TC] Current NCP network: networkKey=${networkKey.contents.toString('hex')}`);
742
+ // config doesn't match adapter anymore
743
+ if (!networkKey.contents.equals(configNetworkKey)) {
744
+ action = NetworkInitAction.LEAVE;
745
+ }
746
+ }
747
+ else {
748
+ // config doesn't match adapter
749
+ action = NetworkInitAction.LEAVE;
750
+ }
751
+ if (action === NetworkInitAction.LEAVE) {
752
+ console.log(`[INIT TC] NCP network does not match config. Leaving network...`);
753
+ const leaveStatus = (await this.ezsp.ezspLeaveNetwork());
754
+ if (leaveStatus !== enums_2.EmberStatus.SUCCESS) {
755
+ throw new Error(`[INIT TC] Failed leave network request with status=${enums_2.EmberStatus[leaveStatus]}.`);
756
+ }
757
+ await this.oneWaitress.startWaitingForEvent({ eventName: OneWaitressEvents.STACK_STATUS_NETWORK_DOWN }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT TC] Leave network');
758
+ await (0, utils_1.Wait)(200); // settle down
759
+ action = NetworkInitAction.LEFT;
760
+ }
761
+ }
762
+ const backup = (await this.getStoredBackup());
763
+ if ((initStatus === enums_2.EmberStatus.NOT_JOINED) || (action === NetworkInitAction.LEFT)) {
764
+ // no network
765
+ if (backup != null) {
766
+ if ((this.networkOptions.panID === backup.networkOptions.panId)
767
+ && (Buffer.from(this.networkOptions.extendedPanID).equals(backup.networkOptions.extendedPanId))
768
+ && (this.networkOptions.channelList.includes(backup.logicalChannel))
769
+ && (configNetworkKey.equals(backup.networkOptions.networkKey))) {
770
+ // config matches backup
771
+ action = NetworkInitAction.FORM_BACKUP;
772
+ }
773
+ else {
774
+ // config doesn't match backup
775
+ console.log(`[INIT TC] Config does not match backup.`);
776
+ action = NetworkInitAction.FORM_CONFIG;
777
+ }
778
+ }
779
+ else {
780
+ // no backup
781
+ console.log(`[INIT TC] No valid backup found.`);
782
+ action = NetworkInitAction.FORM_CONFIG;
783
+ }
784
+ }
785
+ else {
786
+ action = NetworkInitAction.DONE; // just to be clear
787
+ }
788
+ //---- from here on, we assume everything is in place for whatever decision was taken above
789
+ let result = 'resumed';
790
+ switch (action) {
791
+ case NetworkInitAction.FORM_BACKUP: {
792
+ console.log(`[INIT TC] Forming from backup.`);
793
+ const keyList = backup.devices.map((device) => {
794
+ const octets = Array.from(device.ieeeAddress.reverse());
795
+ const deviceEui64 = '0x' + octets.map(octet => octet.toString(16).padStart(2, '0')).join("");
796
+ const key = {
797
+ deviceEui64,
798
+ key: { contents: device.linkKey.key },
799
+ outgoingFrameCounter: device.linkKey.txCounter,
800
+ incomingFrameCounter: device.linkKey.rxCounter,
801
+ };
802
+ return key;
803
+ });
804
+ // before forming
805
+ await this.importLinkKeys(keyList);
806
+ await this.formNetwork(true, /*from backup*/ backup.networkOptions.networkKey, backup.networkKeyInfo.sequenceNumber, backup.networkOptions.panId, Array.from(backup.networkOptions.extendedPanId), backup.logicalChannel, backup.ezsp.hashed_tclk);
807
+ result = 'restored';
808
+ break;
809
+ }
810
+ case NetworkInitAction.FORM_CONFIG: {
811
+ console.log(`[INIT TC] Forming from config.`);
812
+ await this.formNetwork(false, /*from config*/ configNetworkKey, 0, this.networkOptions.panID, this.networkOptions.extendedPanID, this.networkOptions.channelList[0], (0, crypto_1.randomBytes)(consts_1.EMBER_ENCRYPTION_KEY_SIZE));
813
+ result = 'reset';
814
+ break;
815
+ }
816
+ case NetworkInitAction.DONE: {
817
+ console.log(`[INIT TC] NCP network matches config.`);
818
+ break;
819
+ }
820
+ default: {
821
+ throw new Error(`[INIT TC] Invalid action "${NetworkInitAction[action]}" for final stage.`);
822
+ }
823
+ }
824
+ // can't let frame counter wrap to zero (uint32_t), will force a broadcast after init if getting too close
825
+ if (backup != null && (backup.networkKeyInfo.frameCounter > 0xFEEEEEEE)) {
826
+ // XXX: while this remains a pretty low occurrence in most (small) networks,
827
+ // currently Z2M won't support the key update because of one-way config...
828
+ // need to investigate handling this properly
829
+ // console.warn(`[INIT TC] Network key frame counter is reaching its limit. Scheduling broadcast to update network key. `
830
+ // + `This may result in some devices (especially battery-powered) temporarily losing connection.`);
831
+ // // XXX: no idea here on the proper timer value, but this will block the network for several seconds on exec
832
+ // // (probably have to take the behavior of sleepy-end devices into account to improve chances of reaching everyone right away?)
833
+ // setTimeout(async () => {
834
+ // this.requestQueue.enqueue(async (): Promise<EmberStatus> => {
835
+ // await this.broadcastNetworkKeyUpdate();
836
+ // return EmberStatus.SUCCESS;
837
+ // }, console.error, true);// no reject just log error if any, will retry next start, & prioritize so we know it'll run when expected
838
+ // }, 300000);
839
+ console.warn(`[INIT TC] Network key frame counter is reaching its limit. A new network key will have to be instaured soon.`);
840
+ }
841
+ return result;
842
+ }
843
+ /**
844
+ * Form a network using given parameters.
845
+ */
846
+ async formNetwork(fromBackup, networkKey, networkKeySequenceNumber, panId, extendedPanId, radioChannel, tcLinkKey) {
847
+ const state = {
848
+ bitmask: (enums_2.EmberInitialSecurityBitmask.TRUST_CENTER_GLOBAL_LINK_KEY | enums_2.EmberInitialSecurityBitmask.HAVE_PRECONFIGURED_KEY
849
+ | enums_2.EmberInitialSecurityBitmask.HAVE_NETWORK_KEY | enums_2.EmberInitialSecurityBitmask.TRUST_CENTER_USES_HASHED_LINK_KEY
850
+ | enums_2.EmberInitialSecurityBitmask.REQUIRE_ENCRYPTED_KEY),
851
+ preconfiguredKey: { contents: tcLinkKey },
852
+ networkKey: { contents: networkKey },
853
+ networkKeySequenceNumber: networkKeySequenceNumber,
854
+ preconfiguredTrustCenterEui64: consts_2.BLANK_EUI64,
855
+ };
856
+ if (fromBackup) {
857
+ state.bitmask |= enums_2.EmberInitialSecurityBitmask.NO_FRAME_COUNTER_RESET;
858
+ }
859
+ let emberStatus = (await this.ezsp.ezspSetInitialSecurityState(state));
860
+ if (emberStatus !== enums_2.EmberStatus.SUCCESS) {
861
+ throw new Error(`[INIT FORM] Failed to set initial security state with status=${enums_2.EmberStatus[emberStatus]}.`);
862
+ }
863
+ const extended = (enums_2.EmberExtendedSecurityBitmask.JOINER_GLOBAL_LINK_KEY | enums_2.EmberExtendedSecurityBitmask.NWK_LEAVE_REQUEST_NOT_ALLOWED);
864
+ const extSecStatus = (await this.ezsp.ezspSetExtendedSecurityBitmask(extended));
865
+ if (extSecStatus !== enums_2.EzspStatus.SUCCESS) {
866
+ throw new Error(`[INIT FORM] Failed to set extended security bitmask to ${extended} with status=${enums_2.EzspStatus[extSecStatus]}.`);
867
+ }
868
+ if (!fromBackup && STACK_CONFIGS[this.stackConfig].KEY_TABLE_SIZE) {
869
+ emberStatus = await this.ezsp.ezspClearKeyTable();
870
+ if (emberStatus !== enums_2.EmberStatus.SUCCESS) {
871
+ throw new Error(`[INIT FORM] Failed to clear key table with status=${enums_2.EmberStatus[emberStatus]}.`);
872
+ }
873
+ }
874
+ const netParams = {
875
+ panId,
876
+ extendedPanId,
877
+ radioTxPower: 5,
878
+ radioChannel,
879
+ joinMethod: enums_2.EmberJoinMethod.MAC_ASSOCIATION,
880
+ nwkManagerId: consts_2.ZIGBEE_COORDINATOR_ADDRESS,
881
+ nwkUpdateId: 0,
882
+ channels: consts_2.EMBER_ALL_802_15_4_CHANNELS_MASK,
883
+ };
884
+ console.log(`[INIT FORM] Forming new network with: ${JSON.stringify(netParams)}`);
885
+ emberStatus = (await this.ezsp.ezspFormNetwork(netParams));
886
+ if (emberStatus !== enums_2.EmberStatus.SUCCESS) {
887
+ throw new Error(`[INIT FORM] Failed form network request with status=${enums_2.EmberStatus[emberStatus]}.`);
888
+ }
889
+ await this.oneWaitress.startWaitingForEvent({ eventName: OneWaitressEvents.STACK_STATUS_NETWORK_UP }, DEFAULT_NETWORK_REQUEST_TIMEOUT, '[INIT FORM] Form network');
890
+ const stStatus = await this.ezsp.ezspStartWritingStackTokens();
891
+ debug(`[INIT FORM] Start writing stack tokens status=${enums_2.EzspStatus[stStatus]}.`);
892
+ console.log(`[INIT FORM] New network formed!`);
893
+ }
894
+ /**
895
+ * Loads currently stored backup and returns it in internal backup model.
896
+ */
897
+ async getStoredBackup() {
898
+ try {
899
+ await mz_1.fs.access(this.backupPath);
900
+ }
901
+ catch (error) {
902
+ return null;
903
+ }
904
+ let data;
905
+ try {
906
+ data = JSON.parse((await mz_1.fs.readFile(this.backupPath)).toString());
907
+ }
908
+ catch (error) {
909
+ throw new Error(`[BACKUP] Coordinator backup is corrupted.`);
910
+ }
911
+ if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
912
+ if (data.metadata?.version !== 1) {
913
+ throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
914
+ }
915
+ if (!data.stack_specific?.ezsp || !data.metadata.internal.ezspVersion) {
916
+ throw new Error(`[BACKUP] Specified backup is not EZSP.`);
917
+ }
918
+ if (data.metadata.internal.ezspVersion < BACKUP_OLDEST_SUPPORTED_EZSP_VERSION) {
919
+ throw new Error(`[BACKUP] Specified backup is not a supported EZSP version (min: ${BACKUP_OLDEST_SUPPORTED_EZSP_VERSION}).`);
920
+ }
921
+ return utils_1.BackupUtils.fromUnifiedBackup(data);
922
+ }
923
+ else {
924
+ throw new Error(`[BACKUP] Unknown backup format.`);
925
+ }
926
+ }
927
+ /**
928
+ * Export link keys for backup.
929
+ *
930
+ * @return List of keys data with AES hashed keys
931
+ */
932
+ async exportLinkKeys() {
933
+ const [confStatus, keyTableSize] = (await this.ezsp.ezspGetConfigurationValue(enums_1.EzspConfigId.KEY_TABLE_SIZE));
934
+ if (confStatus !== enums_2.EzspStatus.SUCCESS) {
935
+ throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${enums_2.EzspStatus[confStatus]}.`);
936
+ }
937
+ let deviceEui64;
938
+ let plaintextKey;
939
+ let apsKeyMeta;
940
+ let status;
941
+ const keyList = [];
942
+ for (let i = 0; i < keyTableSize; i++) {
943
+ [deviceEui64, plaintextKey, apsKeyMeta, status] = (await this.ezsp.ezspExportLinkKeyByIndex(i));
944
+ debug(`[BACKUP] Export link key at index ${i}, status=${enums_2.SLStatus[status]}.`);
945
+ // only include key if we could retrieve one at index and hash it properly
946
+ if (status === enums_2.SLStatus.OK) {
947
+ // Rather than give the real link key, the backup contains a hashed version of the key.
948
+ // This is done to prevent a compromise of the backup data from compromising the current link keys.
949
+ // This is per the Smart Energy spec.
950
+ const [hashStatus, hashedKey] = (await this.emberAesHashSimple(plaintextKey.contents));
951
+ if (hashStatus === enums_2.EmberStatus.SUCCESS) {
952
+ keyList.push({
953
+ deviceEui64,
954
+ key: { contents: hashedKey },
955
+ outgoingFrameCounter: apsKeyMeta.outgoingFrameCounter,
956
+ incomingFrameCounter: apsKeyMeta.incomingFrameCounter,
957
+ });
958
+ }
959
+ else {
960
+ // this should never happen?
961
+ console.error(`[BACKUP] Failed to hash link key at index ${i} with status=${enums_2.EmberStatus[hashStatus]}. Omitting from backup.`);
962
+ }
963
+ }
964
+ }
965
+ console.log(`[BACKUP] Retrieved ${keyList.length} link keys.`);
966
+ return keyList;
967
+ }
968
+ /**
969
+ * Import link keys from backup.
970
+ *
971
+ * @param backupData
972
+ */
973
+ async importLinkKeys(backupData) {
974
+ if (!backupData?.length) {
975
+ return;
976
+ }
977
+ const [confStatus, keyTableSize] = (await this.ezsp.ezspGetConfigurationValue(enums_1.EzspConfigId.KEY_TABLE_SIZE));
978
+ if (confStatus !== enums_2.EzspStatus.SUCCESS) {
979
+ throw new Error(`[BACKUP] Failed to retrieve key table size from NCP with status=${enums_2.EzspStatus[confStatus]}.`);
980
+ }
981
+ if (backupData.length > keyTableSize) {
982
+ throw new Error(`[BACKUP] Current key table of ${keyTableSize} is too small to import backup of ${backupData.length}!`);
983
+ }
984
+ const networkStatus = (await this.emberNetworkState());
985
+ if (networkStatus !== enums_2.EmberNetworkStatus.NO_NETWORK) {
986
+ throw new Error(`[BACKUP] Cannot import TC data while network is up, networkStatus=${enums_2.EmberNetworkStatus[networkStatus]}.`);
987
+ }
988
+ let status;
989
+ for (let i = 0; i < keyTableSize; i++) {
990
+ if (i >= backupData.length) {
991
+ // erase any key index not present in backup but available on the NCP
992
+ status = (await this.ezsp.ezspEraseKeyTableEntry(i));
993
+ }
994
+ else {
995
+ const importStatus = (await this.ezsp.ezspImportLinkKey(i, backupData[i].deviceEui64, backupData[i].key));
996
+ status = ((importStatus === enums_2.SLStatus.OK) ? enums_2.EmberStatus.SUCCESS : enums_2.EmberStatus.KEY_TABLE_INVALID_ADDRESS);
997
+ }
998
+ if (status !== enums_2.EmberStatus.SUCCESS) {
999
+ throw new Error(`[BACKUP] Failed to ${((i >= backupData.length) ? "erase" : "set")} key table entry at index ${i} `
1000
+ + `with status=${enums_2.EmberStatus[status]}`);
1001
+ }
1002
+ }
1003
+ debug(`[BACKUP] Imported ${backupData.length} keys.`);
1004
+ }
1005
+ /**
1006
+ * Routine to update the network key and broadcast the update to the network after a set time.
1007
+ * NOTE: This should run at a large interval, but before the uint32_t of the frame counter is able to reach all Fs (can't wrap to 0).
1008
+ * This may disrupt sleepy end devices that miss the update, but they should be able to TC rejoin (in most cases...).
1009
+ * On the other hand, the more often this runs, the more secure the network is...
1010
+ */
1011
+ async broadcastNetworkKeyUpdate() {
1012
+ return new Promise((resolve, reject) => {
1013
+ this.requestQueue.enqueue(async () => {
1014
+ console.warn(`[TRUST CENTER] Performing a network key update. This might take a while and disrupt normal operation.`);
1015
+ // zero-filled = let stack generate new random network key
1016
+ let status = await this.ezsp.ezspBroadcastNextNetworkKey({ contents: Buffer.alloc(consts_1.EMBER_ENCRYPTION_KEY_SIZE) });
1017
+ if (status !== enums_2.EmberStatus.SUCCESS) {
1018
+ console.error(`[TRUST CENTER] Failed to broadcast next network key with status=${enums_2.EmberStatus[status]}.`);
1019
+ return status;
1020
+ }
1021
+ // XXX: this will block other requests for a while, but should ensure the key propagates without interference?
1022
+ // could also stop dispatching entirely and do this outside the queue if necessary/better
1023
+ await (0, utils_1.Wait)(BROADCAST_NETWORK_KEY_SWITCH_WAIT_TIME);
1024
+ status = (await this.ezsp.ezspBroadcastNetworkKeySwitch());
1025
+ if (status !== enums_2.EmberStatus.SUCCESS) {
1026
+ // XXX: Not sure how likely this is, but this is bad, probably should hard fail?
1027
+ console.error(`[TRUST CENTER] Failed to broadcast network key switch with status=${enums_2.EmberStatus[status]}.`);
1028
+ return status;
1029
+ }
1030
+ resolve();
1031
+ return status;
1032
+ }, reject);
1033
+ });
1034
+ }
1035
+ /**
1036
+ * Received when EZSP layer alerts of a problem that needs the NCP to be reset.
1037
+ * @param status
1038
+ */
1039
+ async onNcpNeedsResetAndInit(status) {
1040
+ console.error(`!!! NCP FATAL ERROR reason=${enums_2.EzspStatus[status]}. ATTEMPTING RESET... !!!`);
1041
+ try {
1042
+ await this.stop();
1043
+ await (0, utils_1.Wait)(500); // just because
1044
+ await this.start();
1045
+ }
1046
+ catch (err) {
1047
+ console.error(`Failed to reset and init NCP. ${err}`);
1048
+ this.emit(events_1.Events.disconnected);
1049
+ }
1050
+ }
1051
+ /**
1052
+ * Called right before a NCP reset.
1053
+ */
1054
+ async onNCPPreReset() {
1055
+ this.requestQueue.stopDispatching();
1056
+ }
1057
+ /**
1058
+ * Called right after a NCP reset, right before the creation of endpoints.
1059
+ */
1060
+ async onNCPPostReset() {
1061
+ this.requestQueue.startDispatching();
1062
+ this.watchdogCountersHandle = setInterval(this.watchdogCounters.bind(this), WATCHDOG_COUNTERS_FEED_INTERVAL);
1063
+ }
1064
+ /**
1065
+ * Handle changes in groups that needs to be propagated to the NCP multicast table.
1066
+ *
1067
+ * XXX: Since Z2M doesn't explicitly check-in downstream when groups are created/removed, we look at outgoing genGroups commands.
1068
+ * If the NCP doesn't know about groups, it can miss messages from some devices (remotes for example), so we add it...
1069
+ *
1070
+ * @param commandId
1071
+ * @param groupId
1072
+ */
1073
+ async onGroupChange(commandId, groupId) {
1074
+ switch (commandId) {
1075
+ case cluster_1.default.genGroups.commands.add.ID: {
1076
+ // check if group already in multicast table, should not happen...
1077
+ const existingIndex = this.multicastTable.findIndex((e) => ((e != null) && (e.multicastId === groupId)));
1078
+ if (existingIndex == -1) {
1079
+ // find first unused index
1080
+ const newEntryIndex = this.multicastTable.findIndex((e) => (!e));
1081
+ if (newEntryIndex != -1) {
1082
+ const newEntry = {
1083
+ multicastId: groupId,
1084
+ endpoint: endpoints_1.FIXED_ENDPOINTS[0].endpoint,
1085
+ networkIndex: endpoints_1.FIXED_ENDPOINTS[0].networkIndex,
1086
+ };
1087
+ const status = (await this.ezsp.ezspSetMulticastTableEntry(newEntryIndex, newEntry));
1088
+ if (status !== enums_2.EmberStatus.SUCCESS) {
1089
+ console.error(`Failed to register group "${groupId}" in multicast table at index "${newEntryIndex}" with status=${enums_2.EmberStatus[status]}.`);
1090
+ }
1091
+ else {
1092
+ debug(`Registered multicast table entry: ${JSON.stringify(newEntry)}.`);
1093
+ }
1094
+ // always assume "it worked" to keep sync with Z2M first, NCP second, otherwise trouble might arise... should always work anyway
1095
+ this.multicastTable[newEntryIndex] = newEntry;
1096
+ }
1097
+ else {
1098
+ console.warn(`Coordinator multicast table is full (max: ${STACK_CONFIGS[this.stackConfig].MULTICAST_TABLE_SIZE}). `
1099
+ + `Some devices in new groups may not work properly, including in group "${groupId}". `
1100
+ + `If that happens, please remove groups to be below the limit. `
1101
+ + `Removed groups are only removed from coordinator after a Zigbee2MQTT restart.`);
1102
+ }
1103
+ }
1104
+ else {
1105
+ debug(`Added group "${groupId}", but local table says it is already registered at index "${existingIndex}". Skipping.`);
1106
+ }
1107
+ break;
1108
+ }
1109
+ // NOTE: Can't remove groups, since we watch from command exec to group members, that would trigger from any removed member,
1110
+ // even though the group might still exist...
1111
+ // Leaving this here (since it's done...), just in case we get better notifications for groups from upstream.
1112
+ // case Cluster.genGroups.commands.remove.ID: {
1113
+ // const entryIndex = this.multicastTable.findIndex((e) => ((e != null) && (e.multicastId === groupId)));
1114
+ // // just in case, never remove GP at i zero, should never be the case...
1115
+ // if (entryIndex > 0) {
1116
+ // const entry = this.multicastTable[entryIndex];
1117
+ // entry.endpoint = 0;// signals "not in use" in the stack
1118
+ // const status = (await this.ezsp.ezspSetMulticastTableEntry(entryIndex, entry));
1119
+ // if (status !== EmberStatus.SUCCESS) {
1120
+ // console.error(`Failed to remove multicast table entry at index "${entryIndex}" for group "${groupId}".`);
1121
+ // } else {
1122
+ // debug(`Removed multicast table entry at index "${entryIndex}".`);
1123
+ // }
1124
+ // // always assume "it worked" to keep sync with Z2M first, NCP second, otherwise trouble might arise... should always work anyway
1125
+ // this.multicastTable[entryIndex] = null;
1126
+ // } else {
1127
+ // debug(`Removed group "${groupId}", but local table did not have a reference to it.`);
1128
+ // }
1129
+ // break;
1130
+ // }
1131
+ // case Cluster.genGroups.commands.removeAll.ID: {
1132
+ // // this can create quite a few NCP calls, but hopefully shouldn't happen often
1133
+ // // always skip green power at i==0
1134
+ // for (let i = 1; i < this.multicastTable.length; i++) {
1135
+ // const entry = this.multicastTable[i];
1136
+ // if (entry != null) {
1137
+ // entry.endpoint = 0;// signals "not in use" in the stack
1138
+ // const status = (await this.ezsp.ezspSetMulticastTableEntry(i, entry));
1139
+ // if (status !== EmberStatus.SUCCESS) {
1140
+ // console.error(`Failed to remove multicast entry at index "${i}" with status=${EmberStatus[status]}.`);
1141
+ // } else {
1142
+ // debug(`Removed multicast table entry at index "${i}".`);
1143
+ // }
1144
+ // }
1145
+ // this.multicastTable[i] = null;
1146
+ // }
1147
+ // break;
1148
+ // }
1149
+ }
1150
+ }
1151
+ //---- START Events
1152
+ //---- END Events
1153
+ //---- START Cache-enabled EZSP wrappers
1154
+ /**
1155
+ * Clear the cached network values (set to invalid values).
1156
+ */
1157
+ clearNetworkCache() {
1158
+ this.networkCache = (0, initters_1.initNetworkCache)();
1159
+ }
1160
+ /**
1161
+ * Return the current network state.
1162
+ * This call caches the results on the host to prevent frequent EZSP transactions.
1163
+ * Check against UNKNOWN_NETWORK_STATE for validity.
1164
+ */
1165
+ async emberNetworkState() {
1166
+ if (this.networkCache.status === consts_2.UNKNOWN_NETWORK_STATE) {
1167
+ const networkStatus = (await this.ezsp.ezspNetworkState());
1168
+ this.networkCache.status = networkStatus;
1169
+ }
1170
+ return this.networkCache.status;
1171
+ }
1172
+ /**
1173
+ * Return the EUI 64 of the local node
1174
+ * This call caches the results on the host to prevent frequent EZSP transactions.
1175
+ * Check against BLANK_EUI64 for validity.
1176
+ */
1177
+ async emberGetEui64() {
1178
+ if (this.networkCache.eui64 === consts_2.BLANK_EUI64) {
1179
+ this.networkCache.eui64 = (await this.ezsp.ezspGetEui64());
1180
+ }
1181
+ return this.networkCache.eui64;
1182
+ }
1183
+ /**
1184
+ * Return the PAN ID of the local node.
1185
+ * This call caches the results on the host to prevent frequent EZSP transactions.
1186
+ * Check against INVALID_PAN_ID for validity.
1187
+ */
1188
+ async emberGetPanId() {
1189
+ if (this.networkCache.parameters.panId === consts_2.INVALID_PAN_ID) {
1190
+ const [status, , parameters] = (await this.ezsp.ezspGetNetworkParameters());
1191
+ if (status === enums_2.EmberStatus.SUCCESS) {
1192
+ this.networkCache.parameters = parameters;
1193
+ }
1194
+ else {
1195
+ console.error(`Failed to get PAN ID (via network parameters) with status=${enums_2.EmberStatus[status]}.`);
1196
+ }
1197
+ }
1198
+ return this.networkCache.parameters.panId;
1199
+ }
1200
+ /**
1201
+ * Return the Extended PAN ID of the local node.
1202
+ * This call caches the results on the host to prevent frequent EZSP transactions.
1203
+ * Check against BLANK_EXTENDED_PAN_ID for validity.
1204
+ */
1205
+ async emberGetExtendedPanId() {
1206
+ if ((0, es6_1.default)(this.networkCache.parameters.extendedPanId, consts_2.BLANK_EXTENDED_PAN_ID)) {
1207
+ const [status, , parameters] = (await this.ezsp.ezspGetNetworkParameters());
1208
+ if (status === enums_2.EmberStatus.SUCCESS) {
1209
+ this.networkCache.parameters = parameters;
1210
+ }
1211
+ else {
1212
+ console.error(`Failed to get Extended PAN ID (via network parameters) with status=${enums_2.EmberStatus[status]}.`);
1213
+ }
1214
+ }
1215
+ return this.networkCache.parameters.extendedPanId;
1216
+ }
1217
+ /**
1218
+ * Return the radio channel (uint8_t) of the current network.
1219
+ * This call caches the results on the host to prevent frequent EZSP transactions.
1220
+ * Check against INVALID_RADIO_CHANNEL for validity.
1221
+ */
1222
+ async emberGetRadioChannel() {
1223
+ if (this.networkCache.parameters.radioChannel === consts_2.INVALID_RADIO_CHANNEL) {
1224
+ const [status, , parameters] = (await this.ezsp.ezspGetNetworkParameters());
1225
+ if (status === enums_2.EmberStatus.SUCCESS) {
1226
+ this.networkCache.parameters = parameters;
1227
+ }
1228
+ else {
1229
+ console.error(`Failed to get radio channel (via network parameters) with status=${enums_2.EmberStatus[status]}.`);
1230
+ }
1231
+ }
1232
+ return this.networkCache.parameters.radioChannel;
1233
+ }
1234
+ // queued
1235
+ async emberStartEnergyScan() {
1236
+ return new Promise((resolve, reject) => {
1237
+ this.requestQueue.enqueue(async () => {
1238
+ const status = (await this.ezsp.ezspStartScan(enums_2.EzspNetworkScanType.ENERGY_SCAN, consts_2.EMBER_ALL_802_15_4_CHANNELS_MASK, ENERGY_SCAN_DURATION));
1239
+ if (status !== enums_2.SLStatus.OK) {
1240
+ console.error(`Failed energy scan request with status=${enums_2.SLStatus[status]}.`);
1241
+ return enums_2.EmberStatus.ERR_FATAL;
1242
+ }
1243
+ // TODO: result in logs only atm, since UI doesn't support it
1244
+ resolve();
1245
+ return enums_2.EmberStatus.SUCCESS;
1246
+ }, reject);
1247
+ });
1248
+ }
1249
+ //---- END Cache-enabled EZSP wrappers
1250
+ //---- START EZSP wrappers
1251
+ /**
1252
+ * Ensure the Host & NCP are aligned on protocols using version.
1253
+ * Cache the retrieved information.
1254
+ *
1255
+ * NOTE: currently throws on mismatch until support for lower versions is implemented (not planned atm)
1256
+ *
1257
+ * Does nothing if ncpNeedsResetAndInit == true.
1258
+ */
1259
+ async emberVersion() {
1260
+ // Note that NCP == Network Co-Processor
1261
+ // the EZSP protocol version that the Host is running, we are the host so we set this value
1262
+ const hostEzspProtocolVer = consts_1.EZSP_PROTOCOL_VERSION;
1263
+ // send the Host version number to the NCP.
1264
+ // The NCP returns the EZSP version that the NCP is running along with the stackType and stackVersion
1265
+ const [ncpEzspProtocolVer, ncpStackType, ncpStackVer] = (await this.ezsp.ezspVersion(hostEzspProtocolVer));
1266
+ // verify that the stack type is what is expected
1267
+ if (ncpStackType !== consts_1.EZSP_STACK_TYPE_MESH) {
1268
+ throw new Error(`Stack type ${ncpStackType} is not expected!`);
1269
+ }
1270
+ // verify that the NCP EZSP Protocol version is what is expected
1271
+ if (ncpEzspProtocolVer !== consts_1.EZSP_PROTOCOL_VERSION) {
1272
+ throw new Error(`NCP EZSP protocol version of ${ncpEzspProtocolVer} does not match Host version ${hostEzspProtocolVer}`);
1273
+ }
1274
+ debug(`NCP info: EZSPVersion=${ncpEzspProtocolVer} StackType=${ncpStackType} StackVersion=${ncpStackVer}`);
1275
+ const [status, versionStruct] = (await this.ezsp.ezspGetVersionStruct());
1276
+ if (status !== enums_2.EzspStatus.SUCCESS) {
1277
+ // NCP has old style version number
1278
+ debug(`NCP has old-style version number.`);
1279
+ this.version = {
1280
+ ezsp: ncpEzspProtocolVer,
1281
+ revision: `${ncpStackVer}`,
1282
+ major: ncpStackVer,
1283
+ minor: 0,
1284
+ patch: 0,
1285
+ special: 0,
1286
+ build: 0,
1287
+ type: enums_2.EmberVersionType.GA, // default...
1288
+ };
1289
+ }
1290
+ else {
1291
+ // NCP has new style version number
1292
+ this.version = {
1293
+ ezsp: ncpEzspProtocolVer,
1294
+ revision: `${versionStruct.major}.${versionStruct.minor}.${versionStruct.patch} [${enums_2.EmberVersionType[versionStruct.type]}]`,
1295
+ ...versionStruct,
1296
+ };
1297
+ if (versionStruct.type !== enums_2.EmberVersionType.GA) {
1298
+ console.warn(`NCP is running a non-GA version (${enums_2.EmberVersionType[versionStruct.type]}).`);
1299
+ }
1300
+ }
1301
+ debug(`NCP version info: ${JSON.stringify(this.version)}`);
1302
+ }
1303
+ /**
1304
+ * This function sets an EZSP config value.
1305
+ * WARNING: Do not call for values that cannot be set after init without first resetting NCP (like table sizes).
1306
+ * To avoid an extra NCP call, this does not check for it.
1307
+ * @param configId
1308
+ * @param value uint16_t
1309
+ * @returns
1310
+ */
1311
+ async emberSetEzspConfigValue(configId, value) {
1312
+ const status = (await this.ezsp.ezspSetConfigurationValue(configId, value));
1313
+ debug(`[EzspConfigId] SET "${enums_1.EzspConfigId[configId]}" TO "${value}" with status=${enums_2.EzspStatus[status]}.`);
1314
+ if (status === enums_2.EzspStatus.ERROR_INVALID_ID) {
1315
+ // can be ZLL where not all NCPs need or support it.
1316
+ console.warn(`[EzspConfigId] Unsupported configuration ID ${enums_1.EzspConfigId[configId]} by NCP.`);
1317
+ }
1318
+ else if (status !== enums_2.EzspStatus.SUCCESS) {
1319
+ // don't fail in case a set value gets called "out of time"
1320
+ console.error(`[EzspConfigId] Failed to SET "${enums_1.EzspConfigId[configId]}" TO "${value}" with status=${enums_2.EzspStatus[status]}.`);
1321
+ }
1322
+ return status;
1323
+ }
1324
+ /**
1325
+ * This function sets an EZSP value.
1326
+ * @param valueId
1327
+ * @param valueLength uint8_t
1328
+ * @param value uint8_t *
1329
+ * @returns
1330
+ */
1331
+ async emberSetEzspValue(valueId, valueLength, value) {
1332
+ const status = (await this.ezsp.ezspSetValue(valueId, valueLength, value));
1333
+ debug(`[EzspValueId] SET "${enums_1.EzspValueId[valueId]}" TO "${value}" with status=${enums_2.EzspStatus[status]}.`);
1334
+ return status;
1335
+ }
1336
+ /**
1337
+ * This function sets an EZSP policy.
1338
+ * @param policyId
1339
+ * @param decisionId Can be bitop
1340
+ * @returns
1341
+ */
1342
+ async emberSetEzspPolicy(policyId, decisionId) {
1343
+ const status = (await this.ezsp.ezspSetPolicy(policyId, decisionId));
1344
+ debug(`[EzspPolicyId] SET "${enums_1.EzspPolicyId[policyId]}" TO "${decisionId}" with status=${enums_2.EzspStatus[status]}.`);
1345
+ return status;
1346
+ }
1347
+ /**
1348
+ * Here we convert the normal Ember AES hash call to the specialized EZSP call.
1349
+ * This came about because we cannot pass a block of data that is
1350
+ * both input and output into EZSP. The block must be broken up into two
1351
+ * elements. We unify the two pieces here to make it invisible to the users.
1352
+ * @param context EmberAesMmoHashContext *
1353
+ * @param finalize
1354
+ * @param data uint8_t * Expected of valid length (as in, not larger alloc)
1355
+ * @returns status
1356
+ * @returns result context or null
1357
+ */
1358
+ async aesMmoHash(context, finalize, data) {
1359
+ if (data.length > 255) {
1360
+ throw new Error(enums_2.EzspStatus[enums_2.EzspStatus.ERROR_INVALID_CALL]);
1361
+ }
1362
+ const [status, reContext] = (await this.ezsp.ezspAesMmoHash(context, finalize, data));
1363
+ return [status, reContext];
1364
+ }
1365
+ /**
1366
+ * This routine processes the passed chunk of data and updates
1367
+ * the hash calculation based on it. The data passed in MUST
1368
+ * have a length that is a multiple of 16.
1369
+ *
1370
+ * @param context EmberAesMmoHashContext* A pointer to the location of the hash context to update.
1371
+ * @param data const uint8_t* A pointer to the location of the data to hash.
1372
+ *
1373
+ * @returns An ::EmberStatus value indicating EMBER_SUCCESS if the hash was
1374
+ * calculated successfully. EMBER_INVALID_CALL if the block size is not a
1375
+ * multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
1376
+ * data exceeds the maximum limits of the hash function.
1377
+ * @returns result context or null
1378
+ */
1379
+ async emberAesMmoHashUpdate(context, data) {
1380
+ return this.aesMmoHash(context, false /*finalize?*/, data);
1381
+ }
1382
+ /**
1383
+ * This routine processes the passed chunk of data (if non-NULL)
1384
+ * and update the hash context that is passed in. In then performs
1385
+ * the final calculations on the hash and returns the final answer
1386
+ * in the result parameter of the ::EmberAesMmoHashContext structure.
1387
+ * The length of the data passed in may be any value, it does not have
1388
+ * to be a multiple of 16.
1389
+ *
1390
+ * @param context EmberAesMmoHashContext * A pointer to the location of the hash context to finalize.
1391
+ * @param data uint8_t * A pointer to the location of data to hash. May be NULL.
1392
+ *
1393
+ * @returns An ::EmberStatus value indicating EMBER_SUCCESS if the hash was
1394
+ * calculated successfully. EMBER_INVALID_CALL if the block size is not a
1395
+ * multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
1396
+ * data exceeds the maximum limits of the hash function.
1397
+ * @returns result context or null
1398
+ */
1399
+ async emberAesMmoHashFinal(context, data) {
1400
+ return this.aesMmoHash(context, true /*finalize?*/, data);
1401
+ }
1402
+ /**
1403
+ * This is a convenience method when the hash data is less than 255
1404
+ * bytes. It inits, updates, and finalizes the hash in one function call.
1405
+ *
1406
+ * @param data const uint8_t* The data to hash. Expected of valid length (as in, not larger alloc)
1407
+ *
1408
+ * @returns An ::EmberStatus value indicating EMBER_SUCCESS if the hash was
1409
+ * calculated successfully. EMBER_INVALID_CALL if the block size is not a
1410
+ * multiple of 16 bytes, and EMBER_INDEX_OUT_OF_RANGE is returned when the
1411
+ * data exceeds the maximum limits of the hash function.
1412
+ * @returns result uint8_t* The location where the result of the hash will be written.
1413
+ */
1414
+ async emberAesHashSimple(data) {
1415
+ const context = (0, initters_1.aesMmoHashInit)();
1416
+ const [status, reContext] = (await this.emberAesMmoHashFinal(context, data));
1417
+ return [status, reContext?.result];
1418
+ }
1419
+ /**
1420
+ * Enable local permit join and optionally broadcast the ZDO Mgmt_Permit_Join_req message.
1421
+ * This API can be called from any device type and still return EMBER_SUCCESS.
1422
+ * If the API is called from an end device, the permit association bit will just be left off.
1423
+ *
1424
+ * @param duration uint8_t The duration that the permit join bit will remain on
1425
+ * and other devices will be able to join the current network.
1426
+ * @param broadcastMgmtPermitJoin whether or not to broadcast the ZDO Mgmt_Permit_Join_req message.
1427
+ *
1428
+ * @returns status of whether or not permit join was enabled.
1429
+ * @returns apsFrame Will be null if not broadcasting.
1430
+ * @returns messageTag The tag passed to ezspSend${x} function.
1431
+ */
1432
+ async emberPermitJoining(duration, broadcastMgmtPermitJoin) {
1433
+ let status = (await this.ezsp.ezspPermitJoining(duration));
1434
+ let apsFrame = null;
1435
+ let messageTag = null;
1436
+ debug(`Permit joining for ${duration} sec. status=${[status]}`);
1437
+ if (broadcastMgmtPermitJoin) {
1438
+ // `authentication`: TC significance always 1 (zb specs)
1439
+ [status, apsFrame, messageTag] = (await this.emberPermitJoiningRequest(consts_2.EMBER_BROADCAST_ADDRESS, duration, 1, this.defaultApsOptions));
1440
+ }
1441
+ return [status, apsFrame, messageTag];
1442
+ }
1443
+ /**
1444
+ * Set the trust center policy bitmask using decision.
1445
+ * @param decision
1446
+ * @returns
1447
+ */
1448
+ async emberSetJoinPolicy(decision) {
1449
+ let policy = enums_1.EzspDecisionBitmask.DEFAULT_CONFIGURATION;
1450
+ if (decision == enums_2.EmberJoinDecision.USE_PRECONFIGURED_KEY) {
1451
+ policy = (enums_1.EzspDecisionBitmask.ALLOW_JOINS | enums_1.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS);
1452
+ }
1453
+ else if (decision == enums_2.EmberJoinDecision.SEND_KEY_IN_THE_CLEAR) {
1454
+ policy = (enums_1.EzspDecisionBitmask.ALLOW_JOINS | enums_1.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS | enums_1.EzspDecisionBitmask.SEND_KEY_IN_CLEAR);
1455
+ }
1456
+ else if (decision == enums_2.EmberJoinDecision.ALLOW_REJOINS_ONLY) {
1457
+ policy = enums_1.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS;
1458
+ }
1459
+ return this.emberSetEzspPolicy(enums_1.EzspPolicyId.TRUST_CENTER_POLICY, policy);
1460
+ }
1461
+ /**
1462
+ * Get Source Route Overhead
1463
+ *
1464
+ * Returns the number of bytes needed in a packet for source routing.
1465
+ * Since each hop consumes 2 bytes in the packet, this routine calculates the
1466
+ * total number of bytes needed based on number of hops to reach the destination.
1467
+ *
1468
+ * This function is called by the framework to determine the overhead required
1469
+ * in the network frame for source routing to a particular destination.
1470
+ *
1471
+ * @param destination The node id of the destination Ver.: always
1472
+ * @returns int8u The number of bytes needed for source routing in a packet.
1473
+ */
1474
+ async emberGetSourceRouteOverhead(destination) {
1475
+ const [status, value] = (await this.ezsp.ezspGetSourceRouteOverhead(destination));
1476
+ if (status === enums_2.EzspStatus.SUCCESS) {
1477
+ return value;
1478
+ }
1479
+ else {
1480
+ debug(`Failed to get source route overhead (via extended value), status=${enums_2.EzspStatus[status]}.`);
1481
+ }
1482
+ return 0;
1483
+ }
1484
+ /**
1485
+ * Return the maximum size of the payload that the Application Support sub-layer will accept for
1486
+ * the given message type, destination, and APS frame.
1487
+ *
1488
+ * The size depends on multiple factors, including the security level in use and additional information
1489
+ * added to the message to support the various options.
1490
+ *
1491
+ * @param type The outgoing message type.
1492
+ * @param indexOrDestination uint16_t Depending on the message type, this is either the
1493
+ * EmberNodeId of the destination, an index into the address table, an index
1494
+ * into the binding table, the multicast identifier, or a broadcast address.
1495
+ * @param apsFrame EmberApsFrame *The APS frame for the message.
1496
+ * @return uint8_t The maximum APS payload length for the given message.
1497
+ */
1498
+ async maximumApsPayloadLength(type, indexOrDestination, apsFrame) {
1499
+ let destination = consts_2.EMBER_UNKNOWN_NODE_ID;
1500
+ let max = consts_2.MAXIMUM_APS_PAYLOAD_LENGTH; // uint8_t
1501
+ if ((apsFrame.options & enums_2.EmberApsOption.ENCRYPTION) !== 0) {
1502
+ max -= consts_2.APS_ENCRYPTION_OVERHEAD;
1503
+ }
1504
+ if ((apsFrame.options & enums_2.EmberApsOption.SOURCE_EUI64) !== 0) {
1505
+ max -= consts_1.EUI64_SIZE;
1506
+ }
1507
+ if ((apsFrame.options & enums_2.EmberApsOption.DESTINATION_EUI64) !== 0) {
1508
+ max -= consts_1.EUI64_SIZE;
1509
+ }
1510
+ if ((apsFrame.options & enums_2.EmberApsOption.FRAGMENT) !== 0) {
1511
+ max -= consts_2.APS_FRAGMENTATION_OVERHEAD;
1512
+ }
1513
+ switch (type) {
1514
+ case enums_2.EmberOutgoingMessageType.DIRECT:
1515
+ destination = indexOrDestination;
1516
+ break;
1517
+ case enums_2.EmberOutgoingMessageType.VIA_ADDRESS_TABLE:
1518
+ destination = (await this.ezsp.ezspGetAddressTableRemoteNodeId(indexOrDestination));
1519
+ break;
1520
+ case enums_2.EmberOutgoingMessageType.VIA_BINDING:
1521
+ destination = (await this.ezsp.ezspGetBindingRemoteNodeId(indexOrDestination));
1522
+ break;
1523
+ case enums_2.EmberOutgoingMessageType.MULTICAST:
1524
+ // APS multicast messages include the two-byte group id and exclude the one-byte destination endpoint,
1525
+ // for a net loss of an extra byte.
1526
+ max--;
1527
+ break;
1528
+ case enums_2.EmberOutgoingMessageType.BROADCAST:
1529
+ break;
1530
+ default:
1531
+ break;
1532
+ }
1533
+ max -= (await this.emberGetSourceRouteOverhead(destination));
1534
+ return max;
1535
+ }
1536
+ //---- END EZSP wrappers
1537
+ //---- START Ember ZDO
1538
+ /**
1539
+ * ZDO
1540
+ * Change the default radius for broadcast ZDO requests
1541
+ *
1542
+ * @param radius uint8_t The radius to be used for future ZDO request broadcasts.
1543
+ */
1544
+ setZDORequestRadius(radius) {
1545
+ this.zdoRequestRadius = radius;
1546
+ }
1547
+ /**
1548
+ * ZDO
1549
+ * Retrieve the default radius for broadcast ZDO requests
1550
+ *
1551
+ * @return uint8_t The radius to be used for future ZDO request broadcasts.
1552
+ */
1553
+ getZDORequestRadius() {
1554
+ return this.zdoRequestRadius;
1555
+ }
1556
+ /**
1557
+ * ZDO
1558
+ * Get the next device request sequence number.
1559
+ *
1560
+ * Requests have sequence numbers so that they can be matched up with the
1561
+ * responses. To avoid complexities, the library uses numbers with the high
1562
+ * bit clear and the stack uses numbers with the high bit set.
1563
+ *
1564
+ * @return uint8_t The next device request sequence number
1565
+ */
1566
+ nextZDORequestSequence() {
1567
+ return (this.zdoRequestSequence = ((++this.zdoRequestSequence) & APPLICATION_ZDO_SEQUENCE_MASK));
1568
+ }
1569
+ /**
1570
+ * ZDO
1571
+ *
1572
+ * @param destination
1573
+ * @param clusterId uint16_t
1574
+ * @param options
1575
+ * @param length uint8_t
1576
+ * @returns status Indicates success or failure (with reason) of send
1577
+ * @returns apsFrame The APS Frame resulting of the request being built and sent (`sequence` set from stack-given value).
1578
+ * @returns messageTag The tag passed to ezspSend${x} function.
1579
+ */
1580
+ async sendZDORequestBuffer(destination, clusterId, options) {
1581
+ if (this.zdoRequestBuffalo.getPosition() > consts_1.EZSP_MAX_FRAME_LENGTH) {
1582
+ return [enums_2.EmberStatus.MESSAGE_TOO_LONG, null, null];
1583
+ }
1584
+ const messageTag = this.nextZDORequestSequence();
1585
+ this.zdoRequestBuffalo.setCommandByte(0, messageTag);
1586
+ const apsFrame = {
1587
+ profileId: zdo_1.ZDO_PROFILE_ID,
1588
+ clusterId: clusterId,
1589
+ sourceEndpoint: zdo_1.ZDO_ENDPOINT,
1590
+ destinationEndpoint: zdo_1.ZDO_ENDPOINT,
1591
+ options: options,
1592
+ groupId: 0,
1593
+ sequence: 0, // set by stack
1594
+ };
1595
+ const messageContents = this.zdoRequestBuffalo.getWritten();
1596
+ if (destination === consts_2.EMBER_BROADCAST_ADDRESS || destination === consts_2.EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS
1597
+ || destination === consts_2.EMBER_SLEEPY_BROADCAST_ADDRESS) {
1598
+ debug(`~~~> [ZDO BROADCAST apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag}]`);
1599
+ const [status, apsSequence] = (await this.ezsp.ezspSendBroadcast(destination, apsFrame, this.getZDORequestRadius(), messageTag, messageContents));
1600
+ apsFrame.sequence = apsSequence;
1601
+ debug(`~~~> [SENT ZDO type=BROADCAST apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag} status=${enums_2.EmberStatus[status]}]`);
1602
+ return [status, apsFrame, messageTag];
1603
+ }
1604
+ else {
1605
+ debug(`~~~> [ZDO UNICAST apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag}]`);
1606
+ const [status, apsSequence] = (await this.ezsp.ezspSendUnicast(enums_2.EmberOutgoingMessageType.DIRECT, destination, apsFrame, messageTag, messageContents));
1607
+ apsFrame.sequence = apsSequence;
1608
+ debug(`~~~> [SENT ZDO type=DIRECT apsFrame=${JSON.stringify(apsFrame)} messageTag=${messageTag} status=${enums_2.EmberStatus[status]}]`);
1609
+ return [status, apsFrame, messageTag];
1610
+ }
1611
+ }
1612
+ /**
1613
+ * ZDO
1614
+ * Service Discovery Functions
1615
+ * Request the specified node to send a list of its endpoints that
1616
+ * match the specified application profile and, optionally, lists of input
1617
+ * and/or output clusters.
1618
+ * @param target The node whose matching endpoints are desired. The request can
1619
+ * be sent unicast or broadcast ONLY to the "RX-on-when-idle-address" (0xFFFD)
1620
+ * If sent as a broadcast, any node that has matching endpoints will send a
1621
+ * response.
1622
+ * @param profile uint16_t The application profile to match.
1623
+ * @param inCount uint8_t The number of input clusters. To not match any input
1624
+ * clusters, set this value to 0.
1625
+ * @param outCount uint8_t The number of output clusters. To not match any output
1626
+ * clusters, set this value to 0.
1627
+ * @param inClusters uint16_t * The list of input clusters.
1628
+ * @param outClusters uint16_t * The list of output clusters.
1629
+ * @param options The options to use when sending the unicast request. See
1630
+ * emberSendUnicast() for a description. This parameter is ignored if the target
1631
+ * is a broadcast address.
1632
+ * @returns An EmberStatus value. EMBER_SUCCESS, MESSAGE_TOO_LONG,
1633
+ * EMBER_NETWORK_DOWN or EMBER_NETWORK_BUSY.
1634
+ */
1635
+ async emberMatchDescriptorsRequest(target, profile, inClusters, outClusters, options) {
1636
+ // 2 bytes for NWK Address + 2 bytes for Profile Id + 1 byte for in Cluster Count
1637
+ // + in times 2 for 2 byte Clusters + out Cluster Count + out times 2 for 2 byte Clusters
1638
+ const length = (zdo_1.ZDO_MESSAGE_OVERHEAD + 2 + 2 + 1 + (inClusters.length * 2) + 1 + (outClusters.length * 2));
1639
+ // sanity check
1640
+ if (length > consts_1.EZSP_MAX_FRAME_LENGTH) {
1641
+ return [enums_2.EmberStatus.MESSAGE_TOO_LONG, null, null];
1642
+ }
1643
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1644
+ this.zdoRequestBuffalo.writeUInt16(target);
1645
+ this.zdoRequestBuffalo.writeUInt16(profile);
1646
+ this.zdoRequestBuffalo.writeUInt8(inClusters.length);
1647
+ this.zdoRequestBuffalo.writeListUInt16(inClusters);
1648
+ this.zdoRequestBuffalo.writeUInt8(outClusters.length);
1649
+ this.zdoRequestBuffalo.writeListUInt16(outClusters);
1650
+ debug(`~~~> [ZDO MATCH DESCRIPTOR target=${target} profile=${profile} inClusters=${inClusters} outClusters=${outClusters}]`);
1651
+ return this.sendZDORequestBuffer(target, zdo_1.MATCH_DESCRIPTORS_REQUEST, options);
1652
+ }
1653
+ /**
1654
+ * ZDO
1655
+ * Device Discovery Functions
1656
+ * Request the 16 bit network address of a node whose EUI64 is known.
1657
+ *
1658
+ * @param target The EUI64 of the node.
1659
+ * @param reportKids true to request that the target list their children
1660
+ * in the response.
1661
+ * @param childStartIndex uint8_t The index of the first child to list in the response.
1662
+ * Ignored if @c reportKids is false.
1663
+ *
1664
+ * @return An ::EmberStatus value.
1665
+ * - ::EMBER_SUCCESS - The request was transmitted successfully.
1666
+ * - ::EMBER_NO_BUFFERS - Insufficient message buffers were available to construct the request.
1667
+ * - ::EMBER_NETWORK_DOWN - The node is not part of a network.
1668
+ * - ::EMBER_NETWORK_BUSY - Transmission of the request failed.
1669
+ */
1670
+ async emberNetworkAddressRequest(target, reportKids, childStartIndex) {
1671
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1672
+ this.zdoRequestBuffalo.writeIeeeAddr(target);
1673
+ this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
1674
+ this.zdoRequestBuffalo.writeUInt8(childStartIndex);
1675
+ debug(`~~~> [ZDO NETWORK ADDRESS target=${target} reportKids=${reportKids} childStartIndex=${childStartIndex}]`);
1676
+ return this.sendZDORequestBuffer(consts_2.EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS, zdo_1.NETWORK_ADDRESS_REQUEST, enums_2.EmberApsOption.SOURCE_EUI64);
1677
+ }
1678
+ /**
1679
+ * ZDO
1680
+ * Device Discovery Functions
1681
+ * @brief Request the EUI64 of a node whose 16 bit network address is known.
1682
+ *
1683
+ * @param target uint16_t The network address of the node.
1684
+ * @param reportKids uint8_t true to request that the target list their children
1685
+ * in the response.
1686
+ * @param childStartIndex uint8_t The index of the first child to list in the response.
1687
+ * Ignored if reportKids is false.
1688
+ * @param options The options to use when sending the request. See ::emberSendUnicast() for a description.
1689
+ *
1690
+ * @return An ::EmberStatus value.
1691
+ * - ::EMBER_SUCCESS
1692
+ * - ::EMBER_NO_BUFFERS
1693
+ * - ::EMBER_NETWORK_DOWN
1694
+ * - ::EMBER_NETWORK_BUSY
1695
+ */
1696
+ async emberIeeeAddressRequest(target, reportKids, childStartIndex, options) {
1697
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1698
+ this.zdoRequestBuffalo.writeUInt16(target);
1699
+ this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
1700
+ this.zdoRequestBuffalo.writeUInt8(childStartIndex);
1701
+ debug(`~~~> [ZDO IEEE ADDRESS target=${target} reportKids=${reportKids} childStartIndex=${childStartIndex}]`);
1702
+ return this.sendZDORequestBuffer(target, zdo_1.IEEE_ADDRESS_REQUEST, options);
1703
+ }
1704
+ /**
1705
+ * ZDO
1706
+ * @param discoveryNodeId uint16_t
1707
+ * @param reportKids uint8_t
1708
+ * @param childStartIndex uint8_t
1709
+ * @param options
1710
+ * @param targetNodeIdOfRequest
1711
+ */
1712
+ async emberIeeeAddressRequestToTarget(discoveryNodeId, reportKids, childStartIndex, options, targetNodeIdOfRequest) {
1713
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1714
+ this.zdoRequestBuffalo.writeUInt16(discoveryNodeId);
1715
+ this.zdoRequestBuffalo.writeUInt8(reportKids ? 1 : 0);
1716
+ this.zdoRequestBuffalo.writeUInt8(childStartIndex);
1717
+ debug(`~~~> [ZDO IEEE ADDRESS targetNodeIdOfRequest=${targetNodeIdOfRequest} discoveryNodeId=${discoveryNodeId} `
1718
+ + `reportKids=${reportKids} childStartIndex=${childStartIndex}]`);
1719
+ return this.sendZDORequestBuffer(targetNodeIdOfRequest, zdo_1.IEEE_ADDRESS_REQUEST, options);
1720
+ }
1721
+ /**
1722
+ * ZDO
1723
+ *
1724
+ * @param target uint16_t
1725
+ * @param clusterId uint16_t
1726
+ * @param options
1727
+ * @returns
1728
+ */
1729
+ async emberSendZigDevRequestTarget(target, clusterId, options) {
1730
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1731
+ this.zdoRequestBuffalo.writeUInt16(target);
1732
+ return this.sendZDORequestBuffer(target, clusterId, options);
1733
+ }
1734
+ /**
1735
+ * ZDO
1736
+ * @brief Request the specified node to send the simple descriptor for
1737
+ * the specified endpoint.
1738
+ * The simple descriptor contains information specific
1739
+ * to a single endpoint. It describes the application profile identifier,
1740
+ * application device identifier, application device version, application flags,
1741
+ * application input clusters and application output clusters. It is defined in
1742
+ * the ZigBee Application Framework Specification.
1743
+ *
1744
+ * @param target uint16_t The node of interest.
1745
+ * @param targetEndpoint uint8_t The endpoint on the target node whose simple
1746
+ * descriptor is desired.
1747
+ * @param options The options to use when sending the request. See
1748
+ * emberSendUnicast() for a description.
1749
+ *
1750
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1751
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1752
+ */
1753
+ async emberSimpleDescriptorRequest(target, targetEndpoint, options) {
1754
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1755
+ this.zdoRequestBuffalo.writeUInt16(target);
1756
+ this.zdoRequestBuffalo.writeUInt8(targetEndpoint);
1757
+ debug(`~~~> [ZDO SIMPLE DESCRIPTOR target=${target} targetEndpoint=${targetEndpoint}]`);
1758
+ return this.sendZDORequestBuffer(target, zdo_1.SIMPLE_DESCRIPTOR_REQUEST, options);
1759
+ }
1760
+ /**
1761
+ * ZDO
1762
+ * @brief Send a request to remove a binding entry with the specified
1763
+ * contents from the specified node.
1764
+ *
1765
+ * @param target The node on which the binding will be removed.
1766
+ * @param source The source EUI64 in the binding entry.
1767
+ * @param sourceEndpoint The source endpoint in the binding entry.
1768
+ * @param clusterId The cluster ID in the binding entry.
1769
+ * @param type The type of binding, either ::UNICAST_BINDING,
1770
+ * ::MULTICAST_BINDING, or ::UNICAST_MANY_TO_ONE_BINDING.
1771
+ * ::UNICAST_MANY_TO_ONE_BINDING is an Ember-specific extension
1772
+ * and should be used only when the target is an Ember device.
1773
+ * @param destination The destination EUI64 in the binding entry for the
1774
+ * ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1775
+ * @param groupAddress The group address for the ::MULTICAST_BINDING.
1776
+ * @param destinationEndpoint The destination endpoint in the binding entry for
1777
+ * the ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1778
+ * @param options The options to use when sending the request. See
1779
+ * emberSendUnicast() for a description.
1780
+ *
1781
+ * @return An ::EmberStatus value.
1782
+ * - ::EMBER_SUCCESS
1783
+ * - ::EMBER_NO_BUFFERS
1784
+ * _ ::EMBER_NETWORK_DOWN
1785
+ * - ::EMBER_NETWORK_BUSY
1786
+ * @param target
1787
+ * @param bindClusterId
1788
+ * @param source
1789
+ * @param sourceEndpoint uint8_t
1790
+ * @param clusterId uint16_t
1791
+ * @param type uint8_t
1792
+ * @param destination
1793
+ * @param groupAddress uint16_t
1794
+ * @param destinationEndpoint uint8_t
1795
+ * @param options
1796
+ */
1797
+ async emberSendZigDevBindRequest(target, bindClusterId, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
1798
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
1799
+ this.zdoRequestBuffalo.writeIeeeAddr(source);
1800
+ this.zdoRequestBuffalo.writeUInt8(sourceEndpoint);
1801
+ this.zdoRequestBuffalo.writeUInt16(clusterId);
1802
+ this.zdoRequestBuffalo.writeUInt8(type);
1803
+ switch (type) {
1804
+ case zdo_1.UNICAST_BINDING:
1805
+ this.zdoRequestBuffalo.writeIeeeAddr(destination);
1806
+ this.zdoRequestBuffalo.writeUInt8(destinationEndpoint);
1807
+ break;
1808
+ case zdo_1.MULTICAST_BINDING:
1809
+ this.zdoRequestBuffalo.writeUInt16(groupAddress);
1810
+ break;
1811
+ default:
1812
+ return [enums_2.EmberStatus.ERR_FATAL, null, null];
1813
+ }
1814
+ return this.sendZDORequestBuffer(target, bindClusterId, options);
1815
+ }
1816
+ /**
1817
+ * ZDO
1818
+ * Send a request to create a binding entry with the specified
1819
+ * contents on the specified node.
1820
+ *
1821
+ * @param target The node on which the binding will be created.
1822
+ * @param source The source EUI64 in the binding entry.
1823
+ * @param sourceEndpoint The source endpoint in the binding entry.
1824
+ * @param clusterId The cluster ID in the binding entry.
1825
+ * @param type The type of binding, either ::UNICAST_BINDING,
1826
+ * ::MULTICAST_BINDING, or ::UNICAST_MANY_TO_ONE_BINDING.
1827
+ * ::UNICAST_MANY_TO_ONE_BINDING is an Ember-specific extension
1828
+ * and should be used only when the target is an Ember device.
1829
+ * @param destination The destination EUI64 in the binding entry for
1830
+ * ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1831
+ * @param groupAddress The group address for the ::MULTICAST_BINDING.
1832
+ * @param destinationEndpoint The destination endpoint in the binding entry for
1833
+ * the ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1834
+ * @param options The options to use when sending the request. See
1835
+ * emberSendUnicast() for a description.
1836
+ *
1837
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1838
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1839
+ */
1840
+ async emberBindRequest(target, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
1841
+ debug(`~~~> [ZDO BIND target=${target} source=${source} sourceEndpoint=${sourceEndpoint} clusterId=${clusterId} type=${type} `
1842
+ + `destination=${destination} groupAddress=${groupAddress} destinationEndpoint=${destinationEndpoint}]`);
1843
+ return this.emberSendZigDevBindRequest(target, zdo_1.BIND_REQUEST, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options);
1844
+ }
1845
+ /**
1846
+ * ZDO
1847
+ * Send a request to remove a binding entry with the specified
1848
+ * contents from the specified node.
1849
+ *
1850
+ * @param target The node on which the binding will be removed.
1851
+ * @param source The source EUI64 in the binding entry.
1852
+ * @param sourceEndpoint uint8_t The source endpoint in the binding entry.
1853
+ * @param clusterId uint16_t The cluster ID in the binding entry.
1854
+ * @param type uint8_t The type of binding, either ::UNICAST_BINDING,
1855
+ * ::MULTICAST_BINDING, or ::UNICAST_MANY_TO_ONE_BINDING.
1856
+ * ::UNICAST_MANY_TO_ONE_BINDING is an Ember-specific extension
1857
+ * and should be used only when the target is an Ember device.
1858
+ * @param destination The destination EUI64 in the binding entry for the
1859
+ * ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1860
+ * @param groupAddress The group address for the ::MULTICAST_BINDING.
1861
+ * @param destinationEndpoint uint8_t The destination endpoint in the binding entry for
1862
+ * the ::UNICAST_BINDING or ::UNICAST_MANY_TO_ONE_BINDING.
1863
+ * @param options The options to use when sending the request. See
1864
+ * emberSendUnicast() for a description.
1865
+ *
1866
+ * @return An ::EmberStatus value.
1867
+ * - ::EMBER_SUCCESS
1868
+ * - ::EMBER_NO_BUFFERS
1869
+ * _ ::EMBER_NETWORK_DOWN
1870
+ * - ::EMBER_NETWORK_BUSY
1871
+ */
1872
+ async emberUnbindRequest(target, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options) {
1873
+ debug(`~~~> [ZDO UNBIND target=${target} source=${source} sourceEndpoint=${sourceEndpoint} clusterId=${clusterId} type=${type} `
1874
+ + `destination=${destination} groupAddress=${groupAddress} destinationEndpoint=${destinationEndpoint}]`);
1875
+ return this.emberSendZigDevBindRequest(target, zdo_1.UNBIND_REQUEST, source, sourceEndpoint, clusterId, type, destination, groupAddress, destinationEndpoint, options);
1876
+ }
1877
+ /**
1878
+ * ZDO
1879
+ * Request the specified node to send a list of its active
1880
+ * endpoints. An active endpoint is one for which a simple descriptor is
1881
+ * available.
1882
+ *
1883
+ * @param target The node whose active endpoints are desired.
1884
+ * @param options The options to use when sending the request. See
1885
+ * emberSendUnicast() for a description.
1886
+ *
1887
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1888
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1889
+ */
1890
+ async emberActiveEndpointsRequest(target, options) {
1891
+ debug(`~~~> [ZDO ACTIVE ENDPOINTS target=${target}]`);
1892
+ return this.emberSendZigDevRequestTarget(target, zdo_1.ACTIVE_ENDPOINTS_REQUEST, options);
1893
+ }
1894
+ /**
1895
+ * ZDO
1896
+ * Request the specified node to send its power descriptor.
1897
+ * The power descriptor gives a dynamic indication of the power
1898
+ * status of the node. It describes current power mode,
1899
+ * available power sources, current power source and
1900
+ * current power source level. It is defined in the ZigBee
1901
+ * Application Framework Specification.
1902
+ *
1903
+ * @param target The node whose power descriptor is desired.
1904
+ * @param options The options to use when sending the request. See
1905
+ * emberSendUnicast() for a description.
1906
+ *
1907
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1908
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1909
+ */
1910
+ async emberPowerDescriptorRequest(target, options) {
1911
+ debug(`~~~> [ZDO POWER DESCRIPTOR target=${target}]`);
1912
+ return this.emberSendZigDevRequestTarget(target, zdo_1.POWER_DESCRIPTOR_REQUEST, options);
1913
+ }
1914
+ /**
1915
+ * ZDO
1916
+ * Request the specified node to send its node descriptor.
1917
+ * The node descriptor contains information about the capabilities of the ZigBee
1918
+ * node. It describes logical type, APS flags, frequency band, MAC capabilities
1919
+ * flags, manufacturer code and maximum buffer size. It is defined in the ZigBee
1920
+ * Application Framework Specification.
1921
+ *
1922
+ * @param target The node whose node descriptor is desired.
1923
+ * @param options The options to use when sending the request. See
1924
+ * emberSendUnicast() for a description.
1925
+ *
1926
+ * @return An ::EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1927
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1928
+ */
1929
+ async emberNodeDescriptorRequest(target, options) {
1930
+ debug(`~~~> [ZDO NODE DESCRIPTOR target=${target}]`);
1931
+ return this.emberSendZigDevRequestTarget(target, zdo_1.NODE_DESCRIPTOR_REQUEST, options);
1932
+ }
1933
+ /**
1934
+ * ZDO
1935
+ * Request the specified node to send its LQI (neighbor) table.
1936
+ * The response gives PAN ID, EUI64, node ID and cost for each neighbor. The
1937
+ * EUI64 is only available if security is enabled. The other fields in the
1938
+ * response are set to zero. The response format is defined in the ZigBee Device
1939
+ * Profile Specification.
1940
+ *
1941
+ * @param target The node whose LQI table is desired.
1942
+ * @param startIndex uint8_t The index of the first neighbor to include in the
1943
+ * response.
1944
+ * @param options The options to use when sending the request. See
1945
+ * emberSendUnicast() for a description.
1946
+ *
1947
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1948
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1949
+ */
1950
+ async emberLqiTableRequest(target, startIndex, options) {
1951
+ debug(`~~~> [ZDO LQI TABLE target=${target} startIndex=${startIndex}]`);
1952
+ return this.emberTableRequest(zdo_1.LQI_TABLE_REQUEST, target, startIndex, options);
1953
+ }
1954
+ /**
1955
+ * ZDO
1956
+ * Request the specified node to send its routing table.
1957
+ * The response gives destination node ID, status and many-to-one flags,
1958
+ * and the next hop node ID.
1959
+ * The response format is defined in the ZigBee Device
1960
+ * Profile Specification.
1961
+ *
1962
+ * @param target The node whose routing table is desired.
1963
+ * @param startIndex uint8_t The index of the first route entry to include in the
1964
+ * response.
1965
+ * @param options The options to use when sending the request. See
1966
+ * emberSendUnicast() for a description.
1967
+ *
1968
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1969
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1970
+ */
1971
+ async emberRoutingTableRequest(target, startIndex, options) {
1972
+ debug(`~~~> [ZDO ROUTING TABLE target=${target} startIndex=${startIndex}]`);
1973
+ return this.emberTableRequest(zdo_1.ROUTING_TABLE_REQUEST, target, startIndex, options);
1974
+ }
1975
+ /**
1976
+ * ZDO
1977
+ * Request the specified node to send its nonvolatile bindings.
1978
+ * The response gives source address, source endpoint, cluster ID, destination
1979
+ * address and destination endpoint for each binding entry. The response format
1980
+ * is defined in the ZigBee Device Profile Specification.
1981
+ * Note that bindings that have the Ember-specific ::UNICAST_MANY_TO_ONE_BINDING
1982
+ * type are reported as having the standard ::UNICAST_BINDING type.
1983
+ *
1984
+ * @param target The node whose binding table is desired.
1985
+ * @param startIndex uint8_t The index of the first binding entry to include in the
1986
+ * response.
1987
+ * @param options The options to use when sending the request. See
1988
+ * emberSendUnicast() for a description.
1989
+ *
1990
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
1991
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
1992
+ */
1993
+ async emberBindingTableRequest(target, startIndex, options) {
1994
+ debug(`~~~> [ZDO BINDING TABLE target=${target} startIndex=${startIndex}]`);
1995
+ return this.emberTableRequest(zdo_1.BINDING_TABLE_REQUEST, target, startIndex, options);
1996
+ }
1997
+ /**
1998
+ * ZDO
1999
+ *
2000
+ * @param clusterId uint16_t
2001
+ * @param target
2002
+ * @param startIndex uint8_t
2003
+ * @param options
2004
+ * @returns
2005
+ */
2006
+ async emberTableRequest(clusterId, target, startIndex, options) {
2007
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
2008
+ this.zdoRequestBuffalo.writeUInt8(startIndex);
2009
+ return this.sendZDORequestBuffer(target, clusterId, options);
2010
+ }
2011
+ /**
2012
+ * ZDO
2013
+ * Request the specified node to remove the specified device from
2014
+ * the network. The device to be removed must be the node to which the request
2015
+ * is sent or one of its children.
2016
+ *
2017
+ * @param target The node which will remove the device.
2018
+ * @param deviceAddress All zeros if the target is to remove itself from
2019
+ * the network or the EUI64 of a child of the target device to remove
2020
+ * that child.
2021
+ * @param leaveRequestFlags uint8_t A bitmask of leave options.
2022
+ * Include ::AND_REJOIN if the target is to rejoin the network immediately after leaving.
2023
+ * @param options The options to use when sending the request. See
2024
+ * emberSendUnicast() for a description.
2025
+ *
2026
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
2027
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
2028
+ */
2029
+ async emberLeaveRequest(target, deviceAddress, leaveRequestFlags, options) {
2030
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
2031
+ this.zdoRequestBuffalo.writeIeeeAddr(deviceAddress);
2032
+ this.zdoRequestBuffalo.writeUInt8(leaveRequestFlags);
2033
+ debug(`~~~> [ZDO LEAVE target=${target} deviceAddress=${deviceAddress} leaveRequestFlags=${leaveRequestFlags}]`);
2034
+ return this.sendZDORequestBuffer(target, zdo_1.LEAVE_REQUEST, options);
2035
+ }
2036
+ /**
2037
+ * ZDO
2038
+ * Request the specified node to allow or disallow association.
2039
+ *
2040
+ * @param target The node which will allow or disallow association. The request
2041
+ * can be broadcast by using a broadcast address (0xFFFC/0xFFFD/0xFFFF). No
2042
+ * response is sent if the request is broadcast.
2043
+ * @param duration uint8_t A value of 0x00 disables joining. A value of 0xFF enables
2044
+ * joining. Any other value enables joining for that number of seconds.
2045
+ * @param authentication uint8_t Controls Trust Center authentication behavior.
2046
+ * @param options The options to use when sending the request. See
2047
+ * emberSendUnicast() for a description. This parameter is ignored if the target
2048
+ * is a broadcast address.
2049
+ *
2050
+ * @return An EmberStatus value. ::EMBER_SUCCESS, ::EMBER_NO_BUFFERS,
2051
+ * ::EMBER_NETWORK_DOWN or ::EMBER_NETWORK_BUSY.
2052
+ */
2053
+ async emberPermitJoiningRequest(target, duration, authentication, options) {
2054
+ this.zdoRequestBuffalo.setPosition(zdo_1.ZDO_MESSAGE_OVERHEAD);
2055
+ this.zdoRequestBuffalo.writeUInt8(duration);
2056
+ this.zdoRequestBuffalo.writeUInt8(authentication);
2057
+ debug(`~~~> [ZDO PERMIT JOINING target=${target} duration=${duration} authentication=${authentication}]`);
2058
+ return this.sendZDORequestBuffer(target, zdo_1.PERMIT_JOINING_REQUEST, options);
2059
+ }
2060
+ //---- END Ember ZDO
2061
+ //-- START Adapter implementation
2062
+ static async isValidPath(path) {
2063
+ // For TCP paths we cannot get device information, therefore we cannot validate it.
2064
+ if (socketPortUtils_1.default.isTcpPath(path)) {
2065
+ return false;
2066
+ }
2067
+ try {
2068
+ return serialPortUtils_1.default.is((0, utils_1.RealpathSync)(path), autoDetectDefinitions);
2069
+ }
2070
+ catch (error) {
2071
+ debug(`Failed to determine if path is valid: '${error}'`);
2072
+ return false;
2073
+ }
2074
+ }
2075
+ static async autoDetectPath() {
2076
+ const paths = await serialPortUtils_1.default.find(autoDetectDefinitions);
2077
+ paths.sort((a, b) => (a < b) ? -1 : 1);
2078
+ return paths.length > 0 ? paths[0] : null;
2079
+ }
2080
+ async start() {
2081
+ console.log(`======== Ember Adapter Starting ========`);
2082
+ this.initVariables();
2083
+ debug(`Starting EZSP with stack configuration: "${this.stackConfig}".`);
2084
+ const result = await this.initEzsp();
2085
+ return result;
2086
+ }
2087
+ async stop() {
2088
+ await this.ezsp.stop();
2089
+ this.initVariables();
2090
+ console.log(`======== Ember Adapter Stopped ========`);
2091
+ }
2092
+ // queued, non-InterPAN
2093
+ async getCoordinator() {
2094
+ return new Promise((resolve, reject) => {
2095
+ this.requestQueue.enqueue(async () => {
2096
+ this.checkInterpanLock();
2097
+ // in all likelihood this will be retrieved from cache
2098
+ const ieeeAddr = (await this.emberGetEui64());
2099
+ resolve({
2100
+ ieeeAddr,
2101
+ networkAddress: consts_2.ZIGBEE_COORDINATOR_ADDRESS,
2102
+ manufacturerID: consts_2.MANUFACTURER_CODE,
2103
+ endpoints: endpoints_1.FIXED_ENDPOINTS.map((ep) => {
2104
+ return {
2105
+ profileID: ep.profileId,
2106
+ ID: ep.endpoint,
2107
+ deviceID: ep.deviceId,
2108
+ inputClusters: ep.inClusterList,
2109
+ outputClusters: ep.outClusterList,
2110
+ };
2111
+ }),
2112
+ });
2113
+ return enums_2.EmberStatus.SUCCESS;
2114
+ }, reject);
2115
+ });
2116
+ }
2117
+ async getCoordinatorVersion() {
2118
+ return { type: `EZSP v${this.version.ezsp}`, meta: this.version };
2119
+ }
2120
+ // queued
2121
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2122
+ async reset(type) {
2123
+ return Promise.reject(new Error("Not supported"));
2124
+ // NOTE: although this function is legacy atm, a couple of new untested EZSP functions that could also prove useful:
2125
+ // this.ezsp.ezspTokenFactoryReset(true/*excludeOutgoingFC*/, true/*excludeBootCounter*/);
2126
+ // this.ezsp.ezspResetNode()
2127
+ }
2128
+ async supportsBackup() {
2129
+ return true;
2130
+ }
2131
+ // queued
2132
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2133
+ async backup(ieeeAddressesInDatabase) {
2134
+ return new Promise((resolve, reject) => {
2135
+ this.requestQueue.enqueue(async () => {
2136
+ // grab fresh version here, bypass cache
2137
+ const [netStatus, , netParams] = (await this.ezsp.ezspGetNetworkParameters());
2138
+ if (netStatus !== enums_2.EmberStatus.SUCCESS) {
2139
+ console.error(`[BACKUP] Failed to get network parameters.`);
2140
+ return netStatus;
2141
+ }
2142
+ // update cache
2143
+ this.networkCache.parameters = netParams;
2144
+ this.networkCache.eui64 = (await this.ezsp.ezspGetEui64());
2145
+ const [netKeyStatus, netKeyInfo] = (await this.ezsp.ezspGetNetworkKeyInfo());
2146
+ if (netKeyStatus !== enums_2.SLStatus.OK) {
2147
+ console.error(`[BACKUP] Failed to get network keys info.`);
2148
+ return ((netKeyStatus === enums_2.SLStatus.BUSY) || (netKeyStatus === enums_2.SLStatus.NOT_READY))
2149
+ ? enums_2.EmberStatus.NETWORK_BUSY : enums_2.EmberStatus.ERR_FATAL; // allow retry on statuses that should be temporary
2150
+ }
2151
+ if (!netKeyInfo.networkKeySet) {
2152
+ throw new Error(`[BACKUP] No network key set.`);
2153
+ }
2154
+ let keyList = [];
2155
+ if (STACK_CONFIGS[this.stackConfig].KEY_TABLE_SIZE) {
2156
+ keyList = (await this.exportLinkKeys());
2157
+ }
2158
+ // XXX: this only makes sense on stop (if that), not hourly/on start, plus network needs to be at near-standstill @see AN1387
2159
+ // const tokensBuf = (await EmberTokensManager.saveTokens(
2160
+ // this.ezsp,
2161
+ // Buffer.from(this.networkCache.eui64.substring(2/*0x*/), 'hex').reverse()
2162
+ // ));
2163
+ // console.log(tokensBuf.toString('hex'));
2164
+ let context = (0, initters_1.initSecurityManagerContext)();
2165
+ context.coreKeyType = enums_2.SecManKeyType.TC_LINK;
2166
+ const [tcLinkKey, tclkStatus] = (await this.ezsp.ezspExportKey(context));
2167
+ if (tclkStatus !== enums_2.SLStatus.OK) {
2168
+ throw new Error(`[BACKUP] Failed to export TC Link Key with status=${enums_2.SLStatus[tclkStatus]}.`);
2169
+ }
2170
+ context = (0, initters_1.initSecurityManagerContext)(); // make sure it's back to zeroes
2171
+ context.coreKeyType = enums_2.SecManKeyType.NETWORK;
2172
+ context.keyIndex = 0;
2173
+ const [networkKey, nkStatus] = (await this.ezsp.ezspExportKey(context));
2174
+ if (nkStatus !== enums_2.SLStatus.OK) {
2175
+ throw new Error(`[BACKUP] Failed to export Network Key with status=${enums_2.SLStatus[nkStatus]}.`);
2176
+ }
2177
+ const zbChannels = Array.from(Array(consts_2.EMBER_NUM_802_15_4_CHANNELS), (e, i) => i + consts_2.EMBER_MIN_802_15_4_CHANNEL_NUMBER);
2178
+ resolve({
2179
+ networkOptions: {
2180
+ panId: netParams.panId, // uint16_t
2181
+ extendedPanId: Buffer.from(netParams.extendedPanId),
2182
+ channelList: zbChannels.map((c) => ((2 ** c) & netParams.channels) ? c : null).filter((x) => x),
2183
+ networkKey: networkKey.contents,
2184
+ networkKeyDistribute: false,
2185
+ },
2186
+ logicalChannel: netParams.radioChannel,
2187
+ networkKeyInfo: {
2188
+ sequenceNumber: netKeyInfo.networkKeySequenceNumber,
2189
+ frameCounter: netKeyInfo.networkKeyFrameCounter,
2190
+ },
2191
+ securityLevel: STACK_CONFIGS[this.stackConfig].SECURITY_LEVEL,
2192
+ networkUpdateId: netParams.nwkUpdateId,
2193
+ coordinatorIeeeAddress: Buffer.from(this.networkCache.eui64.substring(2) /*take out 0x*/, 'hex').reverse(),
2194
+ devices: keyList.map((key) => ({
2195
+ networkAddress: null, // not used for restore, no reason to make NCP calls for nothing
2196
+ ieeeAddress: Buffer.from(key.deviceEui64.substring(2) /*take out 0x*/, 'hex').reverse(),
2197
+ isDirectChild: false, // not used
2198
+ linkKey: {
2199
+ key: key.key.contents,
2200
+ rxCounter: key.incomingFrameCounter,
2201
+ txCounter: key.outgoingFrameCounter,
2202
+ },
2203
+ })),
2204
+ ezsp: {
2205
+ version: this.version.ezsp,
2206
+ hashed_tclk: tcLinkKey.contents,
2207
+ // tokens: tokensBuf.toString('hex'),
2208
+ // altNetworkKey: altNetworkKey.contents,
2209
+ }
2210
+ });
2211
+ return enums_2.EmberStatus.SUCCESS;
2212
+ }, reject, true);
2213
+ });
2214
+ }
2215
+ // queued, non-InterPAN
2216
+ async getNetworkParameters() {
2217
+ return new Promise((resolve, reject) => {
2218
+ this.requestQueue.enqueue(async () => {
2219
+ this.checkInterpanLock();
2220
+ // first call will cache for the others, but in all likelihood, it will all be from freshly cached after init
2221
+ // since Controller caches this also.
2222
+ const panID = (await this.emberGetPanId());
2223
+ const extendedPanID = (await this.emberGetExtendedPanId());
2224
+ const channel = (await this.emberGetRadioChannel());
2225
+ resolve({
2226
+ panID: panID,
2227
+ extendedPanID: parseInt(Buffer.from(extendedPanID).toString('hex'), 16),
2228
+ channel: channel,
2229
+ });
2230
+ return enums_2.EmberStatus.SUCCESS;
2231
+ }, reject);
2232
+ });
2233
+ }
2234
+ // queued
2235
+ async setTransmitPower(value) {
2236
+ if (typeof value !== 'number') {
2237
+ console.error(`Tried to set transmit power to non-number. Value ${value} of type ${typeof value}.`);
2238
+ return;
2239
+ }
2240
+ return new Promise((resolve, reject) => {
2241
+ this.requestQueue.enqueue(async () => {
2242
+ const status = await this.ezsp.ezspSetRadioPower(value);
2243
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2244
+ console.error(`Failed to set transmit power to ${value} status=${enums_2.EmberStatus[status]}.`);
2245
+ return status;
2246
+ }
2247
+ resolve();
2248
+ return enums_2.EmberStatus.SUCCESS;
2249
+ }, reject);
2250
+ });
2251
+ }
2252
+ // queued
2253
+ async addInstallCode(ieeeAddress, key) {
2254
+ if (!key) {
2255
+ throw new Error(`[ADD INSTALL CODE] Failed for "${ieeeAddress}"; no code given.`);
2256
+ }
2257
+ let validInstallCodeSize = false;
2258
+ for (const validCodeSize of consts_2.EMBER_INSTALL_CODE_SIZES) {
2259
+ if (key.length === validCodeSize) {
2260
+ validInstallCodeSize = true;
2261
+ break;
2262
+ }
2263
+ }
2264
+ if (!validInstallCodeSize) {
2265
+ throw new Error(`[ADD INSTALL CODE] Failed for "${ieeeAddress}"; invalid code size.`);
2266
+ }
2267
+ // Reverse the bits in a byte
2268
+ const reverse = (b) => {
2269
+ return ((b * 0x0802 & 0x22110) | (b * 0x8020 & 0x88440)) * 0x10101 >> 16;
2270
+ };
2271
+ let crc = 0xFFFF; // uint16_t
2272
+ // Compute the CRC and verify that it matches.
2273
+ // The bit reversals, byte swap, and ones' complement are due to differences between halCommonCrc16 and the Smart Energy version.
2274
+ for (let index = 0; index < (key.length - consts_2.EMBER_INSTALL_CODE_CRC_SIZE); index++) {
2275
+ crc = (0, math_1.halCommonCrc16)(reverse(key[index]), crc);
2276
+ }
2277
+ crc = ~(0, math_1.highLowToInt)(reverse((0, math_1.lowByte)(crc)), reverse((0, math_1.highByte)(crc)));
2278
+ if (key[key.length - consts_2.EMBER_INSTALL_CODE_CRC_SIZE] !== (0, math_1.lowByte)(crc) || key[key.length - consts_2.EMBER_INSTALL_CODE_CRC_SIZE + 1] !== (0, math_1.highByte)(crc)) {
2279
+ throw new Error(`[ADD INSTALL CODE] Failed for "${ieeeAddress}"; invalid code CRC.`);
2280
+ }
2281
+ return new Promise((resolve, reject) => {
2282
+ this.requestQueue.enqueue(async () => {
2283
+ // Compute the key from the install code and CRC.
2284
+ const [aesStatus, keyContents] = (await this.emberAesHashSimple(key));
2285
+ if (aesStatus !== enums_2.EmberStatus.SUCCESS) {
2286
+ console.error(`[ADD INSTALL CODE] Failed AES hash for "${ieeeAddress}" with status=${enums_2.EmberStatus[aesStatus]}.`);
2287
+ return aesStatus;
2288
+ }
2289
+ // Add the key to the transient key table.
2290
+ // This will be used while the DUT joins.
2291
+ const impStatus = (await this.ezsp.ezspImportTransientKey(ieeeAddress, { contents: keyContents }, enums_2.SecManFlag.NONE));
2292
+ if (impStatus == enums_2.SLStatus.OK) {
2293
+ debug(`[ADD INSTALL CODE] Success for "${ieeeAddress}".`);
2294
+ }
2295
+ else {
2296
+ console.error(`[ADD INSTALL CODE] Failed for "${ieeeAddress}" with status=${enums_2.SLStatus[impStatus]}.`);
2297
+ return enums_2.EmberStatus.ERR_FATAL;
2298
+ }
2299
+ resolve();
2300
+ return enums_2.EmberStatus.SUCCESS;
2301
+ }, reject);
2302
+ });
2303
+ }
2304
+ /** WARNING: Adapter impl. Starts timer immediately upon returning */
2305
+ waitFor(networkAddress, endpoint, frameType, direction, transactionSequenceNumber, clusterID, commandIdentifier, timeout) {
2306
+ const waiter = this.oneWaitress.waitFor({
2307
+ target: networkAddress,
2308
+ apsFrame: {
2309
+ clusterId: clusterID,
2310
+ profileId: consts_2.HA_PROFILE_ID, // XXX: ok? only used by OTA upstream
2311
+ sequence: 0, // set by stack
2312
+ sourceEndpoint: endpoint,
2313
+ destinationEndpoint: 0,
2314
+ groupId: 0,
2315
+ options: enums_2.EmberApsOption.NONE,
2316
+ },
2317
+ zclSequence: transactionSequenceNumber,
2318
+ }, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT * 3); // XXX: since this is used by OTA..?
2319
+ return {
2320
+ cancel: () => this.oneWaitress.remove(waiter.id),
2321
+ promise: waiter.start().promise,
2322
+ };
2323
+ }
2324
+ //---- ZDO
2325
+ // queued, non-InterPAN
2326
+ async permitJoin(seconds, networkAddress) {
2327
+ const preJoining = async () => {
2328
+ if (seconds) {
2329
+ const plaintextKey = { contents: Buffer.from(consts_2.ZIGBEE_PROFILE_INTEROPERABILITY_LINK_KEY) };
2330
+ const impKeyStatus = (await this.ezsp.ezspImportTransientKey(consts_2.BLANK_EUI64, plaintextKey, enums_2.SecManFlag.NONE));
2331
+ debug(`[ZDO] Pre joining import transient key status=${enums_2.SLStatus[impKeyStatus]}.`);
2332
+ return impKeyStatus === enums_2.SLStatus.OK ? enums_2.EmberStatus.SUCCESS : enums_2.EmberStatus.ERR_FATAL;
2333
+ }
2334
+ else {
2335
+ await this.ezsp.ezspClearTransientLinkKeys();
2336
+ const setJPstatus = (await this.emberSetJoinPolicy(enums_2.EmberJoinDecision.ALLOW_REJOINS_ONLY));
2337
+ if (setJPstatus !== enums_2.EzspStatus.SUCCESS) {
2338
+ console.error(`[ZDO] Failed set join policy for with status=${enums_2.EzspStatus[setJPstatus]}.`);
2339
+ return enums_2.EmberStatus.ERR_FATAL;
2340
+ }
2341
+ return enums_2.EmberStatus.SUCCESS;
2342
+ }
2343
+ };
2344
+ // NOTE: can't ZDO PJ on coordinator, so if network address is null or zero (coordinator), using local permit join
2345
+ if (networkAddress) {
2346
+ return new Promise((resolve, reject) => {
2347
+ this.requestQueue.enqueue(async () => {
2348
+ this.checkInterpanLock();
2349
+ const pjStatus = (await preJoining());
2350
+ if (pjStatus !== enums_2.EmberStatus.SUCCESS) {
2351
+ console.error(`[ZDO] Failed pre joining request for "${networkAddress}" with status=${enums_2.EmberStatus[pjStatus]}.`);
2352
+ return pjStatus;
2353
+ }
2354
+ // `authentication`: TC significance always 1 (zb specs)
2355
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2356
+ const [status, apsFrame, messageTag] = (await this.emberPermitJoiningRequest(networkAddress, seconds, 1, 0));
2357
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2358
+ console.error(`[ZDO] Failed permit joining request for "${networkAddress}" with status=${enums_2.EmberStatus[status]}.`);
2359
+ return status;
2360
+ }
2361
+ (await this.oneWaitress.startWaitingFor({
2362
+ target: networkAddress,
2363
+ apsFrame,
2364
+ responseClusterId: zdo_1.PERMIT_JOINING_RESPONSE,
2365
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2366
+ resolve();
2367
+ return enums_2.EmberStatus.SUCCESS;
2368
+ }, reject);
2369
+ });
2370
+ }
2371
+ else {
2372
+ // no device specified to open, open coordinator + broadcast
2373
+ return new Promise((resolve, reject) => {
2374
+ this.requestQueue.enqueue(async () => {
2375
+ this.checkInterpanLock();
2376
+ const pjStatus = (await preJoining());
2377
+ if (pjStatus !== enums_2.EmberStatus.SUCCESS) {
2378
+ console.error(`[ZDO] Failed pre joining request for "${networkAddress}" with status=${enums_2.EmberStatus[pjStatus]}.`);
2379
+ return pjStatus;
2380
+ }
2381
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2382
+ const [status, apsFrame, messageTag] = (await this.emberPermitJoining(seconds, true /*broadcast*/));
2383
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2384
+ console.error(`[ZDO] Failed permit joining request with status=${enums_2.EmberStatus[status]}.`);
2385
+ return status;
2386
+ }
2387
+ // NOTE: because Z2M is refreshing the permit join duration early to prevent it from closing
2388
+ // (every 200sec, even if only opened for 254sec), we can't wait for the stack opened status,
2389
+ // as it won't trigger again if already opened... so instead we assume it worked
2390
+ // NOTE2: with EZSP, 255=forever, and 254=max, but since upstream logic uses fixed 254 with interval refresh,
2391
+ // we can't simply bypass upstream calls if called for "forever" to prevent useless NCP calls (3-4 each time),
2392
+ // until called with 0 (disable), since we don't know if it was requested for forever or not...
2393
+ // TLDR: upstream logic change required to allow this
2394
+ // if (seconds) {
2395
+ // await this.oneWaitress.startWaitingForEvent(
2396
+ // {eventName: OneWaitressEvents.STACK_STATUS_NETWORK_OPENED},
2397
+ // DEFAULT_ZCL_REQUEST_TIMEOUT,
2398
+ // '[ZDO] Permit Joining',
2399
+ // );
2400
+ // } else {
2401
+ // // NOTE: CLOSED stack status is not triggered if the network was not OPENED in the first place, so don't wait for it
2402
+ // // same kind of problem as described above (upstream always tries to close after start, but EZSP already is)
2403
+ // }
2404
+ resolve();
2405
+ return enums_2.EmberStatus.SUCCESS;
2406
+ }, reject);
2407
+ });
2408
+ }
2409
+ }
2410
+ // queued, non-InterPAN
2411
+ async lqi(networkAddress) {
2412
+ const neighbors = [];
2413
+ const request = async (startIndex) => {
2414
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2415
+ const [reqStatus, apsFrame, messageTag] = (await this.emberLqiTableRequest(networkAddress, startIndex, this.defaultApsOptions));
2416
+ if (reqStatus !== enums_2.EmberStatus.SUCCESS) {
2417
+ console.error(`[ZDO] Failed LQI request for "${networkAddress}" (index "${startIndex}") with status=${enums_2.EmberStatus[reqStatus]}.`);
2418
+ return [reqStatus, null, null];
2419
+ }
2420
+ const result = (await this.oneWaitress.startWaitingFor({
2421
+ target: networkAddress,
2422
+ apsFrame,
2423
+ responseClusterId: zdo_1.LQI_TABLE_RESPONSE,
2424
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2425
+ for (const entry of result.entryList) {
2426
+ neighbors.push({
2427
+ ieeeAddr: entry.eui64,
2428
+ networkAddress: entry.nodeId,
2429
+ linkquality: entry.lqi,
2430
+ relationship: entry.relationship,
2431
+ depth: entry.depth,
2432
+ });
2433
+ }
2434
+ return [enums_2.EmberStatus.SUCCESS, result.neighborTableEntries, result.entryList.length];
2435
+ };
2436
+ return new Promise((resolve, reject) => {
2437
+ this.requestQueue.enqueue(async () => {
2438
+ this.checkInterpanLock();
2439
+ let [status, tableEntries, entryCount] = (await request(0));
2440
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2441
+ return status;
2442
+ }
2443
+ const size = tableEntries;
2444
+ let nextStartIndex = entryCount;
2445
+ while (neighbors.length < size) {
2446
+ [status, tableEntries, entryCount] = (await request(nextStartIndex));
2447
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2448
+ return status;
2449
+ }
2450
+ nextStartIndex += entryCount;
2451
+ }
2452
+ resolve({ neighbors });
2453
+ return status;
2454
+ }, reject);
2455
+ });
2456
+ }
2457
+ // queued, non-InterPAN
2458
+ async routingTable(networkAddress) {
2459
+ const table = [];
2460
+ const request = async (startIndex) => {
2461
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2462
+ const [reqStatus, apsFrame, messageTag] = (await this.emberRoutingTableRequest(networkAddress, startIndex, this.defaultApsOptions));
2463
+ if (reqStatus !== enums_2.EmberStatus.SUCCESS) {
2464
+ console.error(`[ZDO] Failed routing table request for "${networkAddress}" (index "${startIndex}") with status=${enums_2.EmberStatus[reqStatus]}.`);
2465
+ return [reqStatus, null, null];
2466
+ }
2467
+ const result = (await this.oneWaitress.startWaitingFor({
2468
+ target: networkAddress,
2469
+ apsFrame,
2470
+ responseClusterId: zdo_1.ROUTING_TABLE_RESPONSE,
2471
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2472
+ for (const entry of result.entryList) {
2473
+ table.push({
2474
+ destinationAddress: entry.destinationAddress,
2475
+ status: RoutingTableStatus[entry.status], // get str value from enum to satisfy upstream's needs
2476
+ nextHop: entry.nextHopAddress,
2477
+ });
2478
+ }
2479
+ return [enums_2.EmberStatus.SUCCESS, result.routingTableEntries, result.entryList.length];
2480
+ };
2481
+ return new Promise((resolve, reject) => {
2482
+ this.requestQueue.enqueue(async () => {
2483
+ this.checkInterpanLock();
2484
+ let [status, tableEntries, entryCount] = (await request(0));
2485
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2486
+ return status;
2487
+ }
2488
+ const size = tableEntries;
2489
+ let nextStartIndex = entryCount;
2490
+ while (table.length < size) {
2491
+ [status, tableEntries, entryCount] = (await request(nextStartIndex));
2492
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2493
+ return status;
2494
+ }
2495
+ nextStartIndex += entryCount;
2496
+ }
2497
+ resolve({ table });
2498
+ return enums_2.EmberStatus.SUCCESS;
2499
+ }, reject);
2500
+ });
2501
+ }
2502
+ // queued, non-InterPAN
2503
+ async nodeDescriptor(networkAddress) {
2504
+ return new Promise((resolve, reject) => {
2505
+ this.requestQueue.enqueue(async () => {
2506
+ this.checkInterpanLock();
2507
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2508
+ const [status, apsFrame, messageTag] = (await this.emberNodeDescriptorRequest(networkAddress, this.defaultApsOptions));
2509
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2510
+ console.error(`[ZDO] Failed node descriptor for "${networkAddress}" with status=${enums_2.EmberStatus[status]}.`);
2511
+ return status;
2512
+ }
2513
+ const result = (await this.oneWaitress.startWaitingFor({
2514
+ target: networkAddress,
2515
+ apsFrame,
2516
+ responseClusterId: zdo_1.NODE_DESCRIPTOR_RESPONSE,
2517
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2518
+ let type = 'Unknown';
2519
+ switch (result.logicalType) {
2520
+ case 0x0:
2521
+ type = 'Coordinator';
2522
+ break;
2523
+ case 0x1:
2524
+ type = 'Router';
2525
+ break;
2526
+ case 0x2:
2527
+ type = 'EndDevice';
2528
+ break;
2529
+ }
2530
+ // always 0 before rev. 21 where field was added
2531
+ if (result.stackRevision < CURRENT_ZIGBEE_SPEC_REVISION) {
2532
+ console.warn(`[ZDO] Node descriptor for "${networkAddress}" reports device is only compliant to revision `
2533
+ + `"${(result.stackRevision < 21) ? 'pre-21' : result.stackRevision}" of the ZigBee specification `
2534
+ + `(current revision: ${CURRENT_ZIGBEE_SPEC_REVISION}).`);
2535
+ }
2536
+ resolve({ type, manufacturerCode: result.manufacturerCode });
2537
+ return enums_2.EmberStatus.SUCCESS;
2538
+ }, reject);
2539
+ });
2540
+ }
2541
+ // queued, non-InterPAN
2542
+ async activeEndpoints(networkAddress) {
2543
+ return new Promise((resolve, reject) => {
2544
+ this.requestQueue.enqueue(async () => {
2545
+ this.checkInterpanLock();
2546
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2547
+ const [status, apsFrame, messageTag] = (await this.emberActiveEndpointsRequest(networkAddress, this.defaultApsOptions));
2548
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2549
+ console.error(`[ZDO] Failed active endpoints request for "${networkAddress}" with status=${enums_2.EmberStatus[status]}.`);
2550
+ return status;
2551
+ }
2552
+ const result = (await this.oneWaitress.startWaitingFor({
2553
+ target: networkAddress,
2554
+ apsFrame,
2555
+ responseClusterId: zdo_1.ACTIVE_ENDPOINTS_RESPONSE,
2556
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2557
+ resolve({ endpoints: result.endpointList });
2558
+ return enums_2.EmberStatus.SUCCESS;
2559
+ }, reject);
2560
+ });
2561
+ }
2562
+ // queued, non-InterPAN
2563
+ async simpleDescriptor(networkAddress, endpointID) {
2564
+ return new Promise((resolve, reject) => {
2565
+ this.requestQueue.enqueue(async () => {
2566
+ this.checkInterpanLock();
2567
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2568
+ const [status, apsFrame, messageTag] = (await this.emberSimpleDescriptorRequest(networkAddress, endpointID, this.defaultApsOptions));
2569
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2570
+ console.error(`[ZDO] Failed simple descriptor request for "${networkAddress}" endpoint "${endpointID}" `
2571
+ + `with status=${enums_2.EmberStatus[status]}.`);
2572
+ return status;
2573
+ }
2574
+ const result = (await this.oneWaitress.startWaitingFor({
2575
+ target: networkAddress,
2576
+ apsFrame,
2577
+ responseClusterId: zdo_1.SIMPLE_DESCRIPTOR_RESPONSE,
2578
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT));
2579
+ resolve({
2580
+ profileID: result.profileId,
2581
+ endpointID: result.endpoint,
2582
+ deviceID: result.deviceId,
2583
+ inputClusters: result.inClusterList,
2584
+ outputClusters: result.outClusterList,
2585
+ });
2586
+ return enums_2.EmberStatus.SUCCESS;
2587
+ }, reject);
2588
+ });
2589
+ }
2590
+ // queued, non-InterPAN
2591
+ async bind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
2592
+ if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
2593
+ // dest address is EUI64 (str), so type should always be endpoint (unicast)
2594
+ return new Promise((resolve, reject) => {
2595
+ this.requestQueue.enqueue(async () => {
2596
+ this.checkInterpanLock();
2597
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2598
+ const [status, apsFrame, messageTag] = (await this.emberBindRequest(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, zdo_1.UNICAST_BINDING, destinationAddressOrGroup, null, // doesn't matter
2599
+ destinationEndpoint, this.defaultApsOptions));
2600
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2601
+ console.error(`[ZDO] Failed bind request for "${destinationNetworkAddress}" destination "${destinationAddressOrGroup}" `
2602
+ + `endpoint "${destinationEndpoint}" with status=${enums_2.EmberStatus[status]}.`);
2603
+ return status;
2604
+ }
2605
+ await this.oneWaitress.startWaitingFor({
2606
+ target: destinationNetworkAddress,
2607
+ apsFrame,
2608
+ responseClusterId: zdo_1.BIND_RESPONSE,
2609
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT);
2610
+ resolve();
2611
+ return enums_2.EmberStatus.SUCCESS;
2612
+ }, reject);
2613
+ });
2614
+ }
2615
+ else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
2616
+ // dest is group num, so type should always be group (multicast)
2617
+ return new Promise((resolve, reject) => {
2618
+ this.requestQueue.enqueue(async () => {
2619
+ this.checkInterpanLock();
2620
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2621
+ const [status, apsFrame, messageTag] = (await this.emberBindRequest(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, zdo_1.MULTICAST_BINDING, null, // doesn't matter
2622
+ destinationAddressOrGroup, destinationEndpoint, // doesn't matter
2623
+ this.defaultApsOptions));
2624
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2625
+ console.error(`[ZDO] Failed bind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" `
2626
+ + `with status=${enums_2.EmberStatus[status]}.`);
2627
+ return status;
2628
+ }
2629
+ await this.oneWaitress.startWaitingFor({
2630
+ target: destinationNetworkAddress,
2631
+ apsFrame,
2632
+ responseClusterId: zdo_1.BIND_RESPONSE,
2633
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT);
2634
+ resolve();
2635
+ return enums_2.EmberStatus.SUCCESS;
2636
+ }, reject);
2637
+ });
2638
+ }
2639
+ }
2640
+ // queued, non-InterPAN
2641
+ async unbind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
2642
+ if (typeof destinationAddressOrGroup === 'string' && type === 'endpoint') {
2643
+ // dest address is EUI64 (str), so type should always be endpoint (unicast)
2644
+ return new Promise((resolve, reject) => {
2645
+ this.requestQueue.enqueue(async () => {
2646
+ this.checkInterpanLock();
2647
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2648
+ const [status, apsFrame, messageTag] = (await this.emberUnbindRequest(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, zdo_1.UNICAST_BINDING, destinationAddressOrGroup, null, // doesn't matter
2649
+ destinationEndpoint, this.defaultApsOptions));
2650
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2651
+ console.error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" destination "${destinationAddressOrGroup}" `
2652
+ + `endpoint "${destinationEndpoint}" with status=${enums_2.EmberStatus[status]}.`);
2653
+ return status;
2654
+ }
2655
+ await this.oneWaitress.startWaitingFor({
2656
+ target: destinationNetworkAddress,
2657
+ apsFrame,
2658
+ responseClusterId: zdo_1.UNBIND_RESPONSE,
2659
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT);
2660
+ resolve();
2661
+ return enums_2.EmberStatus.SUCCESS;
2662
+ }, reject);
2663
+ });
2664
+ }
2665
+ else if (typeof destinationAddressOrGroup === 'number' && type === 'group') {
2666
+ // dest is group num, so type should always be group (multicast)
2667
+ return new Promise((resolve, reject) => {
2668
+ this.requestQueue.enqueue(async () => {
2669
+ this.checkInterpanLock();
2670
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2671
+ const [status, apsFrame, messageTag] = (await this.emberUnbindRequest(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, zdo_1.MULTICAST_BINDING, null, // doesn't matter
2672
+ destinationAddressOrGroup, destinationEndpoint, // doesn't matter
2673
+ this.defaultApsOptions));
2674
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2675
+ console.error(`[ZDO] Failed unbind request for "${destinationNetworkAddress}" group "${destinationAddressOrGroup}" `
2676
+ + `with status=${enums_2.EmberStatus[status]}.`);
2677
+ return status;
2678
+ }
2679
+ await this.oneWaitress.startWaitingFor({
2680
+ target: destinationNetworkAddress,
2681
+ apsFrame,
2682
+ responseClusterId: zdo_1.UNBIND_RESPONSE,
2683
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT);
2684
+ resolve();
2685
+ return enums_2.EmberStatus.SUCCESS;
2686
+ }, reject);
2687
+ });
2688
+ }
2689
+ }
2690
+ // queued, non-InterPAN
2691
+ async removeDevice(networkAddress, ieeeAddr) {
2692
+ return new Promise((resolve, reject) => {
2693
+ this.requestQueue.enqueue(async () => {
2694
+ this.checkInterpanLock();
2695
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2696
+ const [status, apsFrame, messageTag] = (await this.emberLeaveRequest(networkAddress, ieeeAddr, enums_2.EmberLeaveRequestFlags.WITHOUT_REJOIN, this.defaultApsOptions));
2697
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2698
+ console.error(`[ZDO] Failed remove device request for "${networkAddress}" target "${ieeeAddr}" `
2699
+ + `with status=${enums_2.EmberStatus[status]}.`);
2700
+ return status;
2701
+ }
2702
+ await this.oneWaitress.startWaitingFor({
2703
+ target: networkAddress,
2704
+ apsFrame,
2705
+ responseClusterId: zdo_1.LEAVE_RESPONSE,
2706
+ }, DEFAULT_ZDO_REQUEST_TIMEOUT);
2707
+ resolve();
2708
+ return enums_2.EmberStatus.SUCCESS;
2709
+ }, reject);
2710
+ });
2711
+ }
2712
+ //---- ZCL
2713
+ // queued, non-InterPAN
2714
+ async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
2715
+ const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
2716
+ endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
2717
+ const command = zclFrame.getCommand();
2718
+ let commandResponseId = null;
2719
+ if (command.hasOwnProperty('response') && disableResponse === false) {
2720
+ commandResponseId = command.response;
2721
+ }
2722
+ else if (!zclFrame.Header.frameControl.disableDefaultResponse) {
2723
+ commandResponseId = zcl_1.Foundation.defaultRsp.ID;
2724
+ }
2725
+ const apsFrame = {
2726
+ profileId: sourceEndpointInfo.profileId,
2727
+ clusterId: zclFrame.Cluster.ID,
2728
+ sourceEndpoint: sourceEndpointInfo.endpoint,
2729
+ destinationEndpoint: (typeof endpoint === 'number') ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
2730
+ options: this.defaultApsOptions,
2731
+ groupId: 0,
2732
+ sequence: 0, // set by stack
2733
+ };
2734
+ // don't RETRY if no response expected
2735
+ if (commandResponseId == null) {
2736
+ apsFrame.options &= ~enums_2.EmberApsOption.RETRY;
2737
+ }
2738
+ const data = zclFrame.toBuffer();
2739
+ return new Promise((resolve, reject) => {
2740
+ this.requestQueue.enqueue(async () => {
2741
+ this.checkInterpanLock();
2742
+ if (CHECK_APS_PAYLOAD_LENGTH) {
2743
+ const maxPayloadLength = (await this.maximumApsPayloadLength(enums_2.EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame));
2744
+ if (data.length > maxPayloadLength) {
2745
+ return enums_2.EmberStatus.MESSAGE_TOO_LONG; // queue will reject
2746
+ }
2747
+ }
2748
+ // track group changes in NCP multicast table
2749
+ if (apsFrame.clusterId === cluster_1.default.genGroups.ID) {
2750
+ await this.onGroupChange(command.ID, zclFrame.Payload.groupid);
2751
+ }
2752
+ debug(`~~~> [ZCL to=${networkAddress} apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.Header)}]`);
2753
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2754
+ const [status, messageTag] = (await this.ezsp.send(enums_2.EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, data, 0, // alias
2755
+ 0));
2756
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2757
+ console.error(`~x~> [ZCL to=${networkAddress}] Failed to send request with status=${enums_2.EmberStatus[status]}.`);
2758
+ return status; // let queue handle retry based on status
2759
+ }
2760
+ if (commandResponseId != null) {
2761
+ // NOTE: aps sequence number will have been set by send function
2762
+ const result = (await this.oneWaitress.startWaitingFor({
2763
+ target: networkAddress,
2764
+ apsFrame,
2765
+ zclSequence: zclFrame.Header.transactionSequenceNumber,
2766
+ }, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT));
2767
+ resolve(result);
2768
+ }
2769
+ else {
2770
+ resolve(null); // don't expect a response
2771
+ return enums_2.EmberStatus.SUCCESS;
2772
+ }
2773
+ }, reject);
2774
+ });
2775
+ }
2776
+ // queued, non-InterPAN
2777
+ async sendZclFrameToGroup(groupID, zclFrame, sourceEndpoint) {
2778
+ const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
2779
+ endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
2780
+ const apsFrame = {
2781
+ profileId: sourceEndpointInfo.profileId,
2782
+ clusterId: zclFrame.Cluster.ID,
2783
+ sourceEndpoint: sourceEndpointInfo.endpoint,
2784
+ destinationEndpoint: endpoints_1.FIXED_ENDPOINTS[0].endpoint,
2785
+ options: this.defaultApsOptions,
2786
+ groupId: groupID,
2787
+ sequence: 0, // set by stack
2788
+ };
2789
+ const data = zclFrame.toBuffer();
2790
+ return new Promise((resolve, reject) => {
2791
+ this.requestQueue.enqueue(async () => {
2792
+ this.checkInterpanLock();
2793
+ if (CHECK_APS_PAYLOAD_LENGTH) {
2794
+ const maxPayloadLength = (await this.maximumApsPayloadLength(enums_2.EmberOutgoingMessageType.MULTICAST, groupID, apsFrame));
2795
+ if (data.length > maxPayloadLength) {
2796
+ return enums_2.EmberStatus.MESSAGE_TOO_LONG; // queue will reject
2797
+ }
2798
+ }
2799
+ debug(`~~~> [ZCL GROUP apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.Header)}]`);
2800
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2801
+ const [status, messageTag] = (await this.ezsp.send(enums_2.EmberOutgoingMessageType.MULTICAST, apsFrame.groupId, // not used for MC
2802
+ apsFrame, data, 0, // alias
2803
+ 0));
2804
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2805
+ console.error(`~x~> [ZCL GROUP] Failed to send with status=${enums_2.EmberStatus[status]}.`);
2806
+ return status; // let queue handle retry based on status
2807
+ }
2808
+ // NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
2809
+ resolve();
2810
+ return enums_2.EmberStatus.SUCCESS;
2811
+ }, reject);
2812
+ });
2813
+ }
2814
+ // queued, non-InterPAN
2815
+ async sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint) {
2816
+ const sourceEndpointInfo = typeof sourceEndpoint === 'number' ?
2817
+ endpoints_1.FIXED_ENDPOINTS.find((epi) => (epi.endpoint === sourceEndpoint)) : endpoints_1.FIXED_ENDPOINTS[0];
2818
+ const apsFrame = {
2819
+ profileId: sourceEndpointInfo.profileId,
2820
+ clusterId: zclFrame.Cluster.ID,
2821
+ sourceEndpoint: sourceEndpointInfo.endpoint,
2822
+ destinationEndpoint: (typeof endpoint === 'number') ? endpoint : endpoints_1.FIXED_ENDPOINTS[0].endpoint,
2823
+ options: this.defaultApsOptions,
2824
+ groupId: consts_2.EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS,
2825
+ sequence: 0, // set by stack
2826
+ };
2827
+ const data = zclFrame.toBuffer();
2828
+ return new Promise((resolve, reject) => {
2829
+ this.requestQueue.enqueue(async () => {
2830
+ this.checkInterpanLock();
2831
+ if (CHECK_APS_PAYLOAD_LENGTH) {
2832
+ const maxPayloadLength = (await this.maximumApsPayloadLength(enums_2.EmberOutgoingMessageType.BROADCAST, consts_2.EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS, apsFrame));
2833
+ if (data.length > maxPayloadLength) {
2834
+ return enums_2.EmberStatus.MESSAGE_TOO_LONG; // queue will reject
2835
+ }
2836
+ }
2837
+ debug(`~~~> [ZCL BROADCAST apsFrame=${JSON.stringify(apsFrame)} header=${JSON.stringify(zclFrame.Header)}]`);
2838
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2839
+ const [status, messageTag] = (await this.ezsp.send(enums_2.EmberOutgoingMessageType.BROADCAST, consts_2.EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS, apsFrame, data, 0, // alias
2840
+ 0));
2841
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2842
+ console.error(`~x~> [ZCL BROADCAST] Failed to send with status=${enums_2.EmberStatus[status]}.`);
2843
+ return status; // let queue handle retry based on status
2844
+ }
2845
+ // NOTE: since ezspMessageSentHandler could take a while here, we don't block, it'll just be logged if the delivery failed
2846
+ resolve();
2847
+ return enums_2.EmberStatus.SUCCESS;
2848
+ }, reject);
2849
+ });
2850
+ }
2851
+ //---- InterPAN for Touchlink
2852
+ // XXX: There might be a better way to handle touchlink with ZLL ezsp functions, but I don't have any device to test so, didn't look into it...
2853
+ // TODO: check all this touchlink/interpan stuff
2854
+ // queued
2855
+ async setChannelInterPAN(channel) {
2856
+ if (typeof channel !== 'number') {
2857
+ console.error(`Tried to set channel InterPAN to non-number. Channel ${channel} of type ${typeof channel}.`);
2858
+ return;
2859
+ }
2860
+ return new Promise((resolve, reject) => {
2861
+ this.requestQueue.enqueue(async () => {
2862
+ this.interpanLock = true;
2863
+ const status = (await this.ezsp.ezspSetLogicalAndRadioChannel(channel));
2864
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2865
+ this.interpanLock = false; // XXX: ok?
2866
+ console.error(`Failed to set InterPAN channel to ${channel} with status=${enums_2.EmberStatus[status]}.`);
2867
+ return status;
2868
+ }
2869
+ resolve();
2870
+ return status;
2871
+ }, reject);
2872
+ });
2873
+ }
2874
+ // queued
2875
+ async sendZclFrameInterPANToIeeeAddr(zclFrame, ieeeAddress) {
2876
+ return new Promise((resolve, reject) => {
2877
+ this.requestQueue.enqueue(async () => {
2878
+ const msgBuffalo = new buffalo_1.EzspBuffalo(Buffer.alloc(consts_2.MAXIMUM_INTERPAN_LENGTH));
2879
+ // cache-enabled getters
2880
+ const sourcePanId = (await this.emberGetPanId());
2881
+ const sourceEui64 = (await this.emberGetEui64());
2882
+ msgBuffalo.writeUInt16((consts_2.LONG_DEST_FRAME_CONTROL | consts_2.MAC_ACK_REQUIRED)); // macFrameControl
2883
+ msgBuffalo.writeUInt8(0); // sequence Skip Sequence number, stack sets the sequence number.
2884
+ msgBuffalo.writeUInt16(consts_2.INVALID_PAN_ID); // destPanId
2885
+ msgBuffalo.writeIeeeAddr(ieeeAddress); // destAddress (longAddress)
2886
+ msgBuffalo.writeUInt16(sourcePanId); // sourcePanId
2887
+ msgBuffalo.writeIeeeAddr(sourceEui64); // sourceAddress
2888
+ msgBuffalo.writeUInt16(consts_2.STUB_NWK_FRAME_CONTROL); // nwkFrameControl
2889
+ msgBuffalo.writeUInt8((enums_2.EmberInterpanMessageType.UNICAST | consts_2.INTERPAN_APS_FRAME_TYPE)); // apsFrameControl
2890
+ msgBuffalo.writeUInt16(zclFrame.Cluster.ID);
2891
+ msgBuffalo.writeUInt16(consts_2.TOUCHLINK_PROFILE_ID);
2892
+ debug(`~~~> [ZCL TOUCHLINK to=${ieeeAddress} header=${JSON.stringify(zclFrame.Header)}]`);
2893
+ const status = (await this.ezsp.ezspSendRawMessage(Buffer.concat([msgBuffalo.getWritten(), zclFrame.toBuffer()])));
2894
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2895
+ console.error(`~x~> [ZCL TOUCHLINK to=${ieeeAddress}] Failed to send with status=${enums_2.EmberStatus[status]}.`);
2896
+ return status;
2897
+ }
2898
+ // NOTE: can use ezspRawTransmitCompleteHandler if needed here
2899
+ resolve();
2900
+ return status;
2901
+ }, reject);
2902
+ });
2903
+ }
2904
+ // queued
2905
+ async sendZclFrameInterPANBroadcast(zclFrame, timeout) {
2906
+ const command = zclFrame.getCommand();
2907
+ if (!command.hasOwnProperty('response')) {
2908
+ throw new Error(`Command '${command.name}' has no response, cannot wait for response.`);
2909
+ }
2910
+ // just for waitress
2911
+ const apsFrame = {
2912
+ profileId: consts_2.TOUCHLINK_PROFILE_ID,
2913
+ clusterId: zclFrame.Cluster.ID,
2914
+ sourceEndpoint: 0,
2915
+ destinationEndpoint: 0,
2916
+ options: enums_2.EmberApsOption.NONE,
2917
+ groupId: consts_2.EMBER_SLEEPY_BROADCAST_ADDRESS,
2918
+ sequence: 0, // set by stack
2919
+ };
2920
+ return new Promise((resolve, reject) => {
2921
+ this.requestQueue.enqueue(async () => {
2922
+ const msgBuffalo = new buffalo_1.EzspBuffalo(Buffer.alloc(consts_2.MAXIMUM_INTERPAN_LENGTH));
2923
+ // cache-enabled getters
2924
+ const sourcePanId = (await this.emberGetPanId());
2925
+ const sourceEui64 = (await this.emberGetEui64());
2926
+ msgBuffalo.writeUInt16(consts_2.SHORT_DEST_FRAME_CONTROL); // macFrameControl
2927
+ msgBuffalo.writeUInt8(0); // sequence Skip Sequence number, stack sets the sequence number.
2928
+ msgBuffalo.writeUInt16(consts_2.INVALID_PAN_ID); // destPanId
2929
+ msgBuffalo.writeUInt16(apsFrame.groupId); // destAddress (longAddress)
2930
+ msgBuffalo.writeUInt16(sourcePanId); // sourcePanId
2931
+ msgBuffalo.writeIeeeAddr(sourceEui64); // sourceAddress
2932
+ msgBuffalo.writeUInt16(consts_2.STUB_NWK_FRAME_CONTROL); // nwkFrameControl
2933
+ msgBuffalo.writeUInt8((enums_2.EmberInterpanMessageType.BROADCAST | consts_2.INTERPAN_APS_FRAME_TYPE)); // apsFrameControl
2934
+ msgBuffalo.writeUInt16(apsFrame.clusterId);
2935
+ msgBuffalo.writeUInt16(apsFrame.profileId);
2936
+ const data = Buffer.concat([msgBuffalo.getWritten(), zclFrame.toBuffer()]);
2937
+ debug(`~~~> [ZCL TOUCHLINK BROADCAST header=${JSON.stringify(zclFrame.Header)}]`);
2938
+ const status = (await this.ezsp.ezspSendRawMessage(data));
2939
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2940
+ console.error(`~x~> [ZCL TOUCHLINK BROADCAST] Failed to send with status=${enums_2.EmberStatus[status]}.`);
2941
+ return status;
2942
+ }
2943
+ // NOTE: can use ezspRawTransmitCompleteHandler if needed here
2944
+ const result = (await this.oneWaitress.startWaitingFor({
2945
+ target: null,
2946
+ apsFrame: apsFrame,
2947
+ zclSequence: zclFrame.Header.transactionSequenceNumber,
2948
+ }, timeout || DEFAULT_ZCL_REQUEST_TIMEOUT * 2)); // XXX: touchlink timeout?
2949
+ resolve(result);
2950
+ return enums_2.EmberStatus.SUCCESS;
2951
+ }, reject);
2952
+ });
2953
+ }
2954
+ // queued
2955
+ async restoreChannelInterPAN() {
2956
+ return new Promise((resolve, reject) => {
2957
+ this.requestQueue.enqueue(async () => {
2958
+ const status = (await this.ezsp.ezspSetLogicalAndRadioChannel(this.networkOptions.channelList[0]));
2959
+ if (status !== enums_2.EmberStatus.SUCCESS) {
2960
+ console.error(`Failed to restore InterPAN channel to ${this.networkOptions.channelList[0]} with status=${enums_2.EmberStatus[status]}.`);
2961
+ return status;
2962
+ }
2963
+ // let adapter settle down
2964
+ await (0, utils_1.Wait)(3000);
2965
+ this.interpanLock = false;
2966
+ resolve();
2967
+ return status;
2968
+ }, reject);
2969
+ });
2970
+ }
2971
+ //-- END Adapter implementation
2972
+ checkInterpanLock() {
2973
+ if (this.interpanLock) {
2974
+ console.error(`[INTERPAN MODE] Cannot execute non-InterPAN commands.`);
2975
+ // will be caught by request queue and rejected internally.
2976
+ throw new Error(enums_2.EzspStatus[enums_2.EzspStatus.ERROR_INVALID_CALL]);
2977
+ }
2978
+ }
2979
+ }
2980
+ exports.EmberAdapter = EmberAdapter;
2981
+ //# sourceMappingURL=emberAdapter.js.map