zigbee-herdsman 3.5.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (726) hide show
  1. package/.github/dependabot.yml +9 -3
  2. package/.github/workflows/ci.yml +2 -4
  3. package/.github/workflows/stale.yml +1 -1
  4. package/.release-please-manifest.json +1 -1
  5. package/.vscode/extensions.json +3 -0
  6. package/.vscode/settings.json +11 -0
  7. package/CHANGELOG.md +25 -0
  8. package/biome.json +89 -0
  9. package/dist/adapter/adapter.d.ts +11 -11
  10. package/dist/adapter/adapter.d.ts.map +1 -1
  11. package/dist/adapter/adapter.js +14 -14
  12. package/dist/adapter/adapterDiscovery.d.ts +6 -6
  13. package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
  14. package/dist/adapter/adapterDiscovery.js +139 -141
  15. package/dist/adapter/adapterDiscovery.js.map +1 -1
  16. package/dist/adapter/const.d.ts +1 -1
  17. package/dist/adapter/const.js +2 -2
  18. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +16 -16
  19. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  20. package/dist/adapter/deconz/adapter/deconzAdapter.js +95 -100
  21. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  22. package/dist/adapter/deconz/driver/constants.d.ts +5 -5
  23. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  24. package/dist/adapter/deconz/driver/driver.d.ts +9 -9
  25. package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
  26. package/dist/adapter/deconz/driver/driver.js +112 -106
  27. package/dist/adapter/deconz/driver/driver.js.map +1 -1
  28. package/dist/adapter/deconz/driver/frame.d.ts +1 -1
  29. package/dist/adapter/deconz/driver/frame.d.ts.map +1 -1
  30. package/dist/adapter/deconz/driver/frame.js +1 -2
  31. package/dist/adapter/deconz/driver/frame.js.map +1 -1
  32. package/dist/adapter/deconz/driver/frameParser.d.ts +1 -1
  33. package/dist/adapter/deconz/driver/frameParser.d.ts.map +1 -1
  34. package/dist/adapter/deconz/driver/frameParser.js +66 -70
  35. package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
  36. package/dist/adapter/deconz/driver/parser.d.ts +1 -1
  37. package/dist/adapter/deconz/driver/parser.d.ts.map +1 -1
  38. package/dist/adapter/deconz/driver/parser.js +2 -2
  39. package/dist/adapter/deconz/driver/parser.js.map +1 -1
  40. package/dist/adapter/deconz/driver/writer.d.ts +2 -2
  41. package/dist/adapter/deconz/driver/writer.d.ts.map +1 -1
  42. package/dist/adapter/deconz/driver/writer.js +1 -1
  43. package/dist/adapter/ember/adapter/emberAdapter.d.ts +19 -19
  44. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  45. package/dist/adapter/ember/adapter/emberAdapter.js +117 -97
  46. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  47. package/dist/adapter/ember/adapter/endpoints.d.ts +1 -1
  48. package/dist/adapter/ember/adapter/endpoints.d.ts.map +1 -1
  49. package/dist/adapter/ember/adapter/oneWaitress.d.ts +5 -5
  50. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
  51. package/dist/adapter/ember/adapter/oneWaitress.js +2 -2
  52. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
  53. package/dist/adapter/ember/adapter/tokensManager.d.ts +3 -3
  54. package/dist/adapter/ember/adapter/tokensManager.d.ts.map +1 -1
  55. package/dist/adapter/ember/adapter/tokensManager.js +20 -23
  56. package/dist/adapter/ember/adapter/tokensManager.js.map +1 -1
  57. package/dist/adapter/ember/enums.d.ts +4 -4
  58. package/dist/adapter/ember/enums.d.ts.map +1 -1
  59. package/dist/adapter/ember/enums.js +4 -6
  60. package/dist/adapter/ember/enums.js.map +1 -1
  61. package/dist/adapter/ember/ezsp/buffalo.d.ts +4 -4
  62. package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -1
  63. package/dist/adapter/ember/ezsp/buffalo.js +30 -32
  64. package/dist/adapter/ember/ezsp/buffalo.js.map +1 -1
  65. package/dist/adapter/ember/ezsp/ezsp.d.ts +46 -46
  66. package/dist/adapter/ember/ezsp/ezsp.d.ts.map +1 -1
  67. package/dist/adapter/ember/ezsp/ezsp.js +85 -111
  68. package/dist/adapter/ember/ezsp/ezsp.js.map +1 -1
  69. package/dist/adapter/ember/ezspError.d.ts +1 -1
  70. package/dist/adapter/ember/types.d.ts +14 -14
  71. package/dist/adapter/ember/types.d.ts.map +1 -1
  72. package/dist/adapter/ember/uart/ash.d.ts +5 -5
  73. package/dist/adapter/ember/uart/ash.d.ts.map +1 -1
  74. package/dist/adapter/ember/uart/ash.js +80 -71
  75. package/dist/adapter/ember/uart/ash.js.map +1 -1
  76. package/dist/adapter/ember/uart/parser.d.ts +2 -2
  77. package/dist/adapter/ember/uart/parser.d.ts.map +1 -1
  78. package/dist/adapter/ember/uart/parser.js +2 -1
  79. package/dist/adapter/ember/uart/parser.js.map +1 -1
  80. package/dist/adapter/ember/uart/queues.js +27 -29
  81. package/dist/adapter/ember/uart/queues.js.map +1 -1
  82. package/dist/adapter/ember/uart/writer.d.ts +1 -1
  83. package/dist/adapter/ember/uart/writer.d.ts.map +1 -1
  84. package/dist/adapter/ember/uart/writer.js +3 -5
  85. package/dist/adapter/ember/uart/writer.js.map +1 -1
  86. package/dist/adapter/ember/utils/initters.d.ts +2 -2
  87. package/dist/adapter/ember/utils/initters.d.ts.map +1 -1
  88. package/dist/adapter/ember/utils/initters.js +1 -1
  89. package/dist/adapter/ember/utils/math.js +1 -1
  90. package/dist/adapter/events.d.ts +1 -1
  91. package/dist/adapter/events.d.ts.map +1 -1
  92. package/dist/adapter/ezsp/adapter/backup.d.ts +3 -3
  93. package/dist/adapter/ezsp/adapter/backup.d.ts.map +1 -1
  94. package/dist/adapter/ezsp/adapter/backup.js +8 -10
  95. package/dist/adapter/ezsp/adapter/backup.js.map +1 -1
  96. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +12 -12
  97. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  98. package/dist/adapter/ezsp/adapter/ezspAdapter.js +45 -44
  99. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  100. package/dist/adapter/ezsp/driver/driver.d.ts +12 -12
  101. package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
  102. package/dist/adapter/ezsp/driver/driver.js +148 -141
  103. package/dist/adapter/ezsp/driver/driver.js.map +1 -1
  104. package/dist/adapter/ezsp/driver/ezsp.d.ts +7 -7
  105. package/dist/adapter/ezsp/driver/ezsp.d.ts.map +1 -1
  106. package/dist/adapter/ezsp/driver/ezsp.js +61 -59
  107. package/dist/adapter/ezsp/driver/ezsp.js.map +1 -1
  108. package/dist/adapter/ezsp/driver/frame.js +2 -2
  109. package/dist/adapter/ezsp/driver/index.d.ts +2 -2
  110. package/dist/adapter/ezsp/driver/multicast.d.ts +8 -5
  111. package/dist/adapter/ezsp/driver/multicast.d.ts.map +1 -1
  112. package/dist/adapter/ezsp/driver/multicast.js +9 -9
  113. package/dist/adapter/ezsp/driver/multicast.js.map +1 -1
  114. package/dist/adapter/ezsp/driver/parser.d.ts +1 -1
  115. package/dist/adapter/ezsp/driver/parser.js +3 -3
  116. package/dist/adapter/ezsp/driver/types/basic.d.ts +5 -5
  117. package/dist/adapter/ezsp/driver/types/basic.d.ts.map +1 -1
  118. package/dist/adapter/ezsp/driver/types/basic.js +12 -33
  119. package/dist/adapter/ezsp/driver/types/basic.js.map +1 -1
  120. package/dist/adapter/ezsp/driver/types/index.d.ts +3 -3
  121. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  122. package/dist/adapter/ezsp/driver/types/index.js +8 -9
  123. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  124. package/dist/adapter/ezsp/driver/types/named.d.ts +2 -2
  125. package/dist/adapter/ezsp/driver/types/named.d.ts.map +1 -1
  126. package/dist/adapter/ezsp/driver/types/named.js +8 -11
  127. package/dist/adapter/ezsp/driver/types/named.js.map +1 -1
  128. package/dist/adapter/ezsp/driver/types/struct.d.ts +2 -2
  129. package/dist/adapter/ezsp/driver/types/struct.d.ts.map +1 -1
  130. package/dist/adapter/ezsp/driver/types/struct.js +207 -214
  131. package/dist/adapter/ezsp/driver/types/struct.js.map +1 -1
  132. package/dist/adapter/ezsp/driver/uart.d.ts +2 -2
  133. package/dist/adapter/ezsp/driver/uart.d.ts.map +1 -1
  134. package/dist/adapter/ezsp/driver/uart.js +48 -37
  135. package/dist/adapter/ezsp/driver/uart.js.map +1 -1
  136. package/dist/adapter/ezsp/driver/utils/crc16ccitt.d.ts +3 -3
  137. package/dist/adapter/ezsp/driver/utils/crc16ccitt.d.ts.map +1 -1
  138. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js +16 -34
  139. package/dist/adapter/ezsp/driver/utils/crc16ccitt.js.map +1 -1
  140. package/dist/adapter/ezsp/driver/utils/index.d.ts +4 -4
  141. package/dist/adapter/ezsp/driver/utils/index.d.ts.map +1 -1
  142. package/dist/adapter/ezsp/driver/utils/index.js +4 -4
  143. package/dist/adapter/ezsp/driver/utils/index.js.map +1 -1
  144. package/dist/adapter/ezsp/driver/writer.d.ts +1 -1
  145. package/dist/adapter/ezsp/driver/writer.js +2 -2
  146. package/dist/adapter/index.d.ts +3 -3
  147. package/dist/adapter/serialPort.d.ts +3 -3
  148. package/dist/adapter/serialPort.d.ts.map +1 -1
  149. package/dist/adapter/serialPort.js +1 -0
  150. package/dist/adapter/serialPort.js.map +1 -1
  151. package/dist/adapter/socketPortUtils.js +3 -3
  152. package/dist/adapter/tstype.d.ts +6 -6
  153. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts +4 -4
  154. package/dist/adapter/z-stack/adapter/adapter-backup.d.ts.map +1 -1
  155. package/dist/adapter/z-stack/adapter/adapter-backup.js +106 -119
  156. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
  157. package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts +10 -10
  158. package/dist/adapter/z-stack/adapter/adapter-nv-memory.d.ts.map +1 -1
  159. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +23 -24
  160. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
  161. package/dist/adapter/z-stack/adapter/manager.d.ts +6 -6
  162. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  163. package/dist/adapter/z-stack/adapter/manager.js +115 -127
  164. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  165. package/dist/adapter/z-stack/adapter/tstype.d.ts +3 -3
  166. package/dist/adapter/z-stack/adapter/tstype.js +3 -3
  167. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +10 -10
  168. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  169. package/dist/adapter/z-stack/adapter/zStackAdapter.js +125 -137
  170. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  171. package/dist/adapter/z-stack/constants/common.d.ts.map +1 -1
  172. package/dist/adapter/z-stack/constants/common.js +0 -3
  173. package/dist/adapter/z-stack/constants/common.js.map +1 -1
  174. package/dist/adapter/z-stack/constants/index.d.ts +10 -10
  175. package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
  176. package/dist/adapter/z-stack/constants/index.js +2 -2
  177. package/dist/adapter/z-stack/constants/index.js.map +1 -1
  178. package/dist/adapter/z-stack/constants/utils.d.ts +1 -1
  179. package/dist/adapter/z-stack/constants/utils.js +2 -2
  180. package/dist/adapter/z-stack/constants/utils.js.map +1 -1
  181. package/dist/adapter/z-stack/models/startup-options.d.ts +2 -2
  182. package/dist/adapter/z-stack/models/startup-options.d.ts.map +1 -1
  183. package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts +1 -1
  184. package/dist/adapter/z-stack/structs/entries/address-manager-entry.d.ts.map +1 -1
  185. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js +4 -5
  186. package/dist/adapter/z-stack/structs/entries/address-manager-entry.js.map +1 -1
  187. package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts +2 -2
  188. package/dist/adapter/z-stack/structs/entries/address-manager-table.d.ts.map +1 -1
  189. package/dist/adapter/z-stack/structs/entries/address-manager-table.js +3 -4
  190. package/dist/adapter/z-stack/structs/entries/address-manager-table.js.map +1 -1
  191. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts +1 -1
  192. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.d.ts.map +1 -1
  193. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js +1 -2
  194. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-entry.js.map +1 -1
  195. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts +2 -2
  196. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.d.ts.map +1 -1
  197. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js +3 -4
  198. package/dist/adapter/z-stack/structs/entries/aps-link-key-data-table.js.map +1 -1
  199. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts +1 -1
  200. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.d.ts.map +1 -1
  201. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js +6 -7
  202. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-entry.js.map +1 -1
  203. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts +2 -2
  204. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.d.ts.map +1 -1
  205. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js +3 -4
  206. package/dist/adapter/z-stack/structs/entries/aps-tc-link-key-table.js.map +1 -1
  207. package/dist/adapter/z-stack/structs/entries/channel-list.d.ts +1 -1
  208. package/dist/adapter/z-stack/structs/entries/channel-list.d.ts.map +1 -1
  209. package/dist/adapter/z-stack/structs/entries/channel-list.js +1 -2
  210. package/dist/adapter/z-stack/structs/entries/channel-list.js.map +1 -1
  211. package/dist/adapter/z-stack/structs/entries/has-configured.d.ts +1 -1
  212. package/dist/adapter/z-stack/structs/entries/has-configured.d.ts.map +1 -1
  213. package/dist/adapter/z-stack/structs/entries/has-configured.js +2 -3
  214. package/dist/adapter/z-stack/structs/entries/has-configured.js.map +1 -1
  215. package/dist/adapter/z-stack/structs/entries/index.d.ts +16 -16
  216. package/dist/adapter/z-stack/structs/entries/nib.d.ts +1 -1
  217. package/dist/adapter/z-stack/structs/entries/nib.d.ts.map +1 -1
  218. package/dist/adapter/z-stack/structs/entries/nib.js +49 -50
  219. package/dist/adapter/z-stack/structs/entries/nib.js.map +1 -1
  220. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts +1 -1
  221. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.d.ts.map +1 -1
  222. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js +1 -2
  223. package/dist/adapter/z-stack/structs/entries/nwk-key-descriptor.js.map +1 -1
  224. package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts +1 -1
  225. package/dist/adapter/z-stack/structs/entries/nwk-key.d.ts.map +1 -1
  226. package/dist/adapter/z-stack/structs/entries/nwk-key.js +1 -2
  227. package/dist/adapter/z-stack/structs/entries/nwk-key.js.map +1 -1
  228. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts +1 -1
  229. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.d.ts.map +1 -1
  230. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js +1 -2
  231. package/dist/adapter/z-stack/structs/entries/nwk-pan-id.js.map +1 -1
  232. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts +1 -1
  233. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.d.ts.map +1 -1
  234. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js +3 -4
  235. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.js.map +1 -1
  236. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts +2 -2
  237. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.d.ts.map +1 -1
  238. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js +3 -4
  239. package/dist/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.js.map +1 -1
  240. package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts +1 -1
  241. package/dist/adapter/z-stack/structs/entries/security-manager-entry.d.ts.map +1 -1
  242. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js +4 -5
  243. package/dist/adapter/z-stack/structs/entries/security-manager-entry.js.map +1 -1
  244. package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts +2 -2
  245. package/dist/adapter/z-stack/structs/entries/security-manager-table.d.ts.map +1 -1
  246. package/dist/adapter/z-stack/structs/entries/security-manager-table.js +3 -4
  247. package/dist/adapter/z-stack/structs/entries/security-manager-table.js.map +1 -1
  248. package/dist/adapter/z-stack/structs/index.d.ts +4 -4
  249. package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts +2 -2
  250. package/dist/adapter/z-stack/structs/serializable-memory-object.d.ts.map +1 -1
  251. package/dist/adapter/z-stack/structs/struct.d.ts +8 -8
  252. package/dist/adapter/z-stack/structs/struct.d.ts.map +1 -1
  253. package/dist/adapter/z-stack/structs/struct.js +42 -43
  254. package/dist/adapter/z-stack/structs/struct.js.map +1 -1
  255. package/dist/adapter/z-stack/structs/table.d.ts +3 -3
  256. package/dist/adapter/z-stack/structs/table.d.ts.map +1 -1
  257. package/dist/adapter/z-stack/structs/table.js +10 -10
  258. package/dist/adapter/z-stack/structs/table.js.map +1 -1
  259. package/dist/adapter/z-stack/unpi/frame.d.ts +1 -1
  260. package/dist/adapter/z-stack/unpi/frame.d.ts.map +1 -1
  261. package/dist/adapter/z-stack/unpi/frame.js +2 -4
  262. package/dist/adapter/z-stack/unpi/frame.js.map +1 -1
  263. package/dist/adapter/z-stack/unpi/index.d.ts +4 -4
  264. package/dist/adapter/z-stack/unpi/parser.d.ts +1 -1
  265. package/dist/adapter/z-stack/unpi/parser.js +3 -3
  266. package/dist/adapter/z-stack/unpi/parser.js.map +1 -1
  267. package/dist/adapter/z-stack/unpi/writer.d.ts +2 -2
  268. package/dist/adapter/z-stack/unpi/writer.d.ts.map +1 -1
  269. package/dist/adapter/z-stack/unpi/writer.js +1 -1
  270. package/dist/adapter/z-stack/utils/index.d.ts +2 -2
  271. package/dist/adapter/z-stack/utils/network-options.d.ts +1 -1
  272. package/dist/adapter/z-stack/utils/network-options.d.ts.map +1 -1
  273. package/dist/adapter/z-stack/znp/buffaloZnp.d.ts +3 -3
  274. package/dist/adapter/z-stack/znp/buffaloZnp.d.ts.map +1 -1
  275. package/dist/adapter/z-stack/znp/buffaloZnp.js +34 -20
  276. package/dist/adapter/z-stack/znp/buffaloZnp.js.map +1 -1
  277. package/dist/adapter/z-stack/znp/definition.d.ts +2 -2
  278. package/dist/adapter/z-stack/znp/definition.d.ts.map +1 -1
  279. package/dist/adapter/z-stack/znp/definition.js +1111 -1111
  280. package/dist/adapter/z-stack/znp/index.d.ts +2 -2
  281. package/dist/adapter/z-stack/znp/tstype.d.ts +7 -7
  282. package/dist/adapter/z-stack/znp/tstype.d.ts.map +1 -1
  283. package/dist/adapter/z-stack/znp/utils.d.ts +1 -1
  284. package/dist/adapter/z-stack/znp/utils.d.ts.map +1 -1
  285. package/dist/adapter/z-stack/znp/utils.js +2 -2
  286. package/dist/adapter/z-stack/znp/znp.d.ts +7 -7
  287. package/dist/adapter/z-stack/znp/znp.d.ts.map +1 -1
  288. package/dist/adapter/z-stack/znp/znp.js +46 -45
  289. package/dist/adapter/z-stack/znp/znp.js.map +1 -1
  290. package/dist/adapter/z-stack/znp/zpiObject.d.ts +8 -8
  291. package/dist/adapter/z-stack/znp/zpiObject.d.ts.map +1 -1
  292. package/dist/adapter/z-stack/znp/zpiObject.js +6 -6
  293. package/dist/adapter/z-stack/znp/zpiObject.js.map +1 -1
  294. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +11 -11
  295. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  296. package/dist/adapter/zboss/adapter/zbossAdapter.js +37 -36
  297. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  298. package/dist/adapter/zboss/commands.d.ts +4 -6
  299. package/dist/adapter/zboss/commands.d.ts.map +1 -1
  300. package/dist/adapter/zboss/commands.js +321 -287
  301. package/dist/adapter/zboss/commands.js.map +1 -1
  302. package/dist/adapter/zboss/driver.d.ts +9 -9
  303. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  304. package/dist/adapter/zboss/driver.js +25 -25
  305. package/dist/adapter/zboss/driver.js.map +1 -1
  306. package/dist/adapter/zboss/frame.d.ts +9 -9
  307. package/dist/adapter/zboss/frame.d.ts.map +1 -1
  308. package/dist/adapter/zboss/frame.js +15 -15
  309. package/dist/adapter/zboss/frame.js.map +1 -1
  310. package/dist/adapter/zboss/reader.d.ts +2 -2
  311. package/dist/adapter/zboss/reader.d.ts.map +1 -1
  312. package/dist/adapter/zboss/reader.js +6 -5
  313. package/dist/adapter/zboss/reader.js.map +1 -1
  314. package/dist/adapter/zboss/uart.d.ts +3 -3
  315. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  316. package/dist/adapter/zboss/uart.js +36 -36
  317. package/dist/adapter/zboss/uart.js.map +1 -1
  318. package/dist/adapter/zboss/writer.d.ts +1 -1
  319. package/dist/adapter/zboss/writer.d.ts.map +1 -1
  320. package/dist/adapter/zboss/writer.js +3 -5
  321. package/dist/adapter/zboss/writer.js.map +1 -1
  322. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js +2 -2
  323. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js.map +1 -1
  324. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +14 -14
  325. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  326. package/dist/adapter/zigate/adapter/zigateAdapter.js +52 -53
  327. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  328. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts +6 -6
  329. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts.map +1 -1
  330. package/dist/adapter/zigate/driver/buffaloZiGate.js +41 -23
  331. package/dist/adapter/zigate/driver/buffaloZiGate.js.map +1 -1
  332. package/dist/adapter/zigate/driver/commandType.d.ts +2 -2
  333. package/dist/adapter/zigate/driver/commandType.d.ts.map +1 -1
  334. package/dist/adapter/zigate/driver/commandType.js +37 -37
  335. package/dist/adapter/zigate/driver/commandType.js.map +1 -1
  336. package/dist/adapter/zigate/driver/constants.d.ts +27 -200
  337. package/dist/adapter/zigate/driver/constants.d.ts.map +1 -1
  338. package/dist/adapter/zigate/driver/constants.js +40 -236
  339. package/dist/adapter/zigate/driver/constants.js.map +1 -1
  340. package/dist/adapter/zigate/driver/frame.d.ts.map +1 -1
  341. package/dist/adapter/zigate/driver/frame.js +4 -3
  342. package/dist/adapter/zigate/driver/frame.js.map +1 -1
  343. package/dist/adapter/zigate/driver/messageType.d.ts +1 -1
  344. package/dist/adapter/zigate/driver/messageType.js +76 -76
  345. package/dist/adapter/zigate/driver/ziGateObject.d.ts +3 -3
  346. package/dist/adapter/zigate/driver/ziGateObject.d.ts.map +1 -1
  347. package/dist/adapter/zigate/driver/ziGateObject.js +7 -6
  348. package/dist/adapter/zigate/driver/ziGateObject.js.map +1 -1
  349. package/dist/adapter/zigate/driver/zigate.d.ts +8 -8
  350. package/dist/adapter/zigate/driver/zigate.d.ts.map +1 -1
  351. package/dist/adapter/zigate/driver/zigate.js +59 -54
  352. package/dist/adapter/zigate/driver/zigate.js.map +1 -1
  353. package/dist/adapter/zoh/adapter/utils.js +1 -1
  354. package/dist/adapter/zoh/adapter/zohAdapter.d.ts +13 -13
  355. package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
  356. package/dist/adapter/zoh/adapter/zohAdapter.js +101 -67
  357. package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
  358. package/dist/buffalo/buffalo.d.ts +2 -2
  359. package/dist/buffalo/buffalo.js +4 -4
  360. package/dist/buffalo/buffalo.js.map +1 -1
  361. package/dist/buffalo/index.d.ts +1 -1
  362. package/dist/controller/controller.d.ts +7 -7
  363. package/dist/controller/controller.d.ts.map +1 -1
  364. package/dist/controller/controller.js +94 -98
  365. package/dist/controller/controller.js.map +1 -1
  366. package/dist/controller/database.d.ts +1 -1
  367. package/dist/controller/database.d.ts.map +1 -1
  368. package/dist/controller/database.js +9 -9
  369. package/dist/controller/database.js.map +1 -1
  370. package/dist/controller/events.d.ts +6 -6
  371. package/dist/controller/events.d.ts.map +1 -1
  372. package/dist/controller/greenPower.d.ts +21 -21
  373. package/dist/controller/greenPower.d.ts.map +1 -1
  374. package/dist/controller/greenPower.js +41 -41
  375. package/dist/controller/greenPower.js.map +1 -1
  376. package/dist/controller/helpers/index.d.ts +1 -1
  377. package/dist/controller/helpers/request.d.ts +2 -2
  378. package/dist/controller/helpers/request.d.ts.map +1 -1
  379. package/dist/controller/helpers/request.js +31 -27
  380. package/dist/controller/helpers/request.js.map +1 -1
  381. package/dist/controller/helpers/requestQueue.d.ts +3 -3
  382. package/dist/controller/helpers/requestQueue.d.ts.map +1 -1
  383. package/dist/controller/helpers/requestQueue.js +20 -20
  384. package/dist/controller/helpers/requestQueue.js.map +1 -1
  385. package/dist/controller/helpers/zclFrameConverter.d.ts +2 -2
  386. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  387. package/dist/controller/helpers/zclFrameConverter.js +1 -1
  388. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  389. package/dist/controller/helpers/zclTransactionSequenceNumber.d.ts +6 -4
  390. package/dist/controller/helpers/zclTransactionSequenceNumber.d.ts.map +1 -1
  391. package/dist/controller/helpers/zclTransactionSequenceNumber.js +6 -5
  392. package/dist/controller/helpers/zclTransactionSequenceNumber.js.map +1 -1
  393. package/dist/controller/index.d.ts +1 -1
  394. package/dist/controller/model/device.d.ts +23 -19
  395. package/dist/controller/model/device.d.ts.map +1 -1
  396. package/dist/controller/model/device.js +153 -128
  397. package/dist/controller/model/device.js.map +1 -1
  398. package/dist/controller/model/endpoint.d.ts +11 -11
  399. package/dist/controller/model/endpoint.d.ts.map +1 -1
  400. package/dist/controller/model/endpoint.js +84 -67
  401. package/dist/controller/model/endpoint.js.map +1 -1
  402. package/dist/controller/model/entity.d.ts +3 -3
  403. package/dist/controller/model/entity.d.ts.map +1 -1
  404. package/dist/controller/model/group.d.ts +4 -4
  405. package/dist/controller/model/group.d.ts.map +1 -1
  406. package/dist/controller/model/group.js +21 -9
  407. package/dist/controller/model/group.js.map +1 -1
  408. package/dist/controller/model/index.d.ts +4 -4
  409. package/dist/controller/touchlink.d.ts +1 -1
  410. package/dist/controller/touchlink.d.ts.map +1 -1
  411. package/dist/controller/touchlink.js +11 -11
  412. package/dist/controller/tstype.d.ts +3 -3
  413. package/dist/index.d.ts +10 -10
  414. package/dist/models/backup-storage-legacy.d.ts +14 -16
  415. package/dist/models/backup-storage-legacy.d.ts.map +1 -1
  416. package/dist/models/backup-storage-unified.d.ts +1 -1
  417. package/dist/models/backup.d.ts +2 -2
  418. package/dist/models/backup.d.ts.map +1 -1
  419. package/dist/models/index.d.ts +4 -4
  420. package/dist/utils/backup.d.ts +1 -1
  421. package/dist/utils/backup.d.ts.map +1 -1
  422. package/dist/utils/backup.js +26 -26
  423. package/dist/utils/backup.js.map +1 -1
  424. package/dist/utils/index.d.ts +5 -5
  425. package/dist/utils/logger.js +3 -3
  426. package/dist/utils/patchBigIntSerialization.js +1 -1
  427. package/dist/utils/patchBigIntSerialization.js.map +1 -1
  428. package/dist/utils/queue.d.ts.map +1 -1
  429. package/dist/utils/queue.js +1 -0
  430. package/dist/utils/queue.js.map +1 -1
  431. package/dist/utils/utils.d.ts.map +1 -1
  432. package/dist/utils/utils.js +5 -4
  433. package/dist/utils/utils.js.map +1 -1
  434. package/dist/utils/waitress.d.ts +1 -1
  435. package/dist/utils/waitress.js +3 -3
  436. package/dist/zspec/consts.d.ts +1 -1
  437. package/dist/zspec/consts.d.ts.map +1 -1
  438. package/dist/zspec/consts.js +1 -1
  439. package/dist/zspec/index.d.ts +3 -3
  440. package/dist/zspec/tstypes.d.ts +1 -1
  441. package/dist/zspec/utils.d.ts +4 -4
  442. package/dist/zspec/utils.d.ts.map +1 -1
  443. package/dist/zspec/utils.js +9 -13
  444. package/dist/zspec/utils.js.map +1 -1
  445. package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
  446. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  447. package/dist/zspec/zcl/buffaloZcl.js +127 -84
  448. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  449. package/dist/zspec/zcl/definition/cluster.d.ts +1 -1
  450. package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
  451. package/dist/zspec/zcl/definition/cluster.js +894 -893
  452. package/dist/zspec/zcl/definition/cluster.js.map +1 -1
  453. package/dist/zspec/zcl/definition/consts.js +7 -7
  454. package/dist/zspec/zcl/definition/foundation.d.ts +3 -3
  455. package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
  456. package/dist/zspec/zcl/definition/foundation.js +88 -89
  457. package/dist/zspec/zcl/definition/foundation.js.map +1 -1
  458. package/dist/zspec/zcl/definition/manufacturerCode.d.ts +1 -1
  459. package/dist/zspec/zcl/definition/manufacturerCode.js +1 -1
  460. package/dist/zspec/zcl/definition/manufacturerCode.js.map +1 -1
  461. package/dist/zspec/zcl/definition/status.d.ts +3 -3
  462. package/dist/zspec/zcl/definition/status.js +3 -3
  463. package/dist/zspec/zcl/definition/tstype.d.ts +3 -3
  464. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  465. package/dist/zspec/zcl/index.d.ts +10 -10
  466. package/dist/zspec/zcl/utils.d.ts +3 -3
  467. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  468. package/dist/zspec/zcl/utils.js +18 -21
  469. package/dist/zspec/zcl/utils.js.map +1 -1
  470. package/dist/zspec/zcl/zclFrame.d.ts +7 -7
  471. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  472. package/dist/zspec/zcl/zclFrame.js +38 -41
  473. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  474. package/dist/zspec/zcl/zclHeader.d.ts +2 -2
  475. package/dist/zspec/zcl/zclHeader.d.ts.map +1 -1
  476. package/dist/zspec/zcl/zclHeader.js +3 -3
  477. package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
  478. package/dist/zspec/zdo/buffaloZdo.d.ts +7 -7
  479. package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
  480. package/dist/zspec/zdo/buffaloZdo.js +4 -4
  481. package/dist/zspec/zdo/buffaloZdo.js.map +1 -1
  482. package/dist/zspec/zdo/definition/status.d.ts +1 -1
  483. package/dist/zspec/zdo/definition/status.js +1 -1
  484. package/dist/zspec/zdo/definition/tstypes.d.ts +48 -48
  485. package/dist/zspec/zdo/definition/tstypes.d.ts.map +1 -1
  486. package/dist/zspec/zdo/index.d.ts +7 -7
  487. package/dist/zspec/zdo/utils.d.ts +2 -2
  488. package/dist/zspec/zdo/utils.d.ts.map +1 -1
  489. package/dist/zspec/zdo/utils.js +1 -1
  490. package/dist/zspec/zdo/utils.js.map +1 -1
  491. package/dist/zspec/zdo/zdoStatusError.d.ts +1 -1
  492. package/examples/join-and-log.js +5 -5
  493. package/package.json +6 -13
  494. package/src/adapter/adapter.ts +189 -0
  495. package/src/adapter/adapterDiscovery.ts +653 -0
  496. package/src/adapter/const.ts +12 -0
  497. package/src/adapter/deconz/adapter/deconzAdapter.ts +768 -0
  498. package/src/adapter/deconz/driver/constants.ts +180 -0
  499. package/src/adapter/deconz/driver/driver.ts +900 -0
  500. package/src/adapter/deconz/driver/frame.ts +11 -0
  501. package/src/adapter/deconz/driver/frameParser.ts +557 -0
  502. package/src/adapter/deconz/driver/parser.ts +45 -0
  503. package/src/adapter/deconz/driver/writer.ts +22 -0
  504. package/src/adapter/deconz/types.d.ts +13 -0
  505. package/src/adapter/ember/adapter/emberAdapter.ts +2266 -0
  506. package/src/adapter/ember/adapter/endpoints.ts +86 -0
  507. package/src/adapter/ember/adapter/oneWaitress.ts +322 -0
  508. package/src/adapter/ember/adapter/tokensManager.ts +782 -0
  509. package/src/adapter/ember/consts.ts +178 -0
  510. package/src/adapter/ember/enums.ts +2123 -0
  511. package/src/adapter/ember/ezsp/buffalo.ts +1397 -0
  512. package/src/adapter/ember/ezsp/consts.ts +148 -0
  513. package/src/adapter/ember/ezsp/enums.ts +1087 -0
  514. package/src/adapter/ember/ezsp/ezsp.ts +8985 -0
  515. package/src/adapter/ember/ezspError.ts +10 -0
  516. package/src/adapter/ember/types.ts +866 -0
  517. package/src/adapter/ember/uart/ash.ts +1969 -0
  518. package/src/adapter/ember/uart/consts.ts +109 -0
  519. package/src/adapter/ember/uart/enums.ts +192 -0
  520. package/src/adapter/ember/uart/parser.ts +48 -0
  521. package/src/adapter/ember/uart/queues.ts +247 -0
  522. package/src/adapter/ember/uart/writer.ts +53 -0
  523. package/src/adapter/ember/utils/initters.ts +58 -0
  524. package/src/adapter/ember/utils/math.ts +73 -0
  525. package/src/adapter/events.ts +21 -0
  526. package/src/adapter/ezsp/adapter/backup.ts +109 -0
  527. package/src/adapter/ezsp/adapter/ezspAdapter.ts +614 -0
  528. package/src/adapter/ezsp/driver/commands.ts +2497 -0
  529. package/src/adapter/ezsp/driver/consts.ts +11 -0
  530. package/src/adapter/ezsp/driver/driver.ts +1002 -0
  531. package/src/adapter/ezsp/driver/ezsp.ts +802 -0
  532. package/src/adapter/ezsp/driver/frame.ts +101 -0
  533. package/src/adapter/ezsp/driver/index.ts +4 -0
  534. package/src/adapter/ezsp/driver/multicast.ts +78 -0
  535. package/src/adapter/ezsp/driver/parser.ts +81 -0
  536. package/src/adapter/ezsp/driver/types/basic.ts +201 -0
  537. package/src/adapter/ezsp/driver/types/index.ts +239 -0
  538. package/src/adapter/ezsp/driver/types/named.ts +2330 -0
  539. package/src/adapter/ezsp/driver/types/struct.ts +844 -0
  540. package/src/adapter/ezsp/driver/uart.ts +460 -0
  541. package/src/adapter/ezsp/driver/utils/crc16ccitt.ts +44 -0
  542. package/src/adapter/ezsp/driver/utils/index.ts +32 -0
  543. package/src/adapter/ezsp/driver/writer.ts +64 -0
  544. package/src/adapter/index.ts +3 -0
  545. package/src/adapter/serialPort.ts +58 -0
  546. package/src/adapter/socketPortUtils.ts +16 -0
  547. package/src/adapter/tstype.ts +78 -0
  548. package/src/adapter/z-stack/adapter/adapter-backup.ts +519 -0
  549. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +457 -0
  550. package/src/adapter/z-stack/adapter/endpoints.ts +57 -0
  551. package/src/adapter/z-stack/adapter/manager.ts +543 -0
  552. package/src/adapter/z-stack/adapter/tstype.ts +6 -0
  553. package/src/adapter/z-stack/adapter/zStackAdapter.ts +1190 -0
  554. package/src/adapter/z-stack/constants/af.ts +27 -0
  555. package/src/adapter/z-stack/constants/common.ts +285 -0
  556. package/src/adapter/z-stack/constants/dbg.ts +23 -0
  557. package/src/adapter/z-stack/constants/index.ts +11 -0
  558. package/src/adapter/z-stack/constants/mac.ts +128 -0
  559. package/src/adapter/z-stack/constants/sapi.ts +25 -0
  560. package/src/adapter/z-stack/constants/sys.ts +72 -0
  561. package/src/adapter/z-stack/constants/util.ts +82 -0
  562. package/src/adapter/z-stack/constants/utils.ts +14 -0
  563. package/src/adapter/z-stack/constants/zdo.ts +103 -0
  564. package/src/adapter/z-stack/models/startup-options.ts +13 -0
  565. package/src/adapter/z-stack/structs/entries/address-manager-entry.ts +44 -0
  566. package/src/adapter/z-stack/structs/entries/address-manager-table.ts +19 -0
  567. package/src/adapter/z-stack/structs/entries/aps-link-key-data-entry.ts +12 -0
  568. package/src/adapter/z-stack/structs/entries/aps-link-key-data-table.ts +21 -0
  569. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-entry.ts +19 -0
  570. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-table.ts +21 -0
  571. package/src/adapter/z-stack/structs/entries/channel-list.ts +8 -0
  572. package/src/adapter/z-stack/structs/entries/has-configured.ts +16 -0
  573. package/src/adapter/z-stack/structs/entries/index.ts +16 -0
  574. package/src/adapter/z-stack/structs/entries/nib.ts +66 -0
  575. package/src/adapter/z-stack/structs/entries/nwk-key-descriptor.ts +15 -0
  576. package/src/adapter/z-stack/structs/entries/nwk-key.ts +13 -0
  577. package/src/adapter/z-stack/structs/entries/nwk-pan-id.ts +8 -0
  578. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.ts +20 -0
  579. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.ts +19 -0
  580. package/src/adapter/z-stack/structs/entries/security-manager-entry.ts +33 -0
  581. package/src/adapter/z-stack/structs/entries/security-manager-table.ts +22 -0
  582. package/src/adapter/z-stack/structs/index.ts +4 -0
  583. package/src/adapter/z-stack/structs/serializable-memory-object.ts +14 -0
  584. package/src/adapter/z-stack/structs/struct.ts +367 -0
  585. package/src/adapter/z-stack/structs/table.ts +198 -0
  586. package/src/adapter/z-stack/unpi/constants.ts +33 -0
  587. package/src/adapter/z-stack/unpi/frame.ts +62 -0
  588. package/src/adapter/z-stack/unpi/index.ts +4 -0
  589. package/src/adapter/z-stack/unpi/parser.ts +56 -0
  590. package/src/adapter/z-stack/unpi/writer.ts +21 -0
  591. package/src/adapter/z-stack/utils/channel-list.ts +40 -0
  592. package/src/adapter/z-stack/utils/index.ts +2 -0
  593. package/src/adapter/z-stack/utils/network-options.ts +26 -0
  594. package/src/adapter/z-stack/znp/buffaloZnp.ts +175 -0
  595. package/src/adapter/z-stack/znp/definition.ts +2713 -0
  596. package/src/adapter/z-stack/znp/index.ts +2 -0
  597. package/src/adapter/z-stack/znp/parameterType.ts +22 -0
  598. package/src/adapter/z-stack/znp/tstype.ts +44 -0
  599. package/src/adapter/z-stack/znp/utils.ts +10 -0
  600. package/src/adapter/z-stack/znp/znp.ts +342 -0
  601. package/src/adapter/z-stack/znp/zpiObject.ts +148 -0
  602. package/src/adapter/zboss/adapter/zbossAdapter.ts +527 -0
  603. package/src/adapter/zboss/commands.ts +1184 -0
  604. package/src/adapter/zboss/consts.ts +9 -0
  605. package/src/adapter/zboss/driver.ts +423 -0
  606. package/src/adapter/zboss/enums.ts +360 -0
  607. package/src/adapter/zboss/frame.ts +227 -0
  608. package/src/adapter/zboss/reader.ts +65 -0
  609. package/src/adapter/zboss/types.ts +0 -0
  610. package/src/adapter/zboss/uart.ts +428 -0
  611. package/src/adapter/zboss/utils.ts +58 -0
  612. package/src/adapter/zboss/writer.ts +49 -0
  613. package/src/adapter/zigate/adapter/patchZdoBuffaloBE.ts +27 -0
  614. package/src/adapter/zigate/adapter/zigateAdapter.ts +618 -0
  615. package/src/adapter/zigate/driver/LICENSE +17 -0
  616. package/src/adapter/zigate/driver/buffaloZiGate.ts +212 -0
  617. package/src/adapter/zigate/driver/commandType.ts +418 -0
  618. package/src/adapter/zigate/driver/constants.ts +150 -0
  619. package/src/adapter/zigate/driver/frame.ts +197 -0
  620. package/src/adapter/zigate/driver/messageType.ts +287 -0
  621. package/src/adapter/zigate/driver/parameterType.ts +32 -0
  622. package/src/adapter/zigate/driver/ziGateObject.ts +146 -0
  623. package/src/adapter/zigate/driver/zigate.ts +426 -0
  624. package/src/adapter/zoh/adapter/utils.ts +27 -0
  625. package/src/adapter/zoh/adapter/zohAdapter.ts +837 -0
  626. package/src/buffalo/buffalo.ts +335 -0
  627. package/src/buffalo/index.ts +1 -0
  628. package/src/controller/controller.ts +1048 -0
  629. package/src/controller/database.ts +124 -0
  630. package/src/controller/events.ts +51 -0
  631. package/src/controller/greenPower.ts +603 -0
  632. package/src/controller/helpers/index.ts +1 -0
  633. package/src/controller/helpers/request.ts +94 -0
  634. package/src/controller/helpers/requestQueue.ts +125 -0
  635. package/src/controller/helpers/zclFrameConverter.ts +51 -0
  636. package/src/controller/helpers/zclTransactionSequenceNumber.ts +19 -0
  637. package/src/controller/index.ts +6 -0
  638. package/src/controller/model/device.ts +1320 -0
  639. package/src/controller/model/endpoint.ts +1040 -0
  640. package/src/controller/model/entity.ts +23 -0
  641. package/src/controller/model/group.ts +333 -0
  642. package/src/controller/model/index.ts +4 -0
  643. package/src/controller/touchlink.ts +189 -0
  644. package/src/controller/tstype.ts +39 -0
  645. package/src/index.ts +12 -0
  646. package/src/models/backup-storage-legacy.ts +48 -0
  647. package/src/models/backup-storage-unified.ts +47 -0
  648. package/src/models/backup.ts +37 -0
  649. package/src/models/index.ts +5 -0
  650. package/src/models/network-options.ts +11 -0
  651. package/src/utils/backup.ts +152 -0
  652. package/src/utils/index.ts +5 -0
  653. package/src/utils/logger.ts +20 -0
  654. package/src/utils/patchBigIntSerialization.ts +8 -0
  655. package/src/utils/queue.ts +76 -0
  656. package/src/utils/types.d.ts +3 -0
  657. package/src/utils/utils.ts +20 -0
  658. package/src/utils/wait.ts +5 -0
  659. package/src/utils/waitress.ts +95 -0
  660. package/src/zspec/consts.ts +84 -0
  661. package/src/zspec/enums.ts +22 -0
  662. package/src/zspec/index.ts +3 -0
  663. package/src/zspec/tstypes.ts +18 -0
  664. package/src/zspec/utils.ts +308 -0
  665. package/src/zspec/zcl/buffaloZcl.ts +1133 -0
  666. package/src/zspec/zcl/definition/cluster.ts +5398 -0
  667. package/src/zspec/zcl/definition/consts.ts +24 -0
  668. package/src/zspec/zcl/definition/enums.ts +194 -0
  669. package/src/zspec/zcl/definition/foundation.ts +301 -0
  670. package/src/zspec/zcl/definition/manufacturerCode.ts +729 -0
  671. package/src/zspec/zcl/definition/status.ts +69 -0
  672. package/src/zspec/zcl/definition/tstype.ts +236 -0
  673. package/src/zspec/zcl/index.ts +10 -0
  674. package/src/zspec/zcl/utils.ts +342 -0
  675. package/src/zspec/zcl/zclFrame.ts +336 -0
  676. package/src/zspec/zcl/zclHeader.ts +102 -0
  677. package/src/zspec/zcl/zclStatusError.ts +10 -0
  678. package/src/zspec/zdo/buffaloZdo.ts +2345 -0
  679. package/src/zspec/zdo/definition/clusters.ts +722 -0
  680. package/src/zspec/zdo/definition/consts.ts +16 -0
  681. package/src/zspec/zdo/definition/enums.ts +99 -0
  682. package/src/zspec/zdo/definition/status.ts +105 -0
  683. package/src/zspec/zdo/definition/tstypes.ts +1062 -0
  684. package/src/zspec/zdo/index.ts +7 -0
  685. package/src/zspec/zdo/utils.ts +76 -0
  686. package/src/zspec/zdo/zdoStatusError.ts +10 -0
  687. package/test/adapter/adapter.test.ts +1062 -0
  688. package/test/adapter/ember/ash.test.ts +337 -0
  689. package/test/adapter/ember/consts.ts +131 -0
  690. package/test/adapter/ember/emberAdapter.test.ts +3449 -0
  691. package/test/adapter/ember/ezsp.test.ts +386 -0
  692. package/test/adapter/ember/ezspBuffalo.test.ts +92 -0
  693. package/test/adapter/ember/ezspError.test.ts +11 -0
  694. package/test/adapter/ember/math.test.ts +205 -0
  695. package/test/adapter/ezsp/frame.test.ts +29 -0
  696. package/test/adapter/ezsp/uart.test.ts +180 -0
  697. package/test/adapter/z-stack/adapter.test.ts +3985 -0
  698. package/test/adapter/z-stack/constants.test.ts +32 -0
  699. package/test/adapter/z-stack/structs.test.ts +114 -0
  700. package/test/adapter/z-stack/unpi.test.ts +212 -0
  701. package/test/adapter/z-stack/znp.test.ts +1284 -0
  702. package/test/adapter/zboss/fixZdoResponse.test.ts +178 -0
  703. package/test/adapter/zigate/patchZdoBuffaloBE.test.ts +80 -0
  704. package/test/adapter/zigate/zdo.test.ts +187 -0
  705. package/test/adapter/zoh/utils.test.ts +35 -0
  706. package/test/adapter/zoh/zohAdapter.test.ts +1306 -0
  707. package/test/buffalo.test.ts +430 -0
  708. package/test/controller.test.ts +10005 -0
  709. package/test/greenpower.test.ts +1421 -0
  710. package/test/mockAdapters.ts +65 -0
  711. package/test/mockDevices.ts +472 -0
  712. package/test/testUtils.ts +20 -0
  713. package/test/tsconfig.json +10 -0
  714. package/test/utils/math.ts +19 -0
  715. package/test/utils.test.ts +227 -0
  716. package/test/vitest.config.mts +25 -0
  717. package/test/zcl.test.ts +2832 -0
  718. package/test/zspec/utils.test.ts +131 -0
  719. package/test/zspec/zcl/buffalo.test.ts +1231 -0
  720. package/test/zspec/zcl/frame.test.ts +925 -0
  721. package/test/zspec/zcl/utils.test.ts +280 -0
  722. package/test/zspec/zdo/buffalo.test.ts +1849 -0
  723. package/test/zspec/zdo/utils.test.ts +240 -0
  724. package/.prettierignore +0 -2
  725. package/.prettierrc +0 -26
  726. package/eslint.config.mjs +0 -32
