zigbee-herdsman 6.0.1 → 6.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/adapter/ezsp/driver/uart.js +1 -1
  3. package/dist/adapter/ezsp/driver/uart.js.map +1 -1
  4. package/dist/adapter/z-stack/adapter/zStackAdapter.js +4 -4
  5. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  6. package/dist/adapter/zigate/adapter/zigateAdapter.js +4 -4
  7. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  8. package/dist/controller/model/device.d.ts.map +1 -1
  9. package/dist/controller/model/device.js +1 -0
  10. package/dist/controller/model/device.js.map +1 -1
  11. package/package.json +14 -6
  12. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  13. package/.github/dependabot.yml +0 -22
  14. package/.github/workflows/ci.yml +0 -64
  15. package/.github/workflows/release-please.yml +0 -18
  16. package/.github/workflows/stale.yml +0 -20
  17. package/.github/workflows/typedoc.yaml +0 -47
  18. package/.release-please-manifest.json +0 -3
  19. package/.vscode/extensions.json +0 -3
  20. package/.vscode/settings.json +0 -11
  21. package/biome.json +0 -98
  22. package/examples/join-and-log.js +0 -24
  23. package/release-please-config.json +0 -9
  24. package/src/adapter/adapter.ts +0 -189
  25. package/src/adapter/adapterDiscovery.ts +0 -666
  26. package/src/adapter/const.ts +0 -12
  27. package/src/adapter/deconz/adapter/deconzAdapter.ts +0 -877
  28. package/src/adapter/deconz/driver/constants.ts +0 -246
  29. package/src/adapter/deconz/driver/driver.ts +0 -1540
  30. package/src/adapter/deconz/driver/frame.ts +0 -11
  31. package/src/adapter/deconz/driver/frameParser.ts +0 -753
  32. package/src/adapter/deconz/driver/parser.ts +0 -45
  33. package/src/adapter/deconz/driver/writer.ts +0 -22
  34. package/src/adapter/deconz/types.d.ts +0 -13
  35. package/src/adapter/ember/adapter/emberAdapter.ts +0 -2265
  36. package/src/adapter/ember/adapter/endpoints.ts +0 -86
  37. package/src/adapter/ember/adapter/oneWaitress.ts +0 -324
  38. package/src/adapter/ember/adapter/tokensManager.ts +0 -782
  39. package/src/adapter/ember/consts.ts +0 -178
  40. package/src/adapter/ember/enums.ts +0 -1746
  41. package/src/adapter/ember/ezsp/buffalo.ts +0 -1392
  42. package/src/adapter/ember/ezsp/consts.ts +0 -148
  43. package/src/adapter/ember/ezsp/enums.ts +0 -1114
  44. package/src/adapter/ember/ezsp/ezsp.ts +0 -9061
  45. package/src/adapter/ember/ezspError.ts +0 -10
  46. package/src/adapter/ember/types.ts +0 -866
  47. package/src/adapter/ember/uart/ash.ts +0 -1960
  48. package/src/adapter/ember/uart/consts.ts +0 -109
  49. package/src/adapter/ember/uart/enums.ts +0 -192
  50. package/src/adapter/ember/uart/parser.ts +0 -48
  51. package/src/adapter/ember/uart/queues.ts +0 -247
  52. package/src/adapter/ember/uart/writer.ts +0 -53
  53. package/src/adapter/ember/utils/initters.ts +0 -58
  54. package/src/adapter/ember/utils/math.ts +0 -73
  55. package/src/adapter/events.ts +0 -21
  56. package/src/adapter/ezsp/adapter/backup.ts +0 -109
  57. package/src/adapter/ezsp/adapter/ezspAdapter.ts +0 -614
  58. package/src/adapter/ezsp/driver/commands.ts +0 -2497
  59. package/src/adapter/ezsp/driver/consts.ts +0 -11
  60. package/src/adapter/ezsp/driver/driver.ts +0 -1002
  61. package/src/adapter/ezsp/driver/ezsp.ts +0 -802
  62. package/src/adapter/ezsp/driver/frame.ts +0 -101
  63. package/src/adapter/ezsp/driver/index.ts +0 -4
  64. package/src/adapter/ezsp/driver/multicast.ts +0 -78
  65. package/src/adapter/ezsp/driver/parser.ts +0 -81
  66. package/src/adapter/ezsp/driver/types/basic.ts +0 -201
  67. package/src/adapter/ezsp/driver/types/index.ts +0 -239
  68. package/src/adapter/ezsp/driver/types/named.ts +0 -2330
  69. package/src/adapter/ezsp/driver/types/struct.ts +0 -844
  70. package/src/adapter/ezsp/driver/uart.ts +0 -460
  71. package/src/adapter/ezsp/driver/utils/crc16ccitt.ts +0 -44
  72. package/src/adapter/ezsp/driver/utils/index.ts +0 -32
  73. package/src/adapter/ezsp/driver/writer.ts +0 -64
  74. package/src/adapter/index.ts +0 -3
  75. package/src/adapter/serialPort.ts +0 -58
  76. package/src/adapter/socketPortUtils.ts +0 -16
  77. package/src/adapter/tstype.ts +0 -78
  78. package/src/adapter/z-stack/adapter/adapter-backup.ts +0 -519
  79. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +0 -457
  80. package/src/adapter/z-stack/adapter/endpoints.ts +0 -57
  81. package/src/adapter/z-stack/adapter/manager.ts +0 -543
  82. package/src/adapter/z-stack/adapter/tstype.ts +0 -6
  83. package/src/adapter/z-stack/adapter/zStackAdapter.ts +0 -1190
  84. package/src/adapter/z-stack/constants/af.ts +0 -27
  85. package/src/adapter/z-stack/constants/common.ts +0 -285
  86. package/src/adapter/z-stack/constants/dbg.ts +0 -23
  87. package/src/adapter/z-stack/constants/index.ts +0 -11
  88. package/src/adapter/z-stack/constants/mac.ts +0 -128
  89. package/src/adapter/z-stack/constants/sapi.ts +0 -25
  90. package/src/adapter/z-stack/constants/sys.ts +0 -72
  91. package/src/adapter/z-stack/constants/util.ts +0 -82
  92. package/src/adapter/z-stack/constants/utils.ts +0 -14
  93. package/src/adapter/z-stack/constants/zdo.ts +0 -103
  94. package/src/adapter/z-stack/models/startup-options.ts +0 -13
  95. package/src/adapter/z-stack/structs/entries/address-manager-entry.ts +0 -44
  96. package/src/adapter/z-stack/structs/entries/address-manager-table.ts +0 -19
  97. package/src/adapter/z-stack/structs/entries/aps-link-key-data-entry.ts +0 -12
  98. package/src/adapter/z-stack/structs/entries/aps-link-key-data-table.ts +0 -21
  99. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-entry.ts +0 -19
  100. package/src/adapter/z-stack/structs/entries/aps-tc-link-key-table.ts +0 -21
  101. package/src/adapter/z-stack/structs/entries/channel-list.ts +0 -8
  102. package/src/adapter/z-stack/structs/entries/has-configured.ts +0 -16
  103. package/src/adapter/z-stack/structs/entries/index.ts +0 -16
  104. package/src/adapter/z-stack/structs/entries/nib.ts +0 -66
  105. package/src/adapter/z-stack/structs/entries/nwk-key-descriptor.ts +0 -15
  106. package/src/adapter/z-stack/structs/entries/nwk-key.ts +0 -13
  107. package/src/adapter/z-stack/structs/entries/nwk-pan-id.ts +0 -8
  108. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-entry.ts +0 -20
  109. package/src/adapter/z-stack/structs/entries/nwk-sec-material-descriptor-table.ts +0 -19
  110. package/src/adapter/z-stack/structs/entries/security-manager-entry.ts +0 -33
  111. package/src/adapter/z-stack/structs/entries/security-manager-table.ts +0 -22
  112. package/src/adapter/z-stack/structs/index.ts +0 -4
  113. package/src/adapter/z-stack/structs/serializable-memory-object.ts +0 -14
  114. package/src/adapter/z-stack/structs/struct.ts +0 -367
  115. package/src/adapter/z-stack/structs/table.ts +0 -198
  116. package/src/adapter/z-stack/unpi/constants.ts +0 -33
  117. package/src/adapter/z-stack/unpi/frame.ts +0 -62
  118. package/src/adapter/z-stack/unpi/index.ts +0 -4
  119. package/src/adapter/z-stack/unpi/parser.ts +0 -56
  120. package/src/adapter/z-stack/unpi/writer.ts +0 -21
  121. package/src/adapter/z-stack/utils/channel-list.ts +0 -40
  122. package/src/adapter/z-stack/utils/index.ts +0 -2
  123. package/src/adapter/z-stack/utils/network-options.ts +0 -26
  124. package/src/adapter/z-stack/znp/buffaloZnp.ts +0 -175
  125. package/src/adapter/z-stack/znp/definition.ts +0 -2713
  126. package/src/adapter/z-stack/znp/index.ts +0 -2
  127. package/src/adapter/z-stack/znp/parameterType.ts +0 -22
  128. package/src/adapter/z-stack/znp/tstype.ts +0 -44
  129. package/src/adapter/z-stack/znp/utils.ts +0 -10
  130. package/src/adapter/z-stack/znp/znp.ts +0 -342
  131. package/src/adapter/z-stack/znp/zpiObject.ts +0 -148
  132. package/src/adapter/zboss/adapter/zbossAdapter.ts +0 -526
  133. package/src/adapter/zboss/commands.ts +0 -1184
  134. package/src/adapter/zboss/consts.ts +0 -9
  135. package/src/adapter/zboss/driver.ts +0 -422
  136. package/src/adapter/zboss/enums.ts +0 -360
  137. package/src/adapter/zboss/frame.ts +0 -227
  138. package/src/adapter/zboss/reader.ts +0 -65
  139. package/src/adapter/zboss/types.ts +0 -0
  140. package/src/adapter/zboss/uart.ts +0 -428
  141. package/src/adapter/zboss/utils.ts +0 -58
  142. package/src/adapter/zboss/writer.ts +0 -49
  143. package/src/adapter/zigate/adapter/patchZdoBuffaloBE.ts +0 -27
  144. package/src/adapter/zigate/adapter/zigateAdapter.ts +0 -618
  145. package/src/adapter/zigate/driver/LICENSE +0 -17
  146. package/src/adapter/zigate/driver/buffaloZiGate.ts +0 -212
  147. package/src/adapter/zigate/driver/commandType.ts +0 -418
  148. package/src/adapter/zigate/driver/constants.ts +0 -150
  149. package/src/adapter/zigate/driver/frame.ts +0 -197
  150. package/src/adapter/zigate/driver/messageType.ts +0 -287
  151. package/src/adapter/zigate/driver/parameterType.ts +0 -32
  152. package/src/adapter/zigate/driver/ziGateObject.ts +0 -146
  153. package/src/adapter/zigate/driver/zigate.ts +0 -423
  154. package/src/adapter/zoh/adapter/utils.ts +0 -27
  155. package/src/adapter/zoh/adapter/zohAdapter.ts +0 -838
  156. package/src/buffalo/buffalo.ts +0 -342
  157. package/src/buffalo/index.ts +0 -1
  158. package/src/controller/controller.ts +0 -1022
  159. package/src/controller/database.ts +0 -124
  160. package/src/controller/events.ts +0 -52
  161. package/src/controller/greenPower.ts +0 -603
  162. package/src/controller/helpers/index.ts +0 -1
  163. package/src/controller/helpers/installCodes.ts +0 -107
  164. package/src/controller/helpers/request.ts +0 -96
  165. package/src/controller/helpers/requestQueue.ts +0 -125
  166. package/src/controller/helpers/zclFrameConverter.ts +0 -47
  167. package/src/controller/helpers/zclTransactionSequenceNumber.ts +0 -19
  168. package/src/controller/index.ts +0 -6
  169. package/src/controller/model/device.ts +0 -1248
  170. package/src/controller/model/endpoint.ts +0 -1105
  171. package/src/controller/model/entity.ts +0 -23
  172. package/src/controller/model/group.ts +0 -424
  173. package/src/controller/model/index.ts +0 -5
  174. package/src/controller/model/zigbeeEntity.ts +0 -30
  175. package/src/controller/touchlink.ts +0 -189
  176. package/src/controller/tstype.ts +0 -274
  177. package/src/index.ts +0 -12
  178. package/src/models/backup-storage-legacy.ts +0 -48
  179. package/src/models/backup-storage-unified.ts +0 -47
  180. package/src/models/backup.ts +0 -37
  181. package/src/models/index.ts +0 -5
  182. package/src/models/network-options.ts +0 -11
  183. package/src/utils/backup.ts +0 -152
  184. package/src/utils/index.ts +0 -5
  185. package/src/utils/logger.ts +0 -20
  186. package/src/utils/patchBigIntSerialization.ts +0 -8
  187. package/src/utils/queue.ts +0 -76
  188. package/src/utils/types.d.ts +0 -3
  189. package/src/utils/utils.ts +0 -19
  190. package/src/utils/wait.ts +0 -5
  191. package/src/utils/waitress.ts +0 -96
  192. package/src/zspec/consts.ts +0 -84
  193. package/src/zspec/enums.ts +0 -22
  194. package/src/zspec/index.ts +0 -3
  195. package/src/zspec/tstypes.ts +0 -18
  196. package/src/zspec/utils.ts +0 -247
  197. package/src/zspec/zcl/buffaloZcl.ts +0 -1220
  198. package/src/zspec/zcl/definition/cluster.ts +0 -5915
  199. package/src/zspec/zcl/definition/clusters-typegen.ts +0 -588
  200. package/src/zspec/zcl/definition/clusters-types.ts +0 -7331
  201. package/src/zspec/zcl/definition/consts.ts +0 -24
  202. package/src/zspec/zcl/definition/enums.ts +0 -203
  203. package/src/zspec/zcl/definition/foundation.ts +0 -329
  204. package/src/zspec/zcl/definition/manufacturerCode.ts +0 -729
  205. package/src/zspec/zcl/definition/status.ts +0 -69
  206. package/src/zspec/zcl/definition/tstype.ts +0 -377
  207. package/src/zspec/zcl/index.ts +0 -11
  208. package/src/zspec/zcl/utils.ts +0 -321
  209. package/src/zspec/zcl/zclFrame.ts +0 -356
  210. package/src/zspec/zcl/zclHeader.ts +0 -102
  211. package/src/zspec/zcl/zclStatusError.ts +0 -10
  212. package/src/zspec/zdo/buffaloZdo.ts +0 -2336
  213. package/src/zspec/zdo/definition/clusters.ts +0 -722
  214. package/src/zspec/zdo/definition/consts.ts +0 -16
  215. package/src/zspec/zdo/definition/enums.ts +0 -99
  216. package/src/zspec/zdo/definition/status.ts +0 -105
  217. package/src/zspec/zdo/definition/tstypes.ts +0 -1062
  218. package/src/zspec/zdo/index.ts +0 -7
  219. package/src/zspec/zdo/utils.ts +0 -76
  220. package/src/zspec/zdo/zdoStatusError.ts +0 -10
  221. package/test/adapter/adapter.test.ts +0 -1062
  222. package/test/adapter/ember/ash.test.ts +0 -337
  223. package/test/adapter/ember/consts.ts +0 -131
  224. package/test/adapter/ember/emberAdapter.test.ts +0 -3449
  225. package/test/adapter/ember/ezsp.test.ts +0 -385
  226. package/test/adapter/ember/ezspBuffalo.test.ts +0 -93
  227. package/test/adapter/ember/ezspError.test.ts +0 -12
  228. package/test/adapter/ember/math.test.ts +0 -206
  229. package/test/adapter/ezsp/frame.test.ts +0 -30
  230. package/test/adapter/ezsp/uart.test.ts +0 -181
  231. package/test/adapter/z-stack/adapter.test.ts +0 -3984
  232. package/test/adapter/z-stack/constants.test.ts +0 -33
  233. package/test/adapter/z-stack/structs.test.ts +0 -115
  234. package/test/adapter/z-stack/unpi.test.ts +0 -213
  235. package/test/adapter/z-stack/znp.test.ts +0 -1284
  236. package/test/adapter/zboss/fixZdoResponse.test.ts +0 -179
  237. package/test/adapter/zigate/patchZdoBuffaloBE.test.ts +0 -81
  238. package/test/adapter/zigate/zdo.test.ts +0 -187
  239. package/test/adapter/zoh/utils.test.ts +0 -36
  240. package/test/adapter/zoh/zohAdapter.test.ts +0 -1307
  241. package/test/buffalo.test.ts +0 -431
  242. package/test/controller.bench.ts +0 -193
  243. package/test/controller.test.ts +0 -8702
  244. package/test/greenpower.test.ts +0 -1408
  245. package/test/mockAdapters.ts +0 -65
  246. package/test/mockDevices.ts +0 -598
  247. package/test/requests.bench.ts +0 -206
  248. package/test/testUtils.ts +0 -20
  249. package/test/tsconfig.json +0 -9
  250. package/test/utils/math.ts +0 -19
  251. package/test/utils.test.ts +0 -279
  252. package/test/vitest.config.mts +0 -27
  253. package/test/zcl.test.ts +0 -2831
  254. package/test/zspec/utils.test.ts +0 -68
  255. package/test/zspec/zcl/buffalo.test.ts +0 -1374
  256. package/test/zspec/zcl/frame.test.ts +0 -960
  257. package/test/zspec/zcl/utils.test.ts +0 -273
  258. package/test/zspec/zdo/buffalo.test.ts +0 -1850
  259. package/test/zspec/zdo/utils.test.ts +0 -241
  260. package/tsconfig.json +0 -24
@@ -1,877 +0,0 @@
1
- /* v8 ignore start */
2
-
3
- //import Device from "../../../controller/model/device";
4
- import {existsSync, readFileSync} from "node:fs";
5
- import {dirname} from "node:path";
6
- import type * as Models from "../../../models";
7
- import type {Backup, UnifiedBackupStorage} from "../../../models";
8
- import {BackupUtils, Waitress} from "../../../utils";
9
- import {logger} from "../../../utils/logger";
10
- import * as ZSpec from "../../../zspec";
11
- import type {BroadcastAddress} from "../../../zspec/enums";
12
- import * as Zcl from "../../../zspec/zcl";
13
- import * as Zdo from "../../../zspec/zdo";
14
- import type * as ZdoTypes from "../../../zspec/zdo/definition/tstypes";
15
- import Adapter from "../../adapter";
16
- import type * as Events from "../../events";
17
- import type {AdapterOptions, CoordinatorVersion, NetworkOptions, NetworkParameters, SerialPortOptions, StartResult} from "../../tstype";
18
- import PARAM, {
19
- ApsAddressMode,
20
- type ApsDataRequest,
21
- type GpDataInd,
22
- NwkBroadcastAddress,
23
- ParamId,
24
- type ReceivedDataResponse,
25
- type WaitForDataRequest,
26
- } from "../driver/constants";
27
- import Driver from "../driver/driver";
28
- import processFrame, {frameParserEvents} from "../driver/frameParser";
29
-
30
- const NS = "zh:deconz";
31
-
32
- interface WaitressMatcher {
33
- address?: number | string;
34
- endpoint: number;
35
- transactionSequenceNumber?: number;
36
- frameType: Zcl.FrameType;
37
- clusterID: number;
38
- commandIdentifier: number;
39
- direction: number;
40
- }
41
-
42
- export class DeconzAdapter extends Adapter {
43
- private driver: Driver;
44
- private openRequestsQueue: WaitForDataRequest[];
45
- private frameParserEvent = frameParserEvents;
46
- // biome-ignore lint/correctness/noUnusedPrivateClassMembers: ignore
47
- private fwVersion?: CoordinatorVersion;
48
- private waitress: Waitress<Events.ZclPayload, WaitressMatcher>;
49
- private joinPermitted = false;
50
-
51
- public constructor(networkOptions: NetworkOptions, serialPortOptions: SerialPortOptions, backupPath: string, adapterOptions: AdapterOptions) {
52
- super(networkOptions, serialPortOptions, backupPath, adapterOptions);
53
- this.hasZdoMessageOverhead = true;
54
- this.manufacturerID = Zcl.ManufacturerCode.DRESDEN_ELEKTRONIK_INGENIEURTECHNIK_GMBH;
55
-
56
- this.waitress = new Waitress<Events.ZclPayload, WaitressMatcher>(this.waitressValidator, this.waitressTimeoutFormatter);
57
-
58
- const firmwareLog = [];
59
- if (backupPath) {
60
- // optional: get extra logs from the firmware (debug builds)
61
- const dirPath = dirname(backupPath);
62
- const configPath = `${dirPath}/deconz_options.json`;
63
- if (existsSync(configPath)) {
64
- try {
65
- const data = JSON.parse(readFileSync(configPath).toString());
66
- const log = data.firmware_log || [];
67
- if (Array.isArray(log)) {
68
- for (const level of log) {
69
- if (level === "APS" || level === "APS_L2") {
70
- firmwareLog.push(level);
71
- }
72
- }
73
- }
74
- } catch (_err) {}
75
- }
76
- }
77
-
78
- this.driver = new Driver(serialPortOptions, networkOptions, this.getStoredBackup(), firmwareLog);
79
-
80
- this.driver.on("rxFrame", (frame) => processFrame(frame));
81
- this.openRequestsQueue = [];
82
- this.fwVersion = undefined;
83
-
84
- this.frameParserEvent.on("receivedDataPayload", (data) => this.checkReceivedDataPayload(data));
85
- this.frameParserEvent.on("receivedGreenPowerIndication", (data) => this.checkReceivedGreenPowerIndication(data));
86
-
87
- setInterval(() => {
88
- // Need to have a try/catch block here since promised can be rejected which don't
89
- // have a handler waiting for them anymore.
90
- try {
91
- this.checkWaitForDataRequestTimeouts();
92
- } catch (_err) {}
93
- }, 1000);
94
- }
95
-
96
- /**
97
- * Adapter methods
98
- */
99
- public start(): Promise<StartResult> {
100
- // wait here until driver is connected and has queried all firmware parameters
101
- return new Promise((resolve, reject) => {
102
- const start = Date.now();
103
- const iv = setInterval(() => {
104
- if (this.driver.started()) {
105
- clearInterval(iv);
106
- if (this.driver.restoredFromBackup) {
107
- resolve("restored");
108
- } else {
109
- resolve("resumed");
110
- }
111
- return;
112
- }
113
-
114
- if (20000 < Date.now() - start) {
115
- clearInterval(iv);
116
- reject(new Error("failed to start adapter connection to firmware"));
117
- return;
118
- }
119
- }, 50);
120
- });
121
- }
122
-
123
- public async stop(): Promise<void> {
124
- await this.driver.close();
125
- }
126
-
127
- public getCoordinatorIEEE(): Promise<string> {
128
- logger.debug("-------- z2m:getCoordinatorIEEE() ----------------", NS);
129
- if (this.driver.paramMacAddress === 0n) {
130
- return Promise.reject(new Error("Failed to query coordinator MAC address"));
131
- }
132
- return Promise.resolve(`0x${this.driver.paramMacAddress.toString(16).padStart(16, "0")}`);
133
- }
134
-
135
- public async permitJoin(seconds: number, networkAddress?: number): Promise<void> {
136
- const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
137
-
138
- if (networkAddress) {
139
- // `authentication`: TC significance always 1 (zb specs)
140
- const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
141
-
142
- const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
143
-
144
- if (!Zdo.Buffalo.checkStatus<Zdo.ClusterId.PERMIT_JOINING_RESPONSE>(result)) {
145
- // TODO: will disappear once moved upstream
146
- throw new Zdo.StatusError(result[0]);
147
- }
148
- } else {
149
- await this.driver.writeParameterRequest(ParamId.STK_PERMIT_JOIN, seconds);
150
-
151
- logger.debug(`Permit joining on coordinator for ${seconds} sec.`, NS);
152
-
153
- // broadcast permit joining ZDO
154
- if (networkAddress === undefined) {
155
- // `authentication`: TC significance always 1 (zb specs)
156
- const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
157
-
158
- await this.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.DEFAULT, clusterId, zdoPayload, true);
159
- }
160
- }
161
-
162
- this.joinPermitted = seconds !== 0;
163
- }
164
-
165
- public getCoordinatorVersion(): Promise<CoordinatorVersion> {
166
- logger.debug("-------- z2m:getCoordinatorVersion() ----------------", NS);
167
-
168
- // product: number; transportrev: number; majorrel: number; minorrel: number; maintrel: number; revision: string;
169
-
170
- const fw = this.driver.paramFirmwareVersion;
171
- if (fw === 0) {
172
- return Promise.reject(new Error("Failed to query coordinator firmware version"));
173
- }
174
-
175
- const fwString = `0x${fw.toString(16).padStart(8, "0")}`;
176
-
177
- logger.debug(`Firmware version: ${fwString}`, NS);
178
-
179
- let type = "Unknown";
180
- const platform = (fw >> 8) & 0xff;
181
- if (platform === 5) {
182
- type = "ConBee/RaspBee";
183
- } else if (platform === 7) {
184
- type = "ConBee2/RaspBee2";
185
- } else if (platform === 9) {
186
- type = "ConBee3";
187
- }
188
-
189
- // 0x26780700 -> 2.6.78.7.00
190
- const major = (fw >> 28) & 0xf;
191
- const minor = (fw >> 24) & 0xf;
192
- const patch = (fw >> 16) & 0xff;
193
-
194
- const meta = {transportrev: 0, product: 0, majorrel: major, minorrel: minor, maintrel: patch, revision: fwString};
195
- this.fwVersion = {type: type, meta: meta};
196
- return Promise.resolve({type: type, meta: meta});
197
- }
198
-
199
- public async addInstallCode(ieeeAddress: string, key: Buffer, hashed: boolean): Promise<void> {
200
- await this.driver.writeLinkKey(ieeeAddress, hashed ? key : ZSpec.Utils.aes128MmoHash(key));
201
- }
202
- public async reset(_type: "soft" | "hard"): Promise<void> {
203
- return await Promise.reject(new Error("Reset is not supported"));
204
- }
205
-
206
- public waitFor(
207
- networkAddress: number | undefined,
208
- endpoint: number,
209
- frameType: Zcl.FrameType,
210
- direction: Zcl.Direction,
211
- transactionSequenceNumber: number | undefined,
212
- clusterID: number,
213
- commandIdentifier: number,
214
- timeout: number,
215
- ): {promise: Promise<Events.ZclPayload>; cancel: () => void} {
216
- const payload = {
217
- address: networkAddress,
218
- endpoint,
219
- clusterID,
220
- commandIdentifier,
221
- frameType,
222
- direction,
223
- transactionSequenceNumber,
224
- };
225
-
226
- logger.debug(`waitFor() called ${JSON.stringify(payload)}`, NS);
227
-
228
- const waiter = this.waitress.waitFor(payload, timeout);
229
- const cancel = (): void => this.waitress.remove(waiter.ID);
230
- return {promise: waiter.start().promise, cancel};
231
- }
232
-
233
- public async sendZdo(
234
- ieeeAddress: string,
235
- networkAddress: number,
236
- clusterId: Zdo.ClusterId,
237
- payload: Buffer,
238
- disableResponse: true,
239
- ): Promise<void>;
240
- public async sendZdo<K extends keyof ZdoTypes.RequestToResponseMap>(
241
- ieeeAddress: string,
242
- networkAddress: number,
243
- clusterId: K,
244
- payload: Buffer,
245
- disableResponse: false,
246
- ): Promise<ZdoTypes.RequestToResponseMap[K]>;
247
- public async sendZdo<K extends keyof ZdoTypes.RequestToResponseMap>(
248
- ieeeAddress: string,
249
- networkAddress: number,
250
- clusterId: K,
251
- payload: Buffer,
252
- disableResponse: boolean,
253
- ): Promise<ZdoTypes.RequestToResponseMap[K] | undefined> {
254
- const transactionID = this.nextTransactionID();
255
- payload[0] = transactionID;
256
- const txOptions = 0;
257
-
258
- // TODO(mpi): Disable APS ACKs for now until we find a better solution to not block queues.
259
- //if (networkAddress < NwkBroadcastAddress.BroadcastLowPowerRouters) {
260
- // txOptions = 0x4; // enable APS ACKs for unicast addresses
261
- //}
262
-
263
- const isNwkAddrRequest = clusterId === Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
264
- const req: ApsDataRequest = {
265
- requestId: transactionID,
266
- destAddrMode: ApsAddressMode.Nwk,
267
- destAddr16: networkAddress,
268
- destAddr64: isNwkAddrRequest ? ieeeAddress : undefined,
269
- destEndpoint: Zdo.ZDO_ENDPOINT,
270
- profileId: Zdo.ZDO_PROFILE_ID,
271
- clusterId,
272
- srcEndpoint: Zdo.ZDO_ENDPOINT,
273
- asduLength: payload.length,
274
- asduPayload: payload,
275
- txOptions,
276
- radius: PARAM.PARAM.txRadius.DEFAULT_RADIUS,
277
- timeout: 10000,
278
- };
279
-
280
- const responseClusterId = Zdo.Utils.getResponseClusterId(clusterId);
281
- const confirm = this.driver.enqueueApsDataRequest(req);
282
- let indication: undefined | Promise<ReceivedDataResponse>;
283
-
284
- if (!disableResponse) {
285
- if (responseClusterId) {
286
- indication = this.waitForData(
287
- isNwkAddrRequest ? ieeeAddress : networkAddress,
288
- Zdo.ZDO_PROFILE_ID,
289
- responseClusterId,
290
- transactionID,
291
- req.timeout,
292
- );
293
- }
294
- }
295
-
296
- try {
297
- await confirm;
298
-
299
- if (indication) {
300
- const indicationIndex = this.openRequestsQueue.findIndex(
301
- (x) => x.clusterId === responseClusterId && x.transactionSequenceNumber === transactionID,
302
- );
303
-
304
- if (indicationIndex !== -1) {
305
- this.openRequestsQueue[indicationIndex].confirmed = true;
306
- }
307
- }
308
- } catch (err) {
309
- // no need to wait for indication, remove waiter from queue
310
- if (indication) {
311
- const indicationIndex = this.openRequestsQueue.findIndex(
312
- (x) => x.clusterId === responseClusterId && x.transactionSequenceNumber === transactionID,
313
- );
314
-
315
- if (indicationIndex !== -1) {
316
- this.openRequestsQueue.splice(indicationIndex, 1);
317
- }
318
- }
319
-
320
- throw new Error(`failed to send ZDO request seq: (${transactionID}) ${err}`);
321
- }
322
-
323
- if (indication) {
324
- try {
325
- const data = await indication;
326
- // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
327
- return data.zdo! as ZdoTypes.RequestToResponseMap[K];
328
- } catch (error) {
329
- if (responseClusterId === Zdo.ClusterId.ACTIVE_ENDPOINTS_RESPONSE && networkAddress === 0) {
330
- // TODO(mpi): Check following statement on older firmware versions.
331
- // If it is true we can always query firmware parameters for endpoints.
332
-
333
- logger.warning("Failed to determine active endpoints of coordinator, falling back to [1]", NS);
334
- // Some Conbee adapaters don't provide a response to an active endpoint request of the coordinator, always return
335
- // an endpoint here. Before an active endpoint request was done to determine the endpoints, they were hardcoded:
336
- // https://github.com/Koenkk/zigbee-herdsman/blob/d855b3bf85a066cb7c325fe3ef0006873c735add/src/adapter/deconz/adapter/deconzAdapter.ts#L105
337
- const response: ZdoTypes.ResponseMap[Zdo.ClusterId.ACTIVE_ENDPOINTS_RESPONSE] = [
338
- Zdo.Status.SUCCESS,
339
- {endpointList: [1], nwkAddress: 0},
340
- ];
341
- return response as ZdoTypes.RequestToResponseMap[K];
342
- }
343
-
344
- throw error;
345
- }
346
- }
347
- }
348
-
349
- public async sendZclFrameToEndpoint(
350
- _ieeeAddr: string,
351
- networkAddress: number,
352
- endpoint: number,
353
- zclFrame: Zcl.Frame,
354
- timeout: number,
355
- disableResponse: boolean,
356
- // TODO(mpi): in ember driver this means keep going enqueue request to firmware (up to 3 times).
357
- // In our case this a little different: The firmware may reject the requests because no free APS slots are available,
358
- // this is the only case where "recovery" makes sense. Other cases mean the request will never succeed (network offline, invalid request, ...).
359
- _disableRecovery: boolean,
360
- sourceEndpoint?: number,
361
- ): Promise<Events.ZclPayload | undefined> {
362
- const transactionID = this.nextTransactionID();
363
- const payload = zclFrame.toBuffer();
364
-
365
- // TODO(mpi): Enable APS ACKs for tricky devices, maintain a list of those, or keep at least a few slots free for non APS ACK requests.
366
- //const txOptions = 0x4; // 0x00 normal, 0x04 APS ACK
367
- // TODO(mpi): Disable APS ACKs for now until we find a better solution to not block queues.
368
- const txOptions = 0;
369
-
370
- const request: ApsDataRequest = {
371
- requestId: transactionID,
372
- destAddrMode: ApsAddressMode.Nwk,
373
- destAddr16: networkAddress,
374
- destEndpoint: endpoint,
375
- profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
376
- clusterId: zclFrame.cluster.ID,
377
- srcEndpoint: sourceEndpoint || 1,
378
- asduLength: payload.length,
379
- asduPayload: payload,
380
- // TODO(mpi): This must not be a global option.
381
- // Since z2m doesn't provide it, ideally the driver figures this out on its own.
382
- // deCONZ keeps an error count for each device, if devices work fine without APS ACKs don't use them.
383
- // But if errors occur enable them..
384
- //
385
- // ember driver enables ACKs based on 'commandResponseId' which imho doesn't make sense at all:
386
- //
387
- // don't RETRY if no response expected
388
- // if (commandResponseId === undefined)
389
- // apsFrame.options &= ~EmberApsOption.RETRY;
390
- //
391
-
392
- txOptions,
393
- radius: PARAM.PARAM.txRadius.DEFAULT_RADIUS,
394
- // TODO(mpi): We could treat _disableRecovery = true, to retry if enqueue (valid) requests or APS-confirms fail within timeout period?
395
- timeout: timeout,
396
- };
397
-
398
- if (timeout < 1000) {
399
- throw new Error("Unexpected small timeout");
400
- }
401
-
402
- const command = zclFrame.command;
403
-
404
- // NOTE(mpi): 'disableResponse' is not working as expected?
405
- // For now use the same logic as Ember adapter since 'disableResponse === false' alone isn't correct in some cases.
406
- //
407
- // E.g. when replying to an Query Next Image Request the following parameters where passed from z2m:
408
- // { command.response: undefined, zcl.disableDefaultResponse: true, z2m.disableResponse: false }
409
- // This resulted in waiting for a response which never arrives and a timeout error thrown.
410
- let needWaitResponse = false;
411
-
412
- if (command.response !== undefined && disableResponse === false) {
413
- needWaitResponse = true;
414
- } else if (!zclFrame.header.frameControl.disableDefaultResponse) {
415
- needWaitResponse = true;
416
- }
417
-
418
- const confirm = this.driver.enqueueApsDataRequest(request);
419
-
420
- logger.debug(`ZCL request sent with transactionSequenceNumber.: ${zclFrame.header.transactionSequenceNumber}`, NS);
421
- logger.debug(
422
- `command.response: ${command.response}, zcl.disableDefaultResponse: ${zclFrame.header.frameControl.disableDefaultResponse}, z2m.disableResponse: ${disableResponse}, request.timeout: ${request.timeout}`,
423
- NS,
424
- );
425
-
426
- let indication: undefined | Promise<ReceivedDataResponse>;
427
-
428
- if (needWaitResponse) {
429
- indication = this.waitForData(
430
- networkAddress,
431
- ZSpec.HA_PROFILE_ID,
432
- zclFrame.cluster.ID,
433
- zclFrame.header.transactionSequenceNumber,
434
- request.timeout,
435
- );
436
- }
437
-
438
- try {
439
- await confirm;
440
-
441
- if (indication) {
442
- const indicationIndex = this.openRequestsQueue.findIndex(
443
- (x) => x.clusterId === zclFrame.cluster.ID && x.transactionSequenceNumber === zclFrame.header.transactionSequenceNumber,
444
- );
445
-
446
- if (indicationIndex !== -1) {
447
- this.openRequestsQueue[indicationIndex].confirmed = true;
448
- }
449
- }
450
- } catch (err) {
451
- // no need to wait for indication, remove waiter from queue
452
- if (indication) {
453
- const indicationIndex = this.openRequestsQueue.findIndex(
454
- (x) => x.clusterId === zclFrame.cluster.ID && x.transactionSequenceNumber === zclFrame.header.transactionSequenceNumber,
455
- );
456
-
457
- if (indicationIndex !== -1) {
458
- this.openRequestsQueue.splice(indicationIndex, 1);
459
- }
460
- }
461
-
462
- throw new Error(`failed to send ZCL request (${zclFrame.header.transactionSequenceNumber}) ${err}`);
463
- }
464
-
465
- if (indication) {
466
- try {
467
- const data = await indication;
468
-
469
- // TODO(mpi): This is nuts. Need to make sure that srcAddr16 is always valid.
470
- let addr: string | number;
471
- if (data.srcAddr16 !== undefined) addr = data.srcAddr16;
472
- else if (data.srcAddr64 !== undefined) addr = `0x${data.srcAddr64}`;
473
- else throw new Error("Unexpected waitForData() didn't contain valid address");
474
-
475
- const groupId = 0;
476
- const wasBroadCast = false;
477
-
478
- const response: Events.ZclPayload = {
479
- address: addr,
480
- data: data.asduPayload,
481
- clusterID: zclFrame.cluster.ID,
482
- header: Zcl.Header.fromBuffer(data.asduPayload),
483
- endpoint: data.srcEndpoint,
484
- linkquality: data.lqi,
485
- groupID: groupId,
486
- wasBroadcast: wasBroadCast,
487
- destinationEndpoint: data.destEndpoint,
488
- };
489
- logger.debug(`Response received transactionSequenceNumber: ${zclFrame.header.transactionSequenceNumber}`, NS);
490
- return response;
491
- } catch (err) {
492
- throw new Error(`No ZCL response received for (${zclFrame.header.transactionSequenceNumber}) ${err}`);
493
- }
494
- }
495
- }
496
-
497
- public async sendZclFrameToGroup(groupID: number, zclFrame: Zcl.Frame): Promise<void> {
498
- const transactionID = this.nextTransactionID();
499
- const payload = zclFrame.toBuffer();
500
-
501
- logger.debug(`zclFrame to group - ${groupID}`, NS);
502
-
503
- const request: ApsDataRequest = {
504
- requestId: transactionID,
505
- destAddrMode: ApsAddressMode.Group,
506
- destAddr16: groupID,
507
- profileId: 0x104,
508
- clusterId: zclFrame.cluster.ID,
509
- srcEndpoint: 1,
510
- asduLength: payload.length,
511
- asduPayload: payload,
512
- txOptions: 0,
513
- radius: PARAM.PARAM.txRadius.UNLIMITED,
514
- timeout: PARAM.PARAM.APS.MAX_SEND_TIMEOUT,
515
- };
516
-
517
- logger.debug("sendZclFrameToGroup - message send", NS);
518
- return await (this.driver.enqueueApsDataRequest(request) as Promise<void>);
519
- }
520
-
521
- public async sendZclFrameToAll(endpoint: number, zclFrame: Zcl.Frame, sourceEndpoint: number, destination: BroadcastAddress): Promise<void> {
522
- const transactionID = this.nextTransactionID();
523
- const payload = zclFrame.toBuffer();
524
-
525
- logger.debug(`zclFrame to all - ${endpoint}`, NS);
526
-
527
- const request: ApsDataRequest = {
528
- requestId: transactionID,
529
- destAddrMode: ApsAddressMode.Nwk,
530
- destAddr16: destination,
531
- destEndpoint: endpoint,
532
- profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
533
- clusterId: zclFrame.cluster.ID,
534
- srcEndpoint: sourceEndpoint,
535
- asduLength: payload.length,
536
- asduPayload: payload,
537
- txOptions: 0,
538
- radius: PARAM.PARAM.txRadius.UNLIMITED,
539
- timeout: PARAM.PARAM.APS.MAX_SEND_TIMEOUT,
540
- };
541
-
542
- logger.debug("sendZclFrameToAll - message send", NS);
543
- return await (this.driver.enqueueApsDataRequest(request) as Promise<void>);
544
- }
545
-
546
- public async supportsBackup(): Promise<boolean> {
547
- return await Promise.resolve(true);
548
- }
549
-
550
- /**
551
- * Loads currently stored backup and returns it in internal backup model.
552
- */
553
- private getStoredBackup(): Backup | undefined {
554
- if (!existsSync(this.backupPath)) {
555
- return undefined;
556
- }
557
-
558
- let data: UnifiedBackupStorage;
559
-
560
- try {
561
- data = JSON.parse(readFileSync(this.backupPath).toString());
562
- } catch (error) {
563
- throw new Error(`[BACKUP] Coordinator backup is corrupted. (${(error as Error).stack})`);
564
- }
565
-
566
- if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
567
- if (data.metadata?.version !== 1) {
568
- throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
569
- }
570
-
571
- // if (data.metadata.internal.ezspVersion < BACKUP_OLDEST_SUPPORTED_EZSP_VERSION) {
572
- // renameSync(this.backupPath, `${this.backupPath}.old`);
573
- // logger.warning("[BACKUP] Current backup file is from an unsupported EZSP version. Renaming and ignoring.", NS);
574
- // return undefined;
575
- // }
576
-
577
- return BackupUtils.fromUnifiedBackup(data);
578
- }
579
-
580
- throw new Error("[BACKUP] Unknown backup format.");
581
- }
582
-
583
- public async backup(): Promise<Models.Backup> {
584
- if (!this.driver.started()) {
585
- throw new Error("Can't create backup while driver isn't connected");
586
- }
587
-
588
- // NOTE(mpi): The U64 values are put as big endian format into the buffer, same as string (0x001234...)
589
- const extendedPanId = Buffer.alloc(8);
590
- extendedPanId.writeBigUint64BE(this.driver.paramApsUseExtPanid);
591
- const channelList = [this.driver.paramCurrentChannel]; // Utils.unpackChannelList(nib.channelList)
592
- const networkKey = this.driver.paramNwkKey;
593
- const coordinatorIeeeAddress = Buffer.alloc(8);
594
- coordinatorIeeeAddress.writeBigUint64BE(this.driver.paramMacAddress);
595
-
596
- /* return backup structure */
597
- const backup: Models.Backup = {
598
- networkOptions: {
599
- panId: this.driver.paramNwkPanid,
600
- extendedPanId,
601
- channelList,
602
- networkKey,
603
- networkKeyDistribute: false,
604
- },
605
- logicalChannel: this.driver.paramCurrentChannel,
606
- networkKeyInfo: {
607
- sequenceNumber: 0, // TODO(mpi): on newer firmware versions we can read it
608
- frameCounter: this.driver.paramFrameCounter,
609
- },
610
- securityLevel: 0x05, // AES-CCM-32 (fixed)
611
- networkUpdateId: this.driver.paramNwkUpdateId,
612
- coordinatorIeeeAddress,
613
- devices: [], // TODO(mpi): we currently don't have this, but it will be added once install codes get a proper interface
614
- };
615
-
616
- return await Promise.resolve(backup);
617
- }
618
-
619
- public getNetworkParameters(): Promise<NetworkParameters> {
620
- // TODO(mpi): This works with 0x26780700, needs more investigation with older firmware versions.
621
- const panID = this.driver.paramNwkPanid;
622
- const extendedPanID = this.driver.paramApsUseExtPanid;
623
- const channel = this.driver.paramCurrentChannel;
624
- const nwkUpdateID = this.driver.paramNwkUpdateId;
625
-
626
- if (channel === 0 || extendedPanID === 0n) {
627
- return Promise.reject(new Error("Failed to query network parameters"));
628
- }
629
- // TODO(mpi): check this statement, this should work
630
- // For some reason, reading NWK_UPDATE_ID always returns `null` (tested with `0x26780700` on Conbee II)
631
- // 0x24 was taken from https://github.com/zigpy/zigpy-deconz/blob/70910bc6a63e607332b4f12754ba470651eb878c/zigpy_deconz/api.py#L152
632
- // const nwkUpdateId = await this.driver.readParameterRequest(0x24 /*PARAM.PARAM.Network.NWK_UPDATE_ID*/);
633
-
634
- return Promise.resolve({panID, extendedPanID: `0x${extendedPanID.toString(16).padStart(16, "0")}`, channel, nwkUpdateID});
635
- }
636
-
637
- public async restoreChannelInterPAN(): Promise<void> {
638
- await Promise.reject(new Error("not supported"));
639
- }
640
- public async sendZclFrameInterPANToIeeeAddr(_zclFrame: Zcl.Frame, _ieeeAddr: string): Promise<void> {
641
- await Promise.reject(new Error("not supported"));
642
- }
643
- public async sendZclFrameInterPANBroadcast(_zclFrame: Zcl.Frame, _timeout: number): Promise<Events.ZclPayload> {
644
- return await Promise.reject(new Error("not supported"));
645
- }
646
- public async sendZclFrameInterPANBroadcastWithResponse(_zclFrame: Zcl.Frame, _timeout: number): Promise<Events.ZclPayload> {
647
- return await Promise.reject(new Error("not supported"));
648
- }
649
- public async setChannelInterPAN(_channel: number): Promise<void> {
650
- await Promise.reject(new Error("not supported"));
651
- }
652
- public async sendZclFrameInterPANIeeeAddr(_zclFrame: Zcl.Frame, _ieeeAddr: string): Promise<void> {
653
- await Promise.reject(new Error("not supported"));
654
- }
655
-
656
- /**
657
- * Private methods
658
- */
659
-
660
- private waitForData(
661
- addr: number | string,
662
- profileId: number,
663
- clusterId: number,
664
- transactionSequenceNumber: number,
665
- timeout: number,
666
- ): Promise<ReceivedDataResponse> {
667
- return new Promise((resolve, reject): void => {
668
- const ts = Date.now();
669
- if (!timeout) {
670
- timeout = 60000;
671
- }
672
-
673
- const confirmed = false;
674
- const req: WaitForDataRequest = {addr, profileId, clusterId, transactionSequenceNumber, resolve, reject, confirmed, ts, timeout};
675
- this.openRequestsQueue.push(req);
676
- });
677
- }
678
-
679
- private checkReceivedGreenPowerIndication(ind: GpDataInd): void {
680
- const gpdHeader = Buffer.alloc(15); // applicationId === IEEE_ADDRESS ? 20 : 15
681
- gpdHeader.writeUInt8(0b00000001, 0); // frameControl: FrameType.SPECIFIC + Direction.CLIENT_TO_SERVER + disableDefaultResponse=false
682
- gpdHeader.writeUInt8(ind.seqNr, 1);
683
- gpdHeader.writeUInt8(ind.id, 2); // commandIdentifier
684
- gpdHeader.writeUInt16LE(ind.options, 3); // options
685
- gpdHeader.writeUInt32LE(ind.srcId, 5);
686
- // omitted: gpdIEEEAddr (ieeeAddr)
687
- // omitted: gpdEndpoint (uint8)
688
- gpdHeader.writeUInt32LE(ind.frameCounter, 9);
689
- gpdHeader.writeUInt8(ind.commandId, 13);
690
- gpdHeader.writeUInt8(ind.commandFrameSize, 14);
691
-
692
- const payBuf = Buffer.concat([gpdHeader, ind.commandFrame]);
693
- const payload: Events.ZclPayload = {
694
- header: Zcl.Header.fromBuffer(payBuf),
695
- data: payBuf,
696
- clusterID: Zcl.Clusters.greenPower.ID,
697
- address: ind.srcId & 0xffff,
698
- endpoint: ZSpec.GP_ENDPOINT,
699
- linkquality: 0xff, // bogus
700
- groupID: ZSpec.GP_GROUP_ID,
701
- wasBroadcast: true, // Take the codepath that doesn't require `gppNwkAddr` as its not present in the payload
702
- destinationEndpoint: ZSpec.GP_ENDPOINT,
703
- };
704
-
705
- this.waitress.resolve(payload);
706
- this.emit("zclPayload", payload);
707
- }
708
-
709
- private checkWaitForDataRequestTimeouts() {
710
- if (this.openRequestsQueue.length === 0) {
711
- return;
712
- }
713
-
714
- const now = Date.now();
715
- const req: WaitForDataRequest = this.openRequestsQueue[0];
716
-
717
- if (req.confirmed && req.timeout < now - req.ts) {
718
- this.openRequestsQueue.shift();
719
- logger.debug(
720
- `Timeout for request in openRequestsQueue addr: ${req.addr}, clusterId: ${req.clusterId.toString(16)}, profileId: ${req.profileId.toString(16)}, seq: ${req.transactionSequenceNumber}`,
721
- NS,
722
- );
723
- req.reject(new Error("waiting for response TIMEOUT"));
724
- }
725
- }
726
-
727
- private checkReceivedDataPayload(resp: ReceivedDataResponse): void {
728
- //let srcAddr: number | undefined;
729
- //let srcEUI64: string | undefined;
730
- let header: Zcl.Header | undefined;
731
-
732
- //srcAddr = resp.srcAddr16;
733
-
734
- // TODO(mpi): The following shouldn't be needed anymore.
735
-
736
- // if (resp.srcAddr16 != null) {
737
- //
738
- // } else {
739
- // // For some devices srcAddr64 is reported by ConBee 3, even if the frame contains both
740
- // // srcAddr16 and srcAddr64. This happens even if the request was sent to a short address.
741
- // // At least some parts, e.g. the while loop below, only work with srcAddr16 (i.e. the network
742
- // // address) being set. So we try to look up the network address in the list of know devices.
743
- // if (resp.srcAddr64 != null) {
744
- // logger.debug(`Try to find network address of ${resp.srcAddr64}`, NS);
745
- // // Note: Device expects addresses with a 0x prefix...
746
- // srcAddr = Device.byIeeeAddr(`0x${resp.srcAddr64}`, false)?.networkAddress;
747
- // // apperantly some functions furhter up in the protocol stack expect this to be set.
748
- // // so let's make sure they get the network address
749
- // // Note: srcAddr16 can be undefined after this and this is intended behavior
750
- // // there are zigbee frames which do not contain a 16 bit address, e.g. during joining.
751
- // // So any code that relies on srcAddr16 must handle this in some way.
752
- // resp.srcAddr16 = srcAddr;
753
- // }
754
- // }
755
- //
756
- // ---------------------------------------------------------------------
757
- // if (resp.srcAddr16) { // temp test
758
- // const dev = Device.byNetworkAddress(resp.srcAddr16);
759
- //
760
- // if (dev) {
761
- // logger.debug(`APS-DATA.indication from ${dev.ieeeAddr}, ${dev.modelID} ${dev.manufacturerID}`, NS);
762
- // }
763
- // }
764
-
765
- if (resp.profileId === Zdo.ZDO_PROFILE_ID) {
766
- if (resp.zdo) {
767
- if (resp.clusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE) {
768
- // if (Zdo.Buffalo.checkStatus<Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE>(resp.zdo)) {
769
- // srcEUI64 = resp.zdo[1].eui64;
770
- // }
771
- } else if (resp.clusterId === Zdo.ClusterId.END_DEVICE_ANNOUNCE) {
772
- // XXX: using same response for announce (handled by controller) or joined depending on permit join status?
773
- // TODO(mpi): Clarify with core devs, I don't think the adapter should do this?!
774
- if (this.joinPermitted === true && Zdo.Buffalo.checkStatus<Zdo.ClusterId.END_DEVICE_ANNOUNCE>(resp.zdo)) {
775
- const payload = resp.zdo[1];
776
- this.emit("deviceJoined", {networkAddress: payload.nwkAddress, ieeeAddr: payload.eui64});
777
- }
778
- }
779
-
780
- // TODO(mpi) it seems that the controller is only interested in NWK, IEEE and DeviceAnnounce command
781
- // So maybe we should filter here?
782
- this.emit("zdoResponse", resp.clusterId, resp.zdo);
783
- }
784
- } else {
785
- header = Zcl.Header.fromBuffer(resp.asduPayload);
786
-
787
- if (!header) {
788
- logger.debug("Failed tp parse ZCL header of non ZDO command", NS);
789
- }
790
- }
791
-
792
- let i = this.openRequestsQueue.length;
793
-
794
- while (i--) {
795
- const req: WaitForDataRequest = this.openRequestsQueue[i];
796
-
797
- if (req.profileId !== resp.profileId) {
798
- continue;
799
- }
800
-
801
- if (req.profileId === Zdo.ZDO_PROFILE_ID) {
802
- if (req.clusterId !== resp.clusterId) {
803
- continue;
804
- }
805
-
806
- if (req.transactionSequenceNumber !== resp.asduPayload[0]) {
807
- continue; // ZDP sequence number in first byte
808
- }
809
- } else if (header) {
810
- if (header.transactionSequenceNumber !== req.transactionSequenceNumber) {
811
- continue;
812
- }
813
-
814
- if (req.clusterId !== resp.clusterId) {
815
- continue;
816
- }
817
- } else {
818
- continue; // We should always have a valid transactionId (ZDO and ZCL)
819
- }
820
-
821
- this.openRequestsQueue.splice(i, 1);
822
- req.resolve(resp);
823
- }
824
-
825
- if (resp.profileId !== Zdo.ZDO_PROFILE_ID) {
826
- let groupID = 0;
827
- let wasBroadCast = false;
828
-
829
- if (resp.destAddrMode === ApsAddressMode.Group) {
830
- groupID = resp.destAddr16;
831
- wasBroadCast = true;
832
- } else if (resp.destAddrMode === ApsAddressMode.Nwk && resp.destAddr16 >= NwkBroadcastAddress.BroadcastLowPowerRouters) {
833
- wasBroadCast = true;
834
- }
835
-
836
- const payload: Events.ZclPayload = {
837
- clusterID: resp.clusterId,
838
- header,
839
- data: resp.asduPayload,
840
- address: resp.srcAddr16,
841
- endpoint: resp.srcEndpoint,
842
- linkquality: resp.lqi,
843
- groupID: groupID,
844
- wasBroadcast: wasBroadCast,
845
- destinationEndpoint: resp.destEndpoint,
846
- };
847
-
848
- this.waitress.resolve(payload);
849
- this.emit("zclPayload", payload);
850
- }
851
- }
852
-
853
- private nextTransactionID(): number {
854
- return this.driver.nextTransactionID();
855
- }
856
-
857
- private waitressTimeoutFormatter(matcher: WaitressMatcher, timeout: number): string {
858
- return (
859
- `Timeout - ${matcher.address} - ${matcher.endpoint}` +
860
- ` - ${matcher.transactionSequenceNumber} - ${matcher.clusterID}` +
861
- ` - ${matcher.commandIdentifier} after ${timeout}ms`
862
- );
863
- }
864
-
865
- private waitressValidator(payload: Events.ZclPayload, matcher: WaitressMatcher): boolean {
866
- return Boolean(
867
- payload.header &&
868
- (!matcher.address || payload.address === matcher.address) &&
869
- payload.endpoint === matcher.endpoint &&
870
- (!matcher.transactionSequenceNumber || payload.header.transactionSequenceNumber === matcher.transactionSequenceNumber) &&
871
- payload.clusterID === matcher.clusterID &&
872
- matcher.frameType === payload.header.frameControl.frameType &&
873
- matcher.commandIdentifier === payload.header.commandIdentifier &&
874
- matcher.direction === payload.header.frameControl.direction,
875
- );
876
- }
877
- }