@@ -0,0 +1,1320 @@
1
+ import assert from "node:assert";
2
+
3
+ import type {Events as AdapterEvents} from "../../adapter";
4
+ import type {LQINeighbor, RoutingTableEntry} from "../../adapter/tstype";
5
+ import {wait} from "../../utils";
6
+ import {logger} from "../../utils/logger";
7
+ import * as ZSpec from "../../zspec";
8
+ import {BroadcastAddress} from "../../zspec/enums";
9
+ import type {Eui64} from "../../zspec/tstypes";
10
+ import * as Zcl from "../../zspec/zcl";
11
+ import type {ClusterDefinition, CustomClusters} from "../../zspec/zcl/definition/tstype";
12
+ import * as Zdo from "../../zspec/zdo";
13
+ import type {ControllerEventMap} from "../controller";
14
+ import {ZclFrameConverter} from "../helpers";
15
+ import zclTransactionSequenceNumber from "../helpers/zclTransactionSequenceNumber";
16
+ import type {DatabaseEntry, DeviceType, KeyValue} from "../tstype";
17
+ import Endpoint from "./endpoint";
18
+ import Entity from "./entity";
19
+
20
+ /**
21
+ * @ignore
22
+ */
23
+ const OneJanuary2000 = new Date("January 01, 2000 00:00:00 UTC+00:00").getTime();
24
+
25
+ const NS = "zh:controller:device";
26
+
27
+ interface Lqi {
28
+ neighbors: {
29
+ ieeeAddr: string;
30
+ networkAddress: number;
31
+ linkquality: number;
32
+ relationship: number;
33
+ depth: number;
34
+ }[];
35
+ }
36
+
37
+ interface RoutingTable {
38
+ table: {destinationAddress: number; status: string; nextHop: number}[];
39
+ }
40
+
41
+ type CustomReadResponse = (frame: Zcl.Frame, endpoint: Endpoint) => boolean;
42
+
43
+ export enum InterviewState {
44
+ Pending = "PENDING",
45
+ InProgress = "IN_PROGRESS",
46
+ Successful = "SUCCESSFUL",
47
+ Failed = "FAILED",
48
+ }
49
+
50
+ export class Device extends Entity<ControllerEventMap> {
51
+ // biome-ignore lint/style/useNamingConvention: cross-repo impact
52
+ private readonly ID: number;
53
+ private _applicationVersion?: number;
54
+ private _dateCode?: string;
55
+ private _endpoints: Endpoint[];
56
+ private _hardwareVersion?: number;
57
+ private _ieeeAddr: string;
58
+ private _interviewState: InterviewState;
59
+ private _lastSeen?: number;
60
+ private _manufacturerID?: number;
61
+ private _manufacturerName?: string;
62
+ private _modelID?: string;
63
+ private _networkAddress: number;
64
+ private _powerSource?: string;
65
+ private _softwareBuildID?: string;
66
+ private _stackVersion?: number;
67
+ private _type: DeviceType;
68
+ private _zclVersion?: number;
69
+ private _linkquality?: number;
70
+ private _skipDefaultResponse: boolean;
71
+ private _customReadResponse?: CustomReadResponse;
72
+ private _lastDefaultResponseSequenceNumber?: number;
73
+ private _checkinInterval?: number;
74
+ private _pendingRequestTimeout: number;
75
+ private _customClusters: CustomClusters = {};
76
+ private _gpSecurityKey?: number[];
77
+
78
+ // Getters/setters
79
+ get ieeeAddr(): string {
80
+ return this._ieeeAddr;
81
+ }
82
+ set ieeeAddr(ieeeAddr: string) {
83
+ this._ieeeAddr = ieeeAddr;
84
+ }
85
+ get applicationVersion(): number | undefined {
86
+ return this._applicationVersion;
87
+ }
88
+ set applicationVersion(applicationVersion: number) {
89
+ this._applicationVersion = applicationVersion;
90
+ }
91
+ get endpoints(): Endpoint[] {
92
+ return this._endpoints;
93
+ }
94
+ get interviewState(): InterviewState {
95
+ return this._interviewState;
96
+ }
97
+ get lastSeen(): number | undefined {
98
+ return this._lastSeen;
99
+ }
100
+ get manufacturerID(): number | undefined {
101
+ return this._manufacturerID;
102
+ }
103
+ get isDeleted(): boolean {
104
+ return Device.deletedDevices.has(this.ieeeAddr);
105
+ }
106
+ set type(type: DeviceType) {
107
+ this._type = type;
108
+ }
109
+ get type(): DeviceType {
110
+ return this._type;
111
+ }
112
+ get dateCode(): string | undefined {
113
+ return this._dateCode;
114
+ }
115
+ set dateCode(dateCode: string) {
116
+ this._dateCode = dateCode;
117
+ }
118
+ set hardwareVersion(hardwareVersion: number) {
119
+ this._hardwareVersion = hardwareVersion;
120
+ }
121
+ get hardwareVersion(): number | undefined {
122
+ return this._hardwareVersion;
123
+ }
124
+ get manufacturerName(): string | undefined {
125
+ return this._manufacturerName;
126
+ }
127
+ set manufacturerName(manufacturerName: string | undefined) {
128
+ this._manufacturerName = manufacturerName;
129
+ }
130
+ set modelID(modelID: string) {
131
+ this._modelID = modelID;
132
+ }
133
+ get modelID(): string | undefined {
134
+ return this._modelID;
135
+ }
136
+ get networkAddress(): number {
137
+ return this._networkAddress;
138
+ }
139
+ set networkAddress(networkAddress: number) {
140
+ Device.nwkToIeeeCache.delete(this._networkAddress);
141
+
142
+ this._networkAddress = networkAddress;
143
+
144
+ Device.nwkToIeeeCache.set(this._networkAddress, this.ieeeAddr);
145
+
146
+ for (const endpoint of this._endpoints) {
147
+ endpoint.deviceNetworkAddress = networkAddress;
148
+ }
149
+ }
150
+ get powerSource(): string | undefined {
151
+ return this._powerSource;
152
+ }
153
+ set powerSource(powerSource: string) {
154
+ this._powerSource = typeof powerSource === "number" ? Zcl.POWER_SOURCES[powerSource & ~(1 << 7)] : powerSource;
155
+ }
156
+ get softwareBuildID(): string | undefined {
157
+ return this._softwareBuildID;
158
+ }
159
+ set softwareBuildID(softwareBuildID: string) {
160
+ this._softwareBuildID = softwareBuildID;
161
+ }
162
+ get stackVersion(): number | undefined {
163
+ return this._stackVersion;
164
+ }
165
+ set stackVersion(stackVersion: number) {
166
+ this._stackVersion = stackVersion;
167
+ }
168
+ get zclVersion(): number | undefined {
169
+ return this._zclVersion;
170
+ }
171
+ set zclVersion(zclVersion: number) {
172
+ this._zclVersion = zclVersion;
173
+ }
174
+ get linkquality(): number | undefined {
175
+ return this._linkquality;
176
+ }
177
+ set linkquality(linkquality: number) {
178
+ this._linkquality = linkquality;
179
+ }
180
+ get skipDefaultResponse(): boolean {
181
+ return this._skipDefaultResponse;
182
+ }
183
+ set skipDefaultResponse(skipDefaultResponse: boolean) {
184
+ this._skipDefaultResponse = skipDefaultResponse;
185
+ }
186
+ get customReadResponse(): CustomReadResponse | undefined {
187
+ return this._customReadResponse;
188
+ }
189
+ set customReadResponse(customReadResponse: CustomReadResponse | undefined) {
190
+ this._customReadResponse = customReadResponse;
191
+ }
192
+ get checkinInterval(): number | undefined {
193
+ return this._checkinInterval;
194
+ }
195
+ set checkinInterval(checkinInterval: number | undefined) {
196
+ this._checkinInterval = checkinInterval;
197
+
198
+ this.resetPendingRequestTimeout();
199
+ }
200
+ get pendingRequestTimeout(): number {
201
+ return this._pendingRequestTimeout;
202
+ }
203
+ set pendingRequestTimeout(pendingRequestTimeout: number) {
204
+ this._pendingRequestTimeout = pendingRequestTimeout;
205
+ }
206
+ get customClusters(): CustomClusters {
207
+ return this._customClusters;
208
+ }
209
+ get gpSecurityKey(): number[] | undefined {
210
+ return this._gpSecurityKey;
211
+ }
212
+
213
+ public meta: KeyValue;
214
+
215
+ // This lookup contains all devices that are queried from the database, this is to ensure that always
216
+ // the same instance is returned.
217
+ private static readonly devices: Map<string /* IEEE */, Device> = new Map();
218
+ private static loadedFromDatabase = false;
219
+ private static readonly deletedDevices: Map<string /* IEEE */, Device> = new Map();
220
+ private static readonly nwkToIeeeCache: Map<number /* nwk addr */, string /* IEEE */> = new Map();
221
+
222
+ public static readonly REPORTABLE_PROPERTIES_MAPPING: {
223
+ [s: string]: {
224
+ set: (value: string | number, device: Device) => void;
225
+ key:
226
+ | "modelID"
227
+ | "manufacturerName"
228
+ | "applicationVersion"
229
+ | "zclVersion"
230
+ | "powerSource"
231
+ | "stackVersion"
232
+ | "dateCode"
233
+ | "softwareBuildID"
234
+ | "hardwareVersion";
235
+ };
236
+ } = {
237
+ modelId: {
238
+ key: "modelID",
239
+ set: (v: string | number, d: Device): void => {
240
+ d.modelID = v as string;
241
+ },
242
+ },
243
+ manufacturerName: {
244
+ key: "manufacturerName",
245
+ set: (v: string | number, d: Device): void => {
246
+ d.manufacturerName = v as string;
247
+ },
248
+ },
249
+ powerSource: {
250
+ key: "powerSource",
251
+ set: (v: string | number, d: Device): void => {
252
+ d.powerSource = v as string;
253
+ },
254
+ },
255
+ zclVersion: {
256
+ key: "zclVersion",
257
+ set: (v: string | number, d: Device): void => {
258
+ d.zclVersion = v as number;
259
+ },
260
+ },
261
+ appVersion: {
262
+ key: "applicationVersion",
263
+ set: (v: string | number, d: Device): void => {
264
+ d.applicationVersion = v as number;
265
+ },
266
+ },
267
+ stackVersion: {
268
+ key: "stackVersion",
269
+ set: (v: string | number, d: Device): void => {
270
+ d.stackVersion = v as number;
271
+ },
272
+ },
273
+ hwVersion: {
274
+ key: "hardwareVersion",
275
+ set: (v: string | number, d: Device): void => {
276
+ d.hardwareVersion = v as number;
277
+ },
278
+ },
279
+ dateCode: {
280
+ key: "dateCode",
281
+ set: (v: string | number, d: Device): void => {
282
+ d.dateCode = v as string;
283
+ },
284
+ },
285
+ swBuildId: {
286
+ key: "softwareBuildID",
287
+ set: (v: string | number, d: Device): void => {
288
+ d.softwareBuildID = v as string;
289
+ },
290
+ },
291
+ };
292
+
293
+ private constructor(
294
+ id: number,
295
+ type: DeviceType,
296
+ ieeeAddr: string,
297
+ networkAddress: number,
298
+ manufacturerID: number | undefined,
299
+ endpoints: Endpoint[],
300
+ manufacturerName: string | undefined,
301
+ powerSource: string | undefined,
302
+ modelID: string | undefined,
303
+ applicationVersion: number | undefined,
304
+ stackVersion: number | undefined,
305
+ zclVersion: number | undefined,
306
+ hardwareVersion: number | undefined,
307
+ dateCode: string | undefined,
308
+ softwareBuildID: string | undefined,
309
+ interviewState: InterviewState,
310
+ meta: KeyValue,
311
+ lastSeen: number | undefined,
312
+ checkinInterval: number | undefined,
313
+ pendingRequestTimeout: number,
314
+ gpSecurityKey: number[] | undefined,
315
+ ) {
316
+ super();
317
+ this.ID = id;
318
+ this._type = type;
319
+ this._ieeeAddr = ieeeAddr;
320
+ this._networkAddress = networkAddress;
321
+ this._manufacturerID = manufacturerID;
322
+ this._endpoints = endpoints;
323
+ this._manufacturerName = manufacturerName;
324
+ this._powerSource = powerSource;
325
+ this._modelID = modelID;
326
+ this._applicationVersion = applicationVersion;
327
+ this._stackVersion = stackVersion;
328
+ this._zclVersion = zclVersion;
329
+ this._hardwareVersion = hardwareVersion;
330
+ this._dateCode = dateCode;
331
+ this._softwareBuildID = softwareBuildID;
332
+ this._interviewState = interviewState;
333
+ this._skipDefaultResponse = false;
334
+ this.meta = meta;
335
+ this._lastSeen = lastSeen;
336
+ this._checkinInterval = checkinInterval;
337
+ this._pendingRequestTimeout = pendingRequestTimeout;
338
+ this._gpSecurityKey = gpSecurityKey;
339
+ }
340
+
341
+ public createEndpoint(id: number): Endpoint {
342
+ if (this.getEndpoint(id)) {
343
+ throw new Error(`Device '${this.ieeeAddr}' already has an endpoint '${id}'`);
344
+ }
345
+
346
+ const endpoint = Endpoint.create(id, undefined, undefined, [], [], this.networkAddress, this.ieeeAddr);
347
+ this.endpoints.push(endpoint);
348
+ this.save();
349
+ return endpoint;
350
+ }
351
+
352
+ public changeIeeeAddress(ieeeAddr: string): void {
353
+ Device.devices.delete(this.ieeeAddr);
354
+ this.ieeeAddr = ieeeAddr;
355
+ Device.devices.set(this.ieeeAddr, this);
356
+ Device.nwkToIeeeCache.set(this.networkAddress, this.ieeeAddr);
357
+ for (const ep of this.endpoints) {
358
+ ep.deviceIeeeAddress = ieeeAddr;
359
+ }
360
+
361
+ this.save();
362
+ }
363
+
364
+ public getEndpoint(id: number): Endpoint | undefined {
365
+ return this.endpoints.find((e): boolean => e.ID === id);
366
+ }
367
+
368
+ // There might be multiple endpoints with same DeviceId but it is not supported and first endpoint is returned
369
+ public getEndpointByDeviceType(deviceType: string): Endpoint | undefined {
370
+ const deviceID = Zcl.ENDPOINT_DEVICE_TYPE[deviceType];
371
+ return this.endpoints.find((d): boolean => d.deviceID === deviceID);
372
+ }
373
+
374
+ public implicitCheckin(): void {
375
+ // No need to do anythign in `catch` as `endpoint.sendRequest` already logs failures.
376
+ Promise.allSettled(this.endpoints.map((e) => e.sendPendingRequests(false))).catch(() => {});
377
+ }
378
+
379
+ public updateLastSeen(): void {
380
+ this._lastSeen = Date.now();
381
+ }
382
+
383
+ private resetPendingRequestTimeout(): void {
384
+ // pendingRequestTimeout can be changed dynamically at runtime, and it is not persisted.
385
+ // Default timeout is one checkin interval in milliseconds.
386
+ this._pendingRequestTimeout = (this._checkinInterval ?? 0) * 1000;
387
+ }
388
+
389
+ private hasPendingRequests(): boolean {
390
+ return this.endpoints.find((e) => e.hasPendingRequests()) !== undefined;
391
+ }
392
+
393
+ public async onZclData(dataPayload: AdapterEvents.ZclPayload, frame: Zcl.Frame, endpoint: Endpoint): Promise<void> {
394
+ // Update reportable properties
395
+ if (frame.isCluster("genBasic") && (frame.isCommand("readRsp") || frame.isCommand("report"))) {
396
+ const attrKeyValue = ZclFrameConverter.attributeKeyValue(frame, this.manufacturerID, this.customClusters);
397
+
398
+ for (const key in attrKeyValue) {
399
+ Device.REPORTABLE_PROPERTIES_MAPPING[key]?.set(attrKeyValue[key], this);
400
+ }
401
+ }
402
+
403
+ // Respond to enroll requests
404
+ if (frame.header.isSpecific && frame.isCluster("ssIasZone") && frame.isCommand("enrollReq")) {
405
+ logger.debug(`IAS - '${this.ieeeAddr}' responding to enroll response`, NS);
406
+ const payload = {enrollrspcode: 0, zoneid: 23};
407
+ await endpoint.command("ssIasZone", "enrollRsp", payload, {disableDefaultResponse: true});
408
+ }
409
+
410
+ // Reponse to read requests
411
+ if (frame.header.isGlobal && frame.isCommand("read") && !this._customReadResponse?.(frame, endpoint)) {
412
+ const time = Math.round((new Date().getTime() - OneJanuary2000) / 1000);
413
+ const attributes: {[s: string]: KeyValue} = {
414
+ ...endpoint.clusters,
415
+ genTime: {
416
+ attributes: {
417
+ timeStatus: 3, // Time-master + synchronised
418
+ time: time,
419
+ timeZone: new Date().getTimezoneOffset() * -1 * 60,
420
+ localTime: time - new Date().getTimezoneOffset() * 60,
421
+ lastSetTime: time,
422
+ validUntilTime: time + 24 * 60 * 60, // valid for 24 hours
423
+ },
424
+ },
425
+ };
426
+
427
+ if (frame.cluster.name in attributes) {
428
+ const response: KeyValue = {};
429
+ for (const entry of frame.payload) {
430
+ if (frame.cluster.hasAttribute(entry.attrId)) {
431
+ const name = frame.cluster.getAttribute(entry.attrId).name;
432
+ if (name in attributes[frame.cluster.name].attributes) {
433
+ response[name] = attributes[frame.cluster.name].attributes[name];
434
+ }
435
+ }
436
+ }
437
+
438
+ try {
439
+ await endpoint.readResponse(frame.cluster.ID, frame.header.transactionSequenceNumber, response, {
440
+ srcEndpoint: dataPayload.destinationEndpoint,
441
+ });
442
+ } catch (error) {
443
+ logger.error(`Read response to ${this.ieeeAddr} failed (${(error as Error).message})`, NS);
444
+ }
445
+ }
446
+ }
447
+
448
+ // Handle check-in from sleeping end devices
449
+ if (frame.header.isSpecific && frame.isCluster("genPollCtrl") && frame.isCommand("checkin")) {
450
+ try {
451
+ if (this.hasPendingRequests() || this._checkinInterval === undefined) {
452
+ const payload = {
453
+ startFastPolling: true,
454
+ fastPollTimeout: 0,
455
+ };
456
+ logger.debug(`check-in from ${this.ieeeAddr}: accepting fast-poll`, NS);
457
+ await endpoint.command(frame.cluster.ID, "checkinRsp", payload, {sendPolicy: "immediate"});
458
+
459
+ // This is a good time to read the checkin interval if we haven't stored it previously
460
+ if (this._checkinInterval === undefined) {
461
+ const pollPeriod = await endpoint.read("genPollCtrl", ["checkinInterval"], {sendPolicy: "immediate"});
462
+ this._checkinInterval = pollPeriod.checkinInterval / 4; // convert to seconds
463
+ this.resetPendingRequestTimeout();
464
+ logger.debug(`Request Queue (${this.ieeeAddr}): default expiration timeout set to ${this.pendingRequestTimeout}`, NS);
465
+ }
466
+
467
+ await Promise.all(this.endpoints.map(async (e) => await e.sendPendingRequests(true)));
468
+ // We *must* end fast-poll when we're done sending things. Otherwise
469
+ // we cause undue power-drain.
470
+ logger.debug(`check-in from ${this.ieeeAddr}: stopping fast-poll`, NS);
471
+ await endpoint.command(frame.cluster.ID, "fastPollStop", {}, {sendPolicy: "immediate"});
472
+ } else {
473
+ const payload = {
474
+ startFastPolling: false,
475
+ fastPollTimeout: 0,
476
+ };
477
+ logger.debug(`check-in from ${this.ieeeAddr}: declining fast-poll`, NS);
478
+ await endpoint.command(frame.cluster.ID, "checkinRsp", payload, {sendPolicy: "immediate"});
479
+ }
480
+ } catch (error) {
481
+ logger.error(`Handling of poll check-in from ${this.ieeeAddr} failed (${(error as Error).message})`, NS);
482
+ }
483
+ }
484
+
485
+ // Send a default response if necessary.
486
+ const isDefaultResponse = frame.header.isGlobal && frame.command.name === "defaultRsp";
487
+ const commandHasResponse = frame.command.response !== undefined;
488
+ const disableDefaultResponse = frame.header.frameControl.disableDefaultResponse;
489
+ /* v8 ignore next */
490
+ const disableTuyaDefaultResponse = endpoint.getDevice().manufacturerName?.startsWith("_TZ") && process.env.DISABLE_TUYA_DEFAULT_RESPONSE;
491
+ // Sometimes messages are received twice, prevent responding twice
492
+ const alreadyResponded = this._lastDefaultResponseSequenceNumber === frame.header.transactionSequenceNumber;
493
+
494
+ if (
495
+ this.type !== "GreenPower" &&
496
+ !dataPayload.wasBroadcast &&
497
+ !disableDefaultResponse &&
498
+ !isDefaultResponse &&
499
+ !commandHasResponse &&
500
+ !this._skipDefaultResponse &&
501
+ !alreadyResponded &&
502
+ !disableTuyaDefaultResponse
503
+ ) {
504
+ try {
505
+ this._lastDefaultResponseSequenceNumber = frame.header.transactionSequenceNumber;
506
+ // In the ZCL it is not documented what the direction of the default response should be
507
+ // In https://github.com/Koenkk/zigbee2mqtt/issues/18096 a commandResponse (SERVER_TO_CLIENT)
508
+ // is send and the device expects a CLIENT_TO_SERVER back.
509
+ // Previously SERVER_TO_CLIENT was always used.
510
+ // Therefore for non-global commands we inverse the direction.
511
+ const direction = frame.header.isGlobal
512
+ ? Zcl.Direction.SERVER_TO_CLIENT
513
+ : frame.header.frameControl.direction === Zcl.Direction.CLIENT_TO_SERVER
514
+ ? Zcl.Direction.SERVER_TO_CLIENT
515
+ : Zcl.Direction.CLIENT_TO_SERVER;
516
+
517
+ await endpoint.defaultResponse(frame.command.ID, 0, frame.cluster.ID, frame.header.transactionSequenceNumber, {direction});
518
+ } catch (error) {
519
+ logger.debug(`Default response to ${this.ieeeAddr} failed (${error})`, NS);
520
+ }
521
+ }
522
+ }
523
+
524
+ /*
525
+ * CRUD
526
+ */
527
+
528
+ /**
529
+ * Reset runtime lookups.
530
+ */
531
+ public static resetCache(): void {
532
+ Device.devices.clear();
533
+ Device.loadedFromDatabase = false;
534
+ Device.deletedDevices.clear();
535
+ Device.nwkToIeeeCache.clear();
536
+ }
537
+
538
+ private static fromDatabaseEntry(entry: DatabaseEntry): Device {
539
+ const networkAddress = entry.nwkAddr;
540
+ const ieeeAddr = entry.ieeeAddr;
541
+ const endpoints: Endpoint[] = [];
542
+
543
+ for (const id in entry.endpoints) {
544
+ endpoints.push(Endpoint.fromDatabaseRecord(entry.endpoints[id], networkAddress, ieeeAddr));
545
+ }
546
+
547
+ const meta = entry.meta ?? {};
548
+
549
+ if (entry.type === "Group") {
550
+ throw new Error("Cannot load device from group");
551
+ }
552
+
553
+ // default: no timeout (messages expire immediately after first send attempt)
554
+ let pendingRequestTimeout = 0;
555
+ if (endpoints.filter((e): boolean => e.inputClusters.includes(Zcl.Clusters.genPollCtrl.ID)).length > 0) {
556
+ // default for devices that support genPollCtrl cluster (RX off when idle): 1 day
557
+ pendingRequestTimeout = 86400000;
558
+ }
559
+ // always load value from database available (modernExtend.quirkCheckinInterval() exists for devices without genPollCtl)
560
+ if (entry.checkinInterval !== undefined) {
561
+ // if the checkin interval is known, messages expire by default after one checkin interval
562
+ pendingRequestTimeout = entry.checkinInterval * 1000; // milliseconds
563
+ }
564
+ logger.debug(`Request Queue (${ieeeAddr}): default expiration timeout set to ${pendingRequestTimeout}`, NS);
565
+
566
+ // Migrate interviewCompleted to interviewState
567
+ if (!entry.interviewState) {
568
+ entry.interviewState = entry.interviewCompleted ? InterviewState.Successful : InterviewState.Failed;
569
+ logger.debug(`Migrated interviewState for '${ieeeAddr}': ${entry.interviewCompleted} -> ${entry.interviewState}`, NS);
570
+ }
571
+
572
+ return new Device(
573
+ entry.id,
574
+ entry.type,
575
+ ieeeAddr,
576
+ networkAddress,
577
+ entry.manufId,
578
+ endpoints,
579
+ entry.manufName,
580
+ entry.powerSource,
581
+ entry.modelId,
582
+ entry.appVersion,
583
+ entry.stackVersion,
584
+ entry.zclVersion,
585
+ entry.hwVersion,
586
+ entry.dateCode,
587
+ entry.swBuildId,
588
+ entry.interviewState,
589
+ meta,
590
+ entry.lastSeen,
591
+ entry.checkinInterval,
592
+ pendingRequestTimeout,
593
+ entry.gpSecurityKey,
594
+ );
595
+ }
596
+
597
+ private toDatabaseEntry(): DatabaseEntry {
598
+ const epList = this.endpoints.map((e): number => e.ID);
599
+ const endpoints: KeyValue = {};
600
+
601
+ for (const endpoint of this.endpoints) {
602
+ endpoints[endpoint.ID] = endpoint.toDatabaseRecord();
603
+ }
604
+
605
+ return {
606
+ id: this.ID,
607
+ type: this.type,
608
+ ieeeAddr: this.ieeeAddr,
609
+ nwkAddr: this.networkAddress,
610
+ manufId: this.manufacturerID,
611
+ manufName: this.manufacturerName,
612
+ powerSource: this.powerSource,
613
+ modelId: this.modelID,
614
+ epList,
615
+ endpoints,
616
+ appVersion: this.applicationVersion,
617
+ stackVersion: this.stackVersion,
618
+ hwVersion: this.hardwareVersion,
619
+ dateCode: this.dateCode,
620
+ swBuildId: this.softwareBuildID,
621
+ zclVersion: this.zclVersion,
622
+ /** @deprecated Keep interviewCompleted for backwards compatibility (in case zh gets downgraded) */
623
+ interviewCompleted: this.interviewState === InterviewState.Successful,
624
+ interviewState: this.interviewState === InterviewState.InProgress ? InterviewState.Pending : this.interviewState,
625
+ meta: this.meta,
626
+ lastSeen: this.lastSeen,
627
+ checkinInterval: this.checkinInterval,
628
+ gpSecurityKey: this.gpSecurityKey,
629
+ };
630
+ }
631
+
632
+ public save(writeDatabase = true): void {
633
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
634
+ Entity.database!.update(this.toDatabaseEntry(), writeDatabase);
635
+ }
636
+
637
+ private static loadFromDatabaseIfNecessary(): void {
638
+ if (!Device.loadedFromDatabase) {
639
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
640
+ for (const entry of Entity.database!.getEntriesIterator(["Coordinator", "EndDevice", "Router", "GreenPower", "Unknown"])) {
641
+ const device = Device.fromDatabaseEntry(entry);
642
+
643
+ Device.devices.set(device.ieeeAddr, device);
644
+ Device.nwkToIeeeCache.set(device.networkAddress, device.ieeeAddr);
645
+ }
646
+
647
+ Device.loadedFromDatabase = true;
648
+ }
649
+ }
650
+
651
+ public static find(ieeeOrNwkAddress: string | number, includeDeleted = false): Device | undefined {
652
+ return typeof ieeeOrNwkAddress === "string"
653
+ ? Device.byIeeeAddr(ieeeOrNwkAddress, includeDeleted)
654
+ : Device.byNetworkAddress(ieeeOrNwkAddress, includeDeleted);
655
+ }
656
+
657
+ public static byIeeeAddr(ieeeAddr: string, includeDeleted = false): Device | undefined {
658
+ Device.loadFromDatabaseIfNecessary();
659
+
660
+ return includeDeleted ? (Device.deletedDevices.get(ieeeAddr) ?? Device.devices.get(ieeeAddr)) : Device.devices.get(ieeeAddr);
661
+ }
662
+
663
+ public static byNetworkAddress(networkAddress: number, includeDeleted = false): Device | undefined {
664
+ Device.loadFromDatabaseIfNecessary();
665
+
666
+ const ieeeAddr = Device.nwkToIeeeCache.get(networkAddress);
667
+
668
+ return ieeeAddr ? Device.byIeeeAddr(ieeeAddr, includeDeleted) : undefined;
669
+ }
670
+
671
+ public static byType(type: DeviceType): Device[] {
672
+ const devices: Device[] = [];
673
+
674
+ for (const device of Device.allIterator((d) => d.type === type)) {
675
+ devices.push(device);
676
+ }
677
+
678
+ return devices;
679
+ }
680
+
681
+ /**
682
+ * @deprecated use allIterator()
683
+ */
684
+ public static all(): Device[] {
685
+ Device.loadFromDatabaseIfNecessary();
686
+ return Array.from(Device.devices.values());
687
+ }
688
+
689
+ public static *allIterator(predicate?: (value: Device) => boolean): Generator<Device> {
690
+ Device.loadFromDatabaseIfNecessary();
691
+
692
+ for (const device of Device.devices.values()) {
693
+ if (!predicate || predicate(device)) {
694
+ yield device;
695
+ }
696
+ }
697
+ }
698
+
699
+ public undelete(): void {
700
+ if (Device.deletedDevices.delete(this.ieeeAddr)) {
701
+ Device.devices.set(this.ieeeAddr, this);
702
+
703
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
704
+ Entity.database!.insert(this.toDatabaseEntry());
705
+ } else {
706
+ throw new Error(`Device '${this.ieeeAddr}' is not deleted`);
707
+ }
708
+ }
709
+
710
+ public static create(
711
+ type: DeviceType,
712
+ ieeeAddr: string,
713
+ networkAddress: number,
714
+ manufacturerID: number | undefined,
715
+ manufacturerName: string | undefined,
716
+ powerSource: string | undefined,
717
+ modelID: string | undefined,
718
+ interviewState: InterviewState,
719
+ gpSecurityKey: number[] | undefined,
720
+ ): Device {
721
+ Device.loadFromDatabaseIfNecessary();
722
+
723
+ if (Device.devices.has(ieeeAddr)) {
724
+ throw new Error(`Device with IEEE address '${ieeeAddr}' already exists`);
725
+ }
726
+
727
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
728
+ const ID = Entity.database!.newID();
729
+ const device = new Device(
730
+ ID,
731
+ type,
732
+ ieeeAddr,
733
+ networkAddress,
734
+ manufacturerID,
735
+ [],
736
+ manufacturerName,
737
+ powerSource,
738
+ modelID,
739
+ undefined,
740
+ undefined,
741
+ undefined,
742
+ undefined,
743
+ undefined,
744
+ undefined,
745
+ interviewState,
746
+ {},
747
+ undefined,
748
+ undefined,
749
+ 0,
750
+ gpSecurityKey,
751
+ );
752
+
753
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
754
+ Entity.database!.insert(device.toDatabaseEntry());
755
+ Device.devices.set(device.ieeeAddr, device);
756
+ Device.nwkToIeeeCache.set(device.networkAddress, device.ieeeAddr);
757
+ return device;
758
+ }
759
+
760
+ /*
761
+ * Zigbee functions
762
+ */
763
+
764
+ public async interview(ignoreCache = false): Promise<void> {
765
+ if (this.interviewState === InterviewState.InProgress) {
766
+ const message = `Interview - interview already in progress for '${this.ieeeAddr}'`;
767
+ logger.debug(message, NS);
768
+ throw new Error(message);
769
+ }
770
+
771
+ let err: unknown;
772
+ this._interviewState = InterviewState.InProgress;
773
+ logger.debug(`Interview - start device '${this.ieeeAddr}'`, NS);
774
+
775
+ try {
776
+ await this.interviewInternal(ignoreCache);
777
+ logger.debug(`Interview - completed for device '${this.ieeeAddr}'`, NS);
778
+ this._interviewState = InterviewState.Successful;
779
+ } catch (error) {
780
+ if (this.interviewQuirks()) {
781
+ this._interviewState = InterviewState.Successful;
782
+ logger.debug(`Interview - completed for device '${this.ieeeAddr}' because of quirks ('${error}')`, NS);
783
+ } else {
784
+ this._interviewState = InterviewState.Failed;
785
+ logger.debug(`Interview - failed for device '${this.ieeeAddr}' with error '${error}'`, NS);
786
+ err = error;
787
+ }
788
+ } finally {
789
+ this.save();
790
+ }
791
+
792
+ if (err) {
793
+ throw err;
794
+ }
795
+ }
796
+
797
+ private interviewQuirks(): boolean {
798
+ logger.debug(`Interview - quirks check for '${this.modelID}'-'${this.manufacturerName}'-'${this.type}'`, NS);
799
+
800
+ // Tuya devices are typically hard to interview. They also don't require a full interview to work correctly
801
+ // e.g. no ias enrolling is required for the devices to work.
802
+ // Assume that in case we got both the manufacturerName and modelID the device works correctly.
803
+ // https://github.com/Koenkk/zigbee2mqtt/issues/7564:
804
+ // Fails during ias enroll due to UNSUPPORTED_ATTRIBUTE
805
+ // https://github.com/Koenkk/zigbee2mqtt/issues/4655
806
+ // Device does not change zoneState after enroll (event with original gateway)
807
+ // modelID is mostly in the form of e.g. TS0202 and manufacturerName like e.g. _TYZB01_xph99wvr
808
+ if (this.modelID?.match("^TS\\d*$") && (this.manufacturerName?.match("^_TZ.*_.*$") || this.manufacturerName?.match("^_TYZB01_.*$"))) {
809
+ this._powerSource = this._powerSource || "Battery";
810
+ logger.debug("Interview - quirks matched for Tuya end device", NS);
811
+ return true;
812
+ }
813
+
814
+ // Some devices, e.g. Xiaomi end devices have a different interview procedure, after pairing they
815
+ // report it's modelID trough a readResponse. The readResponse is received by the controller and set
816
+ // on the device.
817
+ const lookup: {
818
+ [s: string]: {
819
+ type?: DeviceType;
820
+ manufacturerID?: number;
821
+ manufacturerName?: string;
822
+ powerSource?: string;
823
+ };
824
+ } = {
825
+ "^3R.*?Z": {
826
+ type: "EndDevice",
827
+ powerSource: "Battery",
828
+ },
829
+ "lumi..*": {
830
+ type: "EndDevice",
831
+ manufacturerID: 4151,
832
+ manufacturerName: "LUMI",
833
+ powerSource: "Battery",
834
+ },
835
+ "TERNCY-PP01": {
836
+ type: "EndDevice",
837
+ manufacturerID: 4648,
838
+ manufacturerName: "TERNCY",
839
+ powerSource: "Battery",
840
+ },
841
+ "3RWS18BZ": {}, // https://github.com/Koenkk/zigbee-herdsman-converters/pull/2710
842
+ "MULTI-MECI--EA01": {},
843
+ MOT003: {}, // https://github.com/Koenkk/zigbee2mqtt/issues/12471
844
+ "C-ZB-SEDC": {}, //candeo device that doesn't follow IAS enrollment process correctly and therefore fails to complete interview
845
+ "C-ZB-SEMO": {}, //candeo device that doesn't follow IAS enrollment process correctly and therefore fails to complete interview
846
+ };
847
+
848
+ let match: string | undefined;
849
+
850
+ for (const key in lookup) {
851
+ if (this.modelID?.match(key)) {
852
+ match = key;
853
+ break;
854
+ }
855
+ }
856
+
857
+ if (match) {
858
+ const info = lookup[match];
859
+ logger.debug(`Interview procedure failed but got modelID matching '${match}', assuming interview succeeded`, NS);
860
+ this._type = this._type === "Unknown" && info.type ? info.type : this._type;
861
+ this._manufacturerID = this._manufacturerID || info.manufacturerID;
862
+ this._manufacturerName = this._manufacturerName || info.manufacturerName;
863
+ this._powerSource = this._powerSource || info.powerSource;
864
+ logger.debug(`Interview - quirks matched on '${match}'`, NS);
865
+ return true;
866
+ }
867
+
868
+ logger.debug("Interview - quirks did not match", NS);
869
+ return false;
870
+ }
871
+
872
+ private async interviewInternal(ignoreCache: boolean): Promise<void> {
873
+ const hasNodeDescriptor = (): boolean => this._manufacturerID !== undefined && this._type !== "Unknown";
874
+
875
+ if (ignoreCache || !hasNodeDescriptor()) {
876
+ for (let attempt = 0; attempt < 6; attempt++) {
877
+ try {
878
+ await this.updateNodeDescriptor();
879
+ break;
880
+ } catch (error) {
881
+ if (this.interviewQuirks()) {
882
+ logger.debug(`Interview - completed for device '${this.ieeeAddr}' because of quirks ('${error}')`, NS);
883
+ return;
884
+ }
885
+
886
+ // Most of the times the first node descriptor query fails and the seconds one succeeds.
887
+ logger.debug(`Interview - node descriptor request failed for '${this.ieeeAddr}', attempt ${attempt + 1}`, NS);
888
+ }
889
+ }
890
+ } else {
891
+ logger.debug(`Interview - skip node descriptor request for '${this.ieeeAddr}', already got it`, NS);
892
+ }
893
+
894
+ if (!hasNodeDescriptor()) {
895
+ throw new Error(`Interview failed because can not get node descriptor ('${this.ieeeAddr}')`);
896
+ }
897
+
898
+ if (this.manufacturerID === 4619 && this._type === "EndDevice") {
899
+ // Give Tuya end device some time to pair. Otherwise they leave immediately.
900
+ // https://github.com/Koenkk/zigbee2mqtt/issues/5814
901
+ logger.debug("Interview - Detected Tuya end device, waiting 10 seconds...", NS);
902
+ await wait(10000);
903
+ } else if (this.manufacturerID === 0 || this.manufacturerID === 4098) {
904
+ // Potentially a Tuya device, some sleep fast so make sure to read the modelId and manufacturerName quickly.
905
+ // In case the device responds, the endoint and modelID/manufacturerName are set
906
+ // in controller.onZclOrRawData()
907
+ // https://github.com/Koenkk/zigbee2mqtt/issues/7553
908
+ logger.debug("Interview - Detected potential Tuya end device, reading modelID and manufacturerName...", NS);
909
+ try {
910
+ const endpoint = Endpoint.create(1, undefined, undefined, [], [], this.networkAddress, this.ieeeAddr);
911
+ const result = await endpoint.read("genBasic", ["modelId", "manufacturerName"], {sendPolicy: "immediate"});
912
+
913
+ for (const key in result) {
914
+ Device.REPORTABLE_PROPERTIES_MAPPING[key].set(result[key], this);
915
+ }
916
+ } catch (error) {
917
+ logger.debug(`Interview - Tuya read modelID and manufacturerName failed (${error})`, NS);
918
+ }
919
+ }
920
+
921
+ // e.g. Xiaomi Aqara Opple devices fail to respond to the first active endpoints request, therefore try 2 times
922
+ // https://github.com/Koenkk/zigbee-herdsman/pull/103
923
+ let gotActiveEndpoints = false;
924
+
925
+ for (let attempt = 0; attempt < 2; attempt++) {
926
+ try {
927
+ await this.updateActiveEndpoints();
928
+ gotActiveEndpoints = true;
929
+ break;
930
+ } catch (error) {
931
+ logger.debug(`Interview - active endpoints request failed for '${this.ieeeAddr}', attempt ${attempt + 1} (${error})`, NS);
932
+ }
933
+ }
934
+
935
+ if (!gotActiveEndpoints) {
936
+ throw new Error(`Interview failed because can not get active endpoints ('${this.ieeeAddr}')`);
937
+ }
938
+
939
+ logger.debug(`Interview - got active endpoints for device '${this.ieeeAddr}'`, NS);
940
+
941
+ const coordinator = Device.byType("Coordinator")[0];
942
+
943
+ for (const endpoint of this._endpoints) {
944
+ await endpoint.updateSimpleDescriptor();
945
+ logger.debug(`Interview - got simple descriptor for endpoint '${endpoint.ID}' device '${this.ieeeAddr}'`, NS);
946
+
947
+ // Read attributes
948
+ // nice to have but not required for successful pairing as most of the attributes are not mandatory in ZCL specification
949
+ if (endpoint.supportsInputCluster("genBasic")) {
950
+ for (const key in Device.REPORTABLE_PROPERTIES_MAPPING) {
951
+ const item = Device.REPORTABLE_PROPERTIES_MAPPING[key];
952
+
953
+ if (ignoreCache || !this[item.key]) {
954
+ try {
955
+ let result: KeyValue;
956
+
957
+ try {
958
+ result = await endpoint.read("genBasic", [key], {sendPolicy: "immediate"});
959
+ } catch (error) {
960
+ // Reading attributes can fail for many reason, e.g. it could be that device rejoins
961
+ // while joining like in:
962
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/2485.
963
+ // The modelID and manufacturerName are crucial for device identification, so retry.
964
+ if (item.key === "modelID" || item.key === "manufacturerName") {
965
+ logger.debug(`Interview - first ${item.key} retrieval attempt failed, retrying after 10 seconds...`, NS);
966
+ await wait(10000);
967
+ result = await endpoint.read("genBasic", [key], {sendPolicy: "immediate"});
968
+ } else {
969
+ throw error;
970
+ }
971
+ }
972
+
973
+ item.set(result[key], this);
974
+ logger.debug(`Interview - got '${item.key}' for device '${this.ieeeAddr}'`, NS);
975
+ } catch (error) {
976
+ logger.debug(`Interview - failed to read attribute '${item.key}' from endpoint '${endpoint.ID}' (${error})`, NS);
977
+ }
978
+ }
979
+ }
980
+ }
981
+
982
+ // Enroll IAS device
983
+ if (endpoint.supportsInputCluster("ssIasZone")) {
984
+ logger.debug(`Interview - IAS - enrolling '${this.ieeeAddr}' endpoint '${endpoint.ID}'`, NS);
985
+
986
+ const stateBefore = await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState"], {sendPolicy: "immediate"});
987
+ logger.debug(`Interview - IAS - before enrolling state: '${JSON.stringify(stateBefore)}'`, NS);
988
+
989
+ // Do not enroll when device has already been enrolled
990
+ if (stateBefore.zoneState !== 1 || stateBefore.iasCieAddr !== coordinator.ieeeAddr) {
991
+ logger.debug("Interview - IAS - not enrolled, enrolling", NS);
992
+
993
+ await endpoint.write("ssIasZone", {iasCieAddr: coordinator.ieeeAddr}, {sendPolicy: "immediate"});
994
+ logger.debug("Interview - IAS - wrote iasCieAddr", NS);
995
+
996
+ // There are 2 enrollment procedures:
997
+ // - Auto enroll: coordinator has to send enrollResponse without receiving an enroll request
998
+ // this case is handled below.
999
+ // - Manual enroll: coordinator replies to enroll request with an enroll response.
1000
+ // this case in hanled in onZclData().
1001
+ // https://github.com/Koenkk/zigbee2mqtt/issues/4569#issuecomment-706075676
1002
+ await wait(500);
1003
+ logger.debug(`IAS - '${this.ieeeAddr}' sending enroll response (auto enroll)`, NS);
1004
+ const payload = {enrollrspcode: 0, zoneid: 23};
1005
+ await endpoint.command("ssIasZone", "enrollRsp", payload, {disableDefaultResponse: true, sendPolicy: "immediate"});
1006
+
1007
+ let enrolled = false;
1008
+ for (let attempt = 0; attempt < 20; attempt++) {
1009
+ await wait(500);
1010
+ const stateAfter = await endpoint.read("ssIasZone", ["iasCieAddr", "zoneState"], {sendPolicy: "immediate"});
1011
+ logger.debug(`Interview - IAS - after enrolling state (${attempt}): '${JSON.stringify(stateAfter)}'`, NS);
1012
+ if (stateAfter.zoneState === 1) {
1013
+ enrolled = true;
1014
+ break;
1015
+ }
1016
+ }
1017
+
1018
+ if (enrolled) {
1019
+ logger.debug(`Interview - IAS successfully enrolled '${this.ieeeAddr}' endpoint '${endpoint.ID}'`, NS);
1020
+ } else {
1021
+ throw new Error(`Interview failed because of failed IAS enroll (zoneState didn't change ('${this.ieeeAddr}')`);
1022
+ }
1023
+ } else {
1024
+ logger.debug("Interview - IAS - already enrolled, skipping enroll", NS);
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ // Bind poll control
1030
+ try {
1031
+ for (const endpoint of this.endpoints.filter((e): boolean => e.supportsInputCluster("genPollCtrl"))) {
1032
+ logger.debug(`Interview - Poll control - binding '${this.ieeeAddr}' endpoint '${endpoint.ID}'`, NS);
1033
+ await endpoint.bind("genPollCtrl", coordinator.endpoints[0]);
1034
+ const pollPeriod = await endpoint.read("genPollCtrl", ["checkinInterval"], {sendPolicy: "immediate"});
1035
+ this._checkinInterval = pollPeriod.checkinInterval / 4; // convert to seconds
1036
+ this.resetPendingRequestTimeout();
1037
+ }
1038
+ /* v8 ignore start */
1039
+ } catch (error) {
1040
+ logger.debug(`Interview - failed to bind genPollCtrl (${error})`, NS);
1041
+ }
1042
+ /* v8 ignore stop */
1043
+ }
1044
+
1045
+ public async updateNodeDescriptor(): Promise<void> {
1046
+ const clusterId = Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST;
1047
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1048
+ const zdoPayload = Zdo.Buffalo.buildRequest(Entity.adapter!.hasZdoMessageOverhead, clusterId, this.networkAddress);
1049
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1050
+ const response = await Entity.adapter!.sendZdo(this.ieeeAddr, this.networkAddress, clusterId, zdoPayload, false);
1051
+
1052
+ if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.NODE_DESCRIPTOR_RESPONSE>(response)) {
1053
+ throw new Zdo.StatusError(response[0]);
1054
+ }
1055
+
1056
+ // TODO: make use of: capabilities.rxOnWhenIdle, maxIncTxSize, maxOutTxSize, serverMask.stackComplianceRevision
1057
+ const nodeDescriptor = response[1];
1058
+ this._manufacturerID = nodeDescriptor.manufacturerCode;
1059
+
1060
+ switch (nodeDescriptor.logicalType) {
1061
+ case 0x0:
1062
+ this._type = "Coordinator";
1063
+ break;
1064
+ case 0x1:
1065
+ this._type = "Router";
1066
+ break;
1067
+ case 0x2:
1068
+ this._type = "EndDevice";
1069
+ break;
1070
+ }
1071
+
1072
+ logger.debug(`Interview - got node descriptor for device '${this.ieeeAddr}'`, NS);
1073
+
1074
+ // TODO: define a property on Device for this value (would be good to have it displayed)
1075
+ // log for devices older than 1 from current revision
1076
+ if (nodeDescriptor.serverMask.stackComplianceRevision < ZSpec.ZIGBEE_REVISION - 1) {
1077
+ // always 0 before revision 21 where field was added
1078
+ const rev = nodeDescriptor.serverMask.stackComplianceRevision < 21 ? "pre-21" : nodeDescriptor.serverMask.stackComplianceRevision;
1079
+
1080
+ logger.info(
1081
+ `Device '${this.ieeeAddr}' is only compliant to revision '${rev}' of the ZigBee specification (current revision: ${ZSpec.ZIGBEE_REVISION}).`,
1082
+ NS,
1083
+ );
1084
+ }
1085
+ }
1086
+
1087
+ public async updateActiveEndpoints(): Promise<void> {
1088
+ const clusterId = Zdo.ClusterId.ACTIVE_ENDPOINTS_REQUEST;
1089
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1090
+ const zdoPayload = Zdo.Buffalo.buildRequest(Entity.adapter!.hasZdoMessageOverhead, clusterId, this.networkAddress);
1091
+
1092
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1093
+ const response = await Entity.adapter!.sendZdo(this.ieeeAddr, this.networkAddress, clusterId, zdoPayload, false);
1094
+
1095
+ if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.ACTIVE_ENDPOINTS_RESPONSE>(response)) {
1096
+ throw new Zdo.StatusError(response[0]);
1097
+ }
1098
+
1099
+ const activeEndpoints = response[1];
1100
+
1101
+ // Make sure that the endpoint are sorted.
1102
+ activeEndpoints.endpointList.sort((a, b) => a - b);
1103
+ for (const endpoint of activeEndpoints.endpointList) {
1104
+ // Some devices, e.g. TERNCY return endpoint 0 in the active endpoints request.
1105
+ // This is not a valid endpoint number according to the ZCL, requesting a simple descriptor will result
1106
+ // into an error. Therefore we filter it, more info: https://github.com/Koenkk/zigbee-herdsman/issues/82
1107
+ if (endpoint !== 0 && !this.getEndpoint(endpoint)) {
1108
+ this._endpoints.push(Endpoint.create(endpoint, undefined, undefined, [], [], this.networkAddress, this.ieeeAddr));
1109
+ }
1110
+ }
1111
+
1112
+ // Remove disappeared endpoints (can happen with e.g. custom devices).
1113
+ this._endpoints = this._endpoints.filter((e) => activeEndpoints.endpointList.includes(e.ID));
1114
+ }
1115
+
1116
+ /**
1117
+ * Request device to advertise its network address.
1118
+ * Note: This does not actually update the device property (if needed), as this is already done with `zdoResponse` event in Controller.
1119
+ */
1120
+ public async requestNetworkAddress(): Promise<void> {
1121
+ const clusterId = Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
1122
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1123
+ const zdoPayload = Zdo.Buffalo.buildRequest(Entity.adapter!.hasZdoMessageOverhead, clusterId, this.ieeeAddr as Eui64, false, 0);
1124
+
1125
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1126
+ await Entity.adapter!.sendZdo(this.ieeeAddr, ZSpec.BroadcastAddress.RX_ON_WHEN_IDLE, clusterId, zdoPayload, true);
1127
+ }
1128
+
1129
+ public async removeFromNetwork(): Promise<void> {
1130
+ if (this._type === "GreenPower") {
1131
+ const payload = {
1132
+ options: 0x002550,
1133
+ srcID: Number(this.ieeeAddr),
1134
+ };
1135
+ const frame = Zcl.Frame.create(
1136
+ Zcl.FrameType.SPECIFIC,
1137
+ Zcl.Direction.SERVER_TO_CLIENT,
1138
+ true,
1139
+ undefined,
1140
+ zclTransactionSequenceNumber.next(),
1141
+ "pairing",
1142
+ 33,
1143
+ payload,
1144
+ this.customClusters,
1145
+ );
1146
+
1147
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1148
+ await Entity.adapter!.sendZclFrameToAll(242, frame, 242, BroadcastAddress.RX_ON_WHEN_IDLE);
1149
+ } else {
1150
+ const clusterId = Zdo.ClusterId.LEAVE_REQUEST;
1151
+ const zdoPayload = Zdo.Buffalo.buildRequest(
1152
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1153
+ Entity.adapter!.hasZdoMessageOverhead,
1154
+ clusterId,
1155
+ this.ieeeAddr as Eui64,
1156
+ Zdo.LeaveRequestFlags.WITHOUT_REJOIN,
1157
+ );
1158
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1159
+ const response = await Entity.adapter!.sendZdo(this.ieeeAddr, this.networkAddress, clusterId, zdoPayload, false);
1160
+
1161
+ if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.LEAVE_RESPONSE>(response)) {
1162
+ throw new Zdo.StatusError(response[0]);
1163
+ }
1164
+ }
1165
+
1166
+ this.removeFromDatabase();
1167
+ }
1168
+
1169
+ public removeFromDatabase(): void {
1170
+ Device.loadFromDatabaseIfNecessary();
1171
+
1172
+ for (const endpoint of this.endpoints) {
1173
+ endpoint.removeFromAllGroupsDatabase();
1174
+ }
1175
+
1176
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1177
+ if (Entity.database!.has(this.ID)) {
1178
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1179
+ Entity.database!.remove(this.ID);
1180
+ }
1181
+
1182
+ Device.deletedDevices.set(this.ieeeAddr, this);
1183
+ Device.devices.delete(this.ieeeAddr);
1184
+
1185
+ // Clear all data in case device joins again
1186
+ // Green power devices are never interviewed, keep existing interview state.
1187
+ this._interviewState = this.type === "GreenPower" ? this._interviewState : InterviewState.Pending;
1188
+ this.meta = {};
1189
+ const newEndpoints: Endpoint[] = [];
1190
+ for (const endpoint of this.endpoints) {
1191
+ newEndpoints.push(
1192
+ Endpoint.create(
1193
+ endpoint.ID,
1194
+ endpoint.profileID,
1195
+ endpoint.deviceID,
1196
+ endpoint.inputClusters,
1197
+ endpoint.outputClusters,
1198
+ this.networkAddress,
1199
+ this.ieeeAddr,
1200
+ ),
1201
+ );
1202
+ }
1203
+ this._endpoints = newEndpoints;
1204
+ }
1205
+
1206
+ public async lqi(): Promise<Lqi> {
1207
+ const clusterId = Zdo.ClusterId.LQI_TABLE_REQUEST;
1208
+ // TODO return Zdo.LQITableEntry directly (requires updates in other repos)
1209
+ const neighbors: LQINeighbor[] = [];
1210
+ const request = async (startIndex: number): Promise<[tableEntries: number, entryCount: number]> => {
1211
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1212
+ const zdoPayload = Zdo.Buffalo.buildRequest(Entity.adapter!.hasZdoMessageOverhead, clusterId, startIndex);
1213
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1214
+ const response = await Entity.adapter!.sendZdo(this.ieeeAddr, this.networkAddress, clusterId, zdoPayload, false);
1215
+
1216
+ if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.LQI_TABLE_RESPONSE>(response)) {
1217
+ throw new Zdo.StatusError(response[0]);
1218
+ }
1219
+
1220
+ const result = response[1];
1221
+
1222
+ for (const entry of result.entryList) {
1223
+ neighbors.push({
1224
+ ieeeAddr: entry.eui64,
1225
+ networkAddress: entry.nwkAddress,
1226
+ linkquality: entry.lqi,
1227
+ relationship: entry.relationship,
1228
+ depth: entry.depth,
1229
+ });
1230
+ }
1231
+
1232
+ return [result.neighborTableEntries, result.entryList.length];
1233
+ };
1234
+
1235
+ let [tableEntries, entryCount] = await request(0);
1236
+
1237
+ const size = tableEntries;
1238
+ let nextStartIndex = entryCount;
1239
+
1240
+ while (neighbors.length < size) {
1241
+ [tableEntries, entryCount] = await request(nextStartIndex);
1242
+
1243
+ nextStartIndex += entryCount;
1244
+ }
1245
+
1246
+ return {neighbors};
1247
+ }
1248
+
1249
+ public async routingTable(): Promise<RoutingTable> {
1250
+ const clusterId = Zdo.ClusterId.ROUTING_TABLE_REQUEST;
1251
+ // TODO return Zdo.RoutingTableEntry directly (requires updates in other repos)
1252
+ const table: RoutingTableEntry[] = [];
1253
+ const request = async (startIndex: number): Promise<[tableEntries: number, entryCount: number]> => {
1254
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1255
+ const zdoPayload = Zdo.Buffalo.buildRequest(Entity.adapter!.hasZdoMessageOverhead, clusterId, startIndex);
1256
+ // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
1257
+ const response = await Entity.adapter!.sendZdo(this.ieeeAddr, this.networkAddress, clusterId, zdoPayload, false);
1258
+
1259
+ if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.ROUTING_TABLE_RESPONSE>(response)) {
1260
+ throw new Zdo.StatusError(response[0]);
1261
+ }
1262
+
1263
+ const result = response[1];
1264
+
1265
+ for (const entry of result.entryList) {
1266
+ table.push({
1267
+ destinationAddress: entry.destinationAddress,
1268
+ status: entry.status,
1269
+ nextHop: entry.nextHopAddress,
1270
+ });
1271
+ }
1272
+
1273
+ return [result.routingTableEntries, result.entryList.length];
1274
+ };
1275
+
1276
+ let [tableEntries, entryCount] = await request(0);
1277
+
1278
+ const size = tableEntries;
1279
+ let nextStartIndex = entryCount;
1280
+
1281
+ while (table.length < size) {
1282
+ [tableEntries, entryCount] = await request(nextStartIndex);
1283
+
1284
+ nextStartIndex += entryCount;
1285
+ }
1286
+
1287
+ return {table};
1288
+ }
1289
+
1290
+ public async ping(disableRecovery = true): Promise<void> {
1291
+ // Zigbee does not have an official pinging mechanism. Use a read request
1292
+ // of a mandatory basic cluster attribute to keep it as lightweight as
1293
+ // possible.
1294
+ const endpoint = this.endpoints.find((ep) => ep.inputClusters.includes(0)) ?? this.endpoints[0];
1295
+ await endpoint.read("genBasic", ["zclVersion"], {disableRecovery});
1296
+ }
1297
+
1298
+ public addCustomCluster(name: string, cluster: ClusterDefinition): void {
1299
+ assert(
1300
+ ![Zcl.Clusters.touchlink.ID, Zcl.Clusters.greenPower.ID].includes(cluster.ID),
1301
+ "Overriding of greenPower or touchlink cluster is not supported",
1302
+ );
1303
+ if (Zcl.Utils.isClusterName(name)) {
1304
+ const existingCluster = Zcl.Clusters[name];
1305
+
1306
+ // Extend existing cluster
1307
+ assert(existingCluster.ID === cluster.ID, `Custom cluster ID (${cluster.ID}) should match existing cluster ID (${existingCluster.ID})`);
1308
+ cluster = {
1309
+ ID: cluster.ID,
1310
+ manufacturerCode: cluster.manufacturerCode,
1311
+ attributes: {...existingCluster.attributes, ...cluster.attributes},
1312
+ commands: {...existingCluster.commands, ...cluster.commands},
1313
+ commandsResponse: {...existingCluster.commandsResponse, ...cluster.commandsResponse},
1314
+ };
1315
+ }
1316
+ this._customClusters[name] = cluster;
1317
+ }
1318
+ }
1319
+
1320
+ export default Device;