@willieee802/zigbee-herdsman 0.49.3 → 0.50.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 (211) hide show
  1. package/.github/dependabot.yml +0 -3
  2. package/.github/workflows/ci.yml +1 -2
  3. package/.github/workflows/release-please.yml +1 -1
  4. package/.github/workflows/typedoc.yaml +3 -3
  5. package/.release-please-manifest.json +1 -1
  6. package/CHANGELOG.md +143 -0
  7. package/biome.json +1 -1
  8. package/dist/adapter/adapter.d.ts +14 -1
  9. package/dist/adapter/adapter.d.ts.map +1 -1
  10. package/dist/adapter/adapter.js +17 -0
  11. package/dist/adapter/adapter.js.map +1 -1
  12. package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
  13. package/dist/adapter/adapterDiscovery.js.map +1 -1
  14. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
  15. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  16. package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
  17. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  18. package/dist/adapter/deconz/driver/constants.d.ts +1 -1
  19. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  20. package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
  21. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  22. package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
  23. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  24. package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
  25. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
  26. package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
  27. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
  28. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
  29. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  30. package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
  31. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  32. package/dist/adapter/ezsp/driver/index.d.ts +1 -1
  33. package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
  34. package/dist/adapter/ezsp/driver/index.js +1 -1
  35. package/dist/adapter/ezsp/driver/index.js.map +1 -1
  36. package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
  37. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  38. package/dist/adapter/ezsp/driver/types/index.js +3 -3
  39. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  40. package/dist/adapter/serialPort.d.ts.map +1 -1
  41. package/dist/adapter/serialPort.js +7 -0
  42. package/dist/adapter/serialPort.js.map +1 -1
  43. package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
  44. package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
  45. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
  46. package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
  47. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  48. package/dist/adapter/z-stack/adapter/manager.js +12 -2
  49. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  50. package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
  51. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
  52. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  53. package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
  54. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  55. package/dist/adapter/z-stack/constants/index.d.ts +1 -1
  56. package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
  57. package/dist/adapter/z-stack/constants/index.js +1 -1
  58. package/dist/adapter/z-stack/constants/index.js.map +1 -1
  59. package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
  60. package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
  61. package/dist/adapter/z-stack/unpi/constants.js +1 -1
  62. package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
  63. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
  64. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  65. package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
  66. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  67. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  68. package/dist/adapter/zboss/driver.js +8 -1
  69. package/dist/adapter/zboss/driver.js.map +1 -1
  70. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  71. package/dist/adapter/zboss/uart.js +14 -2
  72. package/dist/adapter/zboss/uart.js.map +1 -1
  73. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
  74. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  75. package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
  76. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  77. package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
  78. package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
  79. package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
  80. package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
  81. package/dist/controller/controller.d.ts.map +1 -1
  82. package/dist/controller/controller.js +10 -2
  83. package/dist/controller/controller.js.map +1 -1
  84. package/dist/controller/greenPower.d.ts.map +1 -1
  85. package/dist/controller/greenPower.js +15 -9
  86. package/dist/controller/greenPower.js.map +1 -1
  87. package/dist/controller/helpers/ota.d.ts +4 -4
  88. package/dist/controller/helpers/ota.d.ts.map +1 -1
  89. package/dist/controller/helpers/ota.js +28 -9
  90. package/dist/controller/helpers/ota.js.map +1 -1
  91. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  92. package/dist/controller/helpers/zclFrameConverter.js +17 -16
  93. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  94. package/dist/controller/model/device.d.ts +14 -4
  95. package/dist/controller/model/device.d.ts.map +1 -1
  96. package/dist/controller/model/device.js +167 -85
  97. package/dist/controller/model/device.js.map +1 -1
  98. package/dist/controller/model/endpoint.d.ts +7 -3
  99. package/dist/controller/model/endpoint.d.ts.map +1 -1
  100. package/dist/controller/model/endpoint.js +34 -21
  101. package/dist/controller/model/endpoint.js.map +1 -1
  102. package/dist/controller/model/group.d.ts +0 -1
  103. package/dist/controller/model/group.d.ts.map +1 -1
  104. package/dist/controller/model/group.js +14 -19
  105. package/dist/controller/model/group.js.map +1 -1
  106. package/dist/controller/touchlink.js +3 -3
  107. package/dist/controller/touchlink.js.map +1 -1
  108. package/dist/utils/timeService.js +2 -2
  109. package/dist/utils/timeService.js.map +1 -1
  110. package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
  111. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  112. package/dist/zspec/zcl/buffaloZcl.js +198 -96
  113. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  114. package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
  115. package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
  116. package/dist/zspec/zcl/definition/cluster.js +2699 -2808
  117. package/dist/zspec/zcl/definition/cluster.js.map +1 -1
  118. package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
  119. package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
  120. package/dist/zspec/zcl/definition/enums.d.ts +0 -1
  121. package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
  122. package/dist/zspec/zcl/definition/enums.js +0 -1
  123. package/dist/zspec/zcl/definition/enums.js.map +1 -1
  124. package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
  125. package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
  126. package/dist/zspec/zcl/definition/foundation.js +552 -207
  127. package/dist/zspec/zcl/definition/foundation.js.map +1 -1
  128. package/dist/zspec/zcl/definition/status.d.ts +21 -10
  129. package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
  130. package/dist/zspec/zcl/definition/status.js +11 -0
  131. package/dist/zspec/zcl/definition/status.js.map +1 -1
  132. package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
  133. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  134. package/dist/zspec/zcl/utils.d.ts +7 -4
  135. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  136. package/dist/zspec/zcl/utils.js +133 -240
  137. package/dist/zspec/zcl/utils.js.map +1 -1
  138. package/dist/zspec/zcl/zclFrame.d.ts +4 -4
  139. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  140. package/dist/zspec/zcl/zclFrame.js +19 -103
  141. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  142. package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
  143. package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
  144. package/dist/zspec/zcl/zclStatusError.js +2 -2
  145. package/dist/zspec/zcl/zclStatusError.js.map +1 -1
  146. package/package.json +1 -1
  147. package/scripts/clusters-typegen.ts +44 -139
  148. package/src/adapter/adapter.ts +38 -3
  149. package/src/adapter/adapterDiscovery.ts +2 -1
  150. package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
  151. package/src/adapter/deconz/driver/constants.ts +1 -1
  152. package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
  153. package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
  154. package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
  155. package/src/adapter/ezsp/driver/index.ts +1 -1
  156. package/src/adapter/ezsp/driver/types/index.ts +99 -99
  157. package/src/adapter/serialPort.ts +9 -0
  158. package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
  159. package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
  160. package/src/adapter/z-stack/adapter/manager.ts +16 -2
  161. package/src/adapter/z-stack/adapter/tstype.ts +1 -0
  162. package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
  163. package/src/adapter/z-stack/constants/index.ts +1 -1
  164. package/src/adapter/z-stack/unpi/constants.ts +1 -1
  165. package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
  166. package/src/adapter/zboss/driver.ts +8 -1
  167. package/src/adapter/zboss/uart.ts +14 -1
  168. package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
  169. package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
  170. package/src/controller/controller.ts +12 -2
  171. package/src/controller/greenPower.ts +16 -9
  172. package/src/controller/helpers/ota.ts +37 -11
  173. package/src/controller/helpers/zclFrameConverter.ts +20 -17
  174. package/src/controller/model/device.ts +204 -97
  175. package/src/controller/model/endpoint.ts +36 -24
  176. package/src/controller/model/group.ts +14 -20
  177. package/src/controller/touchlink.ts +3 -3
  178. package/src/utils/timeService.ts +2 -2
  179. package/src/zspec/zcl/buffaloZcl.ts +226 -100
  180. package/src/zspec/zcl/definition/cluster.ts +2713 -2822
  181. package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
  182. package/src/zspec/zcl/definition/enums.ts +0 -1
  183. package/src/zspec/zcl/definition/foundation.ts +703 -216
  184. package/src/zspec/zcl/definition/status.ts +22 -11
  185. package/src/zspec/zcl/definition/tstype.ts +59 -58
  186. package/src/zspec/zcl/utils.ts +137 -264
  187. package/src/zspec/zcl/zclFrame.ts +25 -130
  188. package/src/zspec/zcl/zclStatusError.ts +2 -2
  189. package/test/adapter/ember/emberAdapter.test.ts +191 -4
  190. package/test/adapter/ezsp/uart.test.ts +10 -10
  191. package/test/adapter/z-stack/adapter.test.ts +88 -32
  192. package/test/adapter/zoh/zohAdapter.test.ts +4 -4
  193. package/test/controller.test.ts +822 -248
  194. package/test/device-ota.test.ts +141 -16
  195. package/test/device.test.ts +731 -0
  196. package/test/requests.bench.ts +2 -0
  197. package/test/zcl.test.ts +70 -95
  198. package/test/zspec/zcl/buffalo.test.ts +251 -11
  199. package/test/zspec/zcl/foundation.test.ts +990 -0
  200. package/test/zspec/zcl/frame.test.ts +84 -69
  201. package/test/zspec/zcl/utils.test.ts +105 -81
  202. package/tsconfig.json +0 -1
  203. package/scripts/check-clusters-changes.ts +0 -328
  204. package/scripts/clusters-changes.log +0 -584
  205. package/scripts/utils.ts +0 -88
  206. package/scripts/zap-update-clusters-report.json +0 -303
  207. package/scripts/zap-update-clusters.ts +0 -1520
  208. package/scripts/zap-update-types.ts +0 -707
  209. package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
  210. package/scripts/zap-xml-clusters-overrides.ts +0 -400
  211. package/scripts/zap-xml-types.ts +0 -146
@@ -12,7 +12,7 @@ import type {BroadcastAddress} from "../../../zspec/enums";
12
12
  import * as Zcl from "../../../zspec/zcl";
13
13
  import * as Zdo from "../../../zspec/zdo";
14
14
  import type * as ZdoTypes from "../../../zspec/zdo/definition/tstypes";
15
- import Adapter from "../../adapter";
15
+ import Adapter, {type ClusterWaitressMatcher, type ZclWaitressPayload} from "../../adapter";
16
16
  import type * as Events from "../../events";
17
17
  import type {AdapterOptions, CoordinatorVersion, NetworkOptions, NetworkParameters, SerialPortOptions, StartResult} from "../../tstype";
18
18
  import {readBackup} from "../../utils";
@@ -30,23 +30,13 @@ import processFrame, {frameParserEvents} from "../driver/frameParser";
30
30
 
31
31
  const NS = "zh:deconz";
32
32
 
33
- interface WaitressMatcher {
34
- address?: number | string;
35
- endpoint: number;
36
- transactionSequenceNumber?: number;
37
- frameType: Zcl.FrameType;
38
- clusterID: number;
39
- commandIdentifier: number;
40
- direction: number;
41
- }
42
-
43
33
  export class DeconzAdapter extends Adapter {
44
34
  private driver: Driver;
45
35
  private openRequestsQueue: WaitForDataRequest[];
46
36
  private frameParserEvent = frameParserEvents;
47
37
  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: ignore
48
38
  private fwVersion?: CoordinatorVersion;
49
- private waitress: Waitress<Events.ZclPayload, WaitressMatcher>;
39
+ private waitress: Waitress<ZclWaitressPayload, ClusterWaitressMatcher>;
50
40
  private joinPermitted = false;
51
41
 
52
42
  public constructor(networkOptions: NetworkOptions, serialPortOptions: SerialPortOptions, backupPath: string, adapterOptions: AdapterOptions) {
@@ -54,7 +44,7 @@ export class DeconzAdapter extends Adapter {
54
44
  this.hasZdoMessageOverhead = true;
55
45
  this.manufacturerID = Zcl.ManufacturerCode.DRESDEN_ELEKTRONIK_INGENIEURTECHNIK_GMBH;
56
46
 
57
- this.waitress = new Waitress<Events.ZclPayload, WaitressMatcher>(this.waitressValidator, this.waitressTimeoutFormatter);
47
+ this.waitress = new Waitress(Adapter.zclWaitressValidator, Adapter.clusterWaitressTimeoutFormatter);
58
48
 
59
49
  const firmwareLog = [];
60
50
  if (backupPath) {
@@ -205,24 +195,17 @@ export class DeconzAdapter extends Adapter {
205
195
  }
206
196
 
207
197
  public waitFor(
208
- networkAddress: number | undefined,
198
+ networkAddress: number,
209
199
  endpoint: number,
210
- frameType: Zcl.FrameType,
211
- direction: Zcl.Direction,
200
+ _frameType: Zcl.FrameType,
201
+ _direction: Zcl.Direction,
212
202
  transactionSequenceNumber: number | undefined,
213
- clusterID: number,
214
- commandIdentifier: number,
203
+ clusterId: number,
204
+ commandId: number,
205
+ defaultRspCommandId: number | undefined,
215
206
  timeout: number,
216
207
  ): {promise: Promise<Events.ZclPayload>; cancel: () => void} {
217
- const payload = {
218
- address: networkAddress,
219
- endpoint,
220
- clusterID,
221
- commandIdentifier,
222
- frameType,
223
- direction,
224
- transactionSequenceNumber,
225
- };
208
+ const payload = {address: networkAddress, endpoint, clusterId, commandId, defaultRspCommandId, transactionSequenceNumber};
226
209
 
227
210
  logger.debug(() => `waitFor() called ${JSON.stringify(payload)}`, NS);
228
211
 
@@ -370,7 +353,12 @@ export class DeconzAdapter extends Adapter {
370
353
  // 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.
371
354
  //const txOptions = 0x4; // 0x00 normal, 0x04 APS ACK
372
355
  // TODO(mpi): Disable APS ACKs for now until we find a better solution to not block queues.
373
- const txOptions = 0;
356
+ let txOptions = 0x00;
357
+
358
+ // Zigbee Direct cluster, enable APS layer encryption
359
+ if (zclFrame.cluster.ID === Zcl.Clusters.zigbeeDirectConfiguration.ID) {
360
+ txOptions |= 0x01;
361
+ }
374
362
 
375
363
  const request: ApsDataRequest = {
376
364
  requestId: transactionID,
@@ -713,7 +701,10 @@ export class DeconzAdapter extends Adapter {
713
701
  destinationEndpoint: ZSpec.GP_ENDPOINT,
714
702
  };
715
703
 
716
- this.waitress.resolve(payload);
704
+ if (payload.header !== undefined) {
705
+ this.waitress.resolve(payload as ZclWaitressPayload);
706
+ }
707
+
717
708
  this.emit("zclPayload", payload);
718
709
  }
719
710
 
@@ -856,7 +847,10 @@ export class DeconzAdapter extends Adapter {
856
847
  destinationEndpoint: resp.destEndpoint,
857
848
  };
858
849
 
859
- this.waitress.resolve(payload);
850
+ if (payload.header !== undefined) {
851
+ this.waitress.resolve(payload as ZclWaitressPayload);
852
+ }
853
+
860
854
  this.emit("zclPayload", payload);
861
855
  }
862
856
  }
@@ -864,25 +858,4 @@ export class DeconzAdapter extends Adapter {
864
858
  private nextTransactionID(): number {
865
859
  return this.driver.nextTransactionID();
866
860
  }
867
-
868
- private waitressTimeoutFormatter(matcher: WaitressMatcher, timeout: number): string {
869
- return (
870
- `Timeout - ${matcher.address} - ${matcher.endpoint}` +
871
- ` - ${matcher.transactionSequenceNumber} - ${matcher.clusterID}` +
872
- ` - ${matcher.commandIdentifier} after ${timeout}ms`
873
- );
874
- }
875
-
876
- private waitressValidator(payload: Events.ZclPayload, matcher: WaitressMatcher): boolean {
877
- return Boolean(
878
- payload.header &&
879
- (!matcher.address || payload.address === matcher.address) &&
880
- payload.endpoint === matcher.endpoint &&
881
- (matcher.transactionSequenceNumber === undefined || payload.header.transactionSequenceNumber === matcher.transactionSequenceNumber) &&
882
- payload.clusterID === matcher.clusterID &&
883
- matcher.frameType === payload.header.frameControl.frameType &&
884
- matcher.commandIdentifier === payload.header.commandIdentifier &&
885
- matcher.direction === payload.header.frameControl.direction,
886
- );
887
- }
888
861
  }
@@ -241,6 +241,6 @@ interface ApsDataRequest {
241
241
 
242
242
  type Command = Buffer | number | bigint;
243
243
 
244
- export type {ApsRequest, Request, WaitForDataRequest, ApsDataRequest, ReceivedDataResponse, DataStateResponse, Command, GpDataInd};
244
+ export type {ApsDataRequest, ApsRequest, Command, DataStateResponse, GpDataInd, ReceivedDataResponse, Request, WaitForDataRequest};
245
245
 
246
246
  export default {PARAM};
@@ -957,16 +957,22 @@ export class EmberAdapter extends Adapter {
957
957
  logger.info("[INIT TC] Forming from backup.", NS);
958
958
  // `backup` valid in this `action` path (not detected by TS)
959
959
  /* v8 ignore start */
960
+ const keyList: LinkKeyBackupData[] = [];
961
+
960
962
  // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
961
- const keyList: LinkKeyBackupData[] = backup!.devices.map((device) => ({
962
- deviceEui64: ZSpec.Utils.eui64BEBufferToHex(device.ieeeAddress),
963
- // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
964
- key: {contents: device.linkKey!.key},
965
- // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
966
- outgoingFrameCounter: device.linkKey!.txCounter,
967
- // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
968
- incomingFrameCounter: device.linkKey!.rxCounter,
969
- }));
963
+ for (const device of backup!.devices) {
964
+ // link_key is optional in the open coordinator backup format, skip devices without one
965
+ if (device.linkKey == null) {
966
+ continue;
967
+ }
968
+
969
+ keyList.push({
970
+ deviceEui64: ZSpec.Utils.eui64BEBufferToHex(device.ieeeAddress),
971
+ key: {contents: device.linkKey.key},
972
+ outgoingFrameCounter: device.linkKey.txCounter,
973
+ incomingFrameCounter: device.linkKey.rxCounter,
974
+ });
975
+ }
970
976
  /* v8 ignore stop */
971
977
 
972
978
  // before forming
@@ -1705,13 +1711,14 @@ export class EmberAdapter extends Adapter {
1705
1711
 
1706
1712
  /** WARNING: Adapter impl. Starts timer immediately upon returning */
1707
1713
  public waitFor(
1708
- networkAddress: number | undefined,
1714
+ networkAddress: number,
1709
1715
  endpoint: number,
1710
1716
  _frameType: Zcl.FrameType,
1711
1717
  _direction: Zcl.Direction,
1712
1718
  transactionSequenceNumber: number | undefined,
1713
1719
  clusterID: number,
1714
1720
  commandIdentifier: number,
1721
+ defaultRspCommandId: number | undefined,
1715
1722
  timeout: number,
1716
1723
  ): {promise: Promise<ZclPayload>; cancel: () => void} {
1717
1724
  const sourceEndpointInfo = FIXED_ENDPOINTS[0];
@@ -1729,6 +1736,7 @@ export class EmberAdapter extends Adapter {
1729
1736
  },
1730
1737
  zclSequence: transactionSequenceNumber,
1731
1738
  commandIdentifier,
1739
+ defaultRspCommandId,
1732
1740
  },
1733
1741
  timeout,
1734
1742
  );
@@ -1958,6 +1966,11 @@ export class EmberAdapter extends Adapter {
1958
1966
  apsFrame.options &= ~EmberApsOption.RETRY;
1959
1967
  }
1960
1968
 
1969
+ // Zigbee Direct cluster, enable APS layer encryption
1970
+ if (zclFrame.cluster.ID === Zcl.Clusters.zigbeeDirectConfiguration.ID) {
1971
+ apsFrame.options |= EmberApsOption.ENCRYPTION;
1972
+ }
1973
+
1961
1974
  const data = zclFrame.toBuffer();
1962
1975
 
1963
1976
  return await this.queue.execute<ZclPayload | undefined>(async () => {
@@ -1,9 +1,9 @@
1
1
  /* v8 ignore start */
2
2
 
3
3
  import equals from "fast-deep-equal/es6";
4
-
5
4
  import {TOUCHLINK_PROFILE_ID} from "../../../zspec/consts";
6
5
  import type {Eui64, NodeId} from "../../../zspec/tstypes";
6
+ import {FrameType} from "../../../zspec/zcl";
7
7
  import type {ZclPayload} from "../../events";
8
8
  import type {EmberApsFrame} from "../types";
9
9
 
@@ -29,6 +29,8 @@ type OneWaitressMatcher = {
29
29
  zclSequence?: number;
30
30
  /** Expected command ID for ZCL commands */
31
31
  commandIdentifier?: number;
32
+ /** Expected default response command ID for ZCL commands */
33
+ defaultRspCommandId?: number;
32
34
  };
33
35
 
34
36
  type OneWaitressEventMatcher = {
@@ -154,13 +156,21 @@ export class EmberOneWaitress {
154
156
  continue;
155
157
  }
156
158
 
159
+ const {matcher} = waiter;
160
+ const {address, endpoint, clusterID, header} = payload;
161
+
157
162
  // no target in touchlink, also no APS sequence, but use the ZCL one instead
158
163
  if (
159
- (waiter.matcher.apsFrame.profileId === TOUCHLINK_PROFILE_ID ||
160
- (payload.address === waiter.matcher.target && payload.endpoint === waiter.matcher.apsFrame.destinationEndpoint)) &&
161
- (waiter.matcher.zclSequence === undefined || payload.header.transactionSequenceNumber === waiter.matcher.zclSequence) &&
162
- (waiter.matcher.commandIdentifier === undefined || payload.header.commandIdentifier === waiter.matcher.commandIdentifier) &&
163
- payload.clusterID === waiter.matcher.apsFrame.clusterId
164
+ (matcher.apsFrame.profileId === TOUCHLINK_PROFILE_ID ||
165
+ (address === matcher.target && endpoint === matcher.apsFrame.destinationEndpoint)) &&
166
+ clusterID === matcher.apsFrame.clusterId &&
167
+ (matcher.zclSequence === undefined || header.transactionSequenceNumber === matcher.zclSequence) &&
168
+ (matcher.commandIdentifier === undefined ||
169
+ header.commandIdentifier === matcher.commandIdentifier ||
170
+ // defaultRsp
171
+ (header.frameControl.frameType === FrameType.GLOBAL &&
172
+ header.commandIdentifier === 0x0b &&
173
+ (matcher.defaultRspCommandId === undefined || payload.data[payload.data.byteLength - 2] === matcher.defaultRspCommandId)))
164
174
  ) {
165
175
  clearTimeout(waiter.timer);
166
176
 
@@ -1,7 +1,6 @@
1
1
  /* v8 ignore start */
2
2
 
3
3
  import assert from "node:assert";
4
-
5
4
  import type * as Models from "../../../models";
6
5
  import {Queue, Waitress, wait} from "../../../utils";
7
6
  import {logger} from "../../../utils/logger";
@@ -9,7 +8,7 @@ import * as ZSpec from "../../../zspec";
9
8
  import * as Zcl from "../../../zspec/zcl";
10
9
  import * as Zdo from "../../../zspec/zdo";
11
10
  import type * as ZdoTypes from "../../../zspec/zdo/definition/tstypes";
12
- import Adapter from "../../adapter";
11
+ import Adapter, {type ClusterWaitressMatcher, type ZclWaitressPayload} from "../../adapter";
13
12
  import type {ZclPayload} from "../../events";
14
13
  import type {AdapterOptions, CoordinatorVersion, NetworkOptions, NetworkParameters, SerialPortOptions, StartResult} from "../../tstype";
15
14
  import {Driver, type EmberIncomingMessage} from "../driver";
@@ -17,17 +16,9 @@ import {EmberEUI64, EmberStatus} from "../driver/types";
17
16
 
18
17
  const NS = "zh:ezsp";
19
18
 
20
- interface WaitressMatcher {
21
- address?: number | string;
22
- endpoint: number;
23
- transactionSequenceNumber?: number;
24
- clusterID: number;
25
- commandIdentifier: number;
26
- }
27
-
28
19
  export class EZSPAdapter extends Adapter {
29
20
  private driver: Driver;
30
- private waitress: Waitress<ZclPayload, WaitressMatcher>;
21
+ private waitress: Waitress<ZclWaitressPayload, ClusterWaitressMatcher>;
31
22
  private interpanLock: boolean;
32
23
  private queue: Queue;
33
24
  private closing: boolean;
@@ -37,7 +28,7 @@ export class EZSPAdapter extends Adapter {
37
28
  this.hasZdoMessageOverhead = true;
38
29
  this.manufacturerID = Zcl.ManufacturerCode.SILICON_LABORATORIES;
39
30
 
40
- this.waitress = new Waitress<ZclPayload, WaitressMatcher>(this.waitressValidator, this.waitressTimeoutFormatter);
31
+ this.waitress = new Waitress(Adapter.zclWaitressValidator, Adapter.clusterWaitressTimeoutFormatter);
41
32
  this.interpanLock = false;
42
33
  this.closing = false;
43
34
 
@@ -78,7 +69,10 @@ export class EZSPAdapter extends Adapter {
78
69
  destinationEndpoint: frame.apsFrame.destinationEndpoint,
79
70
  };
80
71
 
81
- this.waitress.resolve(payload);
72
+ if (payload.header !== undefined) {
73
+ this.waitress.resolve(payload as ZclWaitressPayload);
74
+ }
75
+
82
76
  this.emit("zclPayload", payload);
83
77
  } else if (frame.apsFrame.profileId === ZSpec.TOUCHLINK_PROFILE_ID && frame.senderEui64) {
84
78
  // ZLL Frame
@@ -94,7 +88,10 @@ export class EZSPAdapter extends Adapter {
94
88
  destinationEndpoint: 1,
95
89
  };
96
90
 
97
- this.waitress.resolve(payload);
91
+ if (payload.header !== undefined) {
92
+ this.waitress.resolve(payload as ZclWaitressPayload);
93
+ }
94
+
98
95
  this.emit("zclPayload", payload);
99
96
  } else if (frame.apsFrame.profileId === ZSpec.GP_PROFILE_ID) {
100
97
  // GP Frame
@@ -114,7 +111,10 @@ export class EZSPAdapter extends Adapter {
114
111
  destinationEndpoint: frame.apsFrame.sourceEndpoint,
115
112
  };
116
113
 
117
- this.waitress.resolve(payload);
114
+ if (payload.header !== undefined) {
115
+ this.waitress.resolve(payload as ZclWaitressPayload);
116
+ }
117
+
118
118
  this.emit("zclPayload", payload);
119
119
  } else {
120
120
  logger.debug("Ignoring GP frame because clusterId is not greenPower", NS);
@@ -373,6 +373,7 @@ export class EZSPAdapter extends Adapter {
373
373
  zclFrame.header.transactionSequenceNumber,
374
374
  zclFrame.cluster.ID,
375
375
  command.response,
376
+ undefined,
376
377
  timeout,
377
378
  );
378
379
  } else if (!zclFrame.header.frameControl.disableDefaultResponse) {
@@ -382,6 +383,7 @@ export class EZSPAdapter extends Adapter {
382
383
  zclFrame.header.transactionSequenceNumber,
383
384
  zclFrame.cluster.ID,
384
385
  Zcl.Foundation.defaultRsp.ID,
386
+ undefined,
385
387
  timeout,
386
388
  );
387
389
  }
@@ -540,7 +542,7 @@ export class EZSPAdapter extends Adapter {
540
542
  let response: ReturnType<typeof this.waitForInternal> | undefined;
541
543
 
542
544
  if (!disableResponse && command.response !== undefined) {
543
- this.waitForInternal(undefined, 0xfe, undefined, zclFrame.cluster.ID, command.response, timeout);
545
+ this.waitForInternal(undefined, 0xfe, undefined, zclFrame.cluster.ID, command.response, undefined, timeout);
544
546
  }
545
547
 
546
548
  try {
@@ -578,18 +580,13 @@ export class EZSPAdapter extends Adapter {
578
580
  networkAddress: number | undefined,
579
581
  endpoint: number,
580
582
  transactionSequenceNumber: number | undefined,
581
- clusterID: number,
582
- commandIdentifier: number,
583
+ clusterId: number,
584
+ commandId: number,
585
+ defaultRspCommandId: number | undefined,
583
586
  timeout: number,
584
587
  ): {start: () => {promise: Promise<ZclPayload>}; cancel: () => void} {
585
588
  const waiter = this.waitress.waitFor(
586
- {
587
- address: networkAddress,
588
- endpoint,
589
- clusterID,
590
- commandIdentifier,
591
- transactionSequenceNumber,
592
- },
589
+ {address: networkAddress, endpoint, clusterId, commandId, defaultRspCommandId, transactionSequenceNumber},
593
590
  timeout,
594
591
  );
595
592
  const cancel = (): void => this.waitress.remove(waiter.ID);
@@ -597,36 +594,18 @@ export class EZSPAdapter extends Adapter {
597
594
  }
598
595
 
599
596
  public waitFor(
600
- networkAddress: number | undefined,
597
+ networkAddress: number,
601
598
  endpoint: number,
602
599
  _frameType: Zcl.FrameType,
603
600
  _direction: Zcl.Direction,
604
601
  transactionSequenceNumber: number | undefined,
605
- clusterID: number,
606
- commandIdentifier: number,
602
+ clusterId: number,
603
+ commandId: number,
604
+ defaultRspCommandId: number | undefined,
607
605
  timeout: number,
608
606
  ): {promise: Promise<ZclPayload>; cancel: () => void} {
609
- const waiter = this.waitForInternal(networkAddress, endpoint, transactionSequenceNumber, clusterID, commandIdentifier, timeout);
607
+ const waiter = this.waitForInternal(networkAddress, endpoint, transactionSequenceNumber, clusterId, commandId, defaultRspCommandId, timeout);
610
608
 
611
609
  return {cancel: waiter.cancel, promise: waiter.start().promise};
612
610
  }
613
-
614
- private waitressTimeoutFormatter(matcher: WaitressMatcher, timeout: number): string {
615
- return (
616
- `Timeout - ${matcher.address} - ${matcher.endpoint}` +
617
- ` - ${matcher.transactionSequenceNumber} - ${matcher.clusterID}` +
618
- ` - ${matcher.commandIdentifier} after ${timeout}ms`
619
- );
620
- }
621
-
622
- private waitressValidator(payload: ZclPayload, matcher: WaitressMatcher): boolean {
623
- return Boolean(
624
- payload.header &&
625
- (!matcher.address || payload.address === matcher.address) &&
626
- payload.endpoint === matcher.endpoint &&
627
- (matcher.transactionSequenceNumber === undefined || payload.header.transactionSequenceNumber === matcher.transactionSequenceNumber) &&
628
- payload.clusterID === matcher.clusterID &&
629
- matcher.commandIdentifier === payload.header.commandIdentifier,
630
- );
631
- }
632
611
  }
@@ -1,4 +1,4 @@
1
1
  import {Driver, EmberIncomingMessage} from "./driver";
2
2
  import {Ezsp} from "./ezsp";
3
3
 
4
- export {Ezsp, Driver, EmberIncomingMessage};
4
+ export {Driver, EmberIncomingMessage, Ezsp};
@@ -121,119 +121,119 @@ export function serialize(data: any[], schema: {serialize: (schema: any, item: a
121
121
  }
122
122
 
123
123
  export {
124
- /* Basic Types */
125
- int8s,
126
- uint_t,
127
- uint8_t,
128
- uint16_t,
129
- uint24_t,
130
- uint32_t,
131
- uint64_t,
132
- LVBytes,
133
- list,
134
- LVList,
135
- fixed_list,
136
- WordList,
137
- Bytes,
138
- /* Named Types */
139
- NcpResetCode,
140
- EmberRf4ceTxOption,
141
- EmberRf4ceNodeCapabilities,
142
- EmberRf4ceApplicationCapabilities,
143
- EmberNodeId,
144
- EmberPanId,
145
- EmberMulticastId,
146
- EmberEUI64,
147
- EmberLibraryStatus,
148
- SecureEzspSecurityType,
149
- SecureEzspSecurityLevel,
150
- EmberGpSecurityLevel,
151
- EmberGpKeyType,
152
- SecureEzspRandomNumber,
153
- SecureEzspSessionId,
154
124
  Bool,
155
- EzspConfigId,
156
- EzspValueId,
157
- EzspExtendedValueId,
158
- EzspEndpointFlags,
125
+ Bytes,
126
+ EmberAesMmoHashContext,
127
+ EmberApsFrame,
128
+ EmberApsOption,
129
+ EmberBindingTableEntry,
130
+ EmberBindingType,
131
+ EmberCertificate283k1Data,
132
+ EmberCertificateData,
133
+ EmberConcentratorType,
159
134
  EmberConfigTxPowerMode,
160
- EzspPolicyId,
161
- EzspDecisionId,
162
- EzspMfgTokenId,
163
- EzspStatus,
164
- EmberStatus,
165
- SLStatus,
166
- EmberStackError,
135
+ EmberCounterType,
136
+ EmberCurrentSecurityBitmask,
137
+ EmberCurrentSecurityState,
138
+ EmberDerivedKeyType,
139
+ EmberDeviceUpdate,
140
+ EmberEUI64,
167
141
  EmberEventUnits,
168
- EmberNodeType,
169
- EmberNetworkStatus,
142
+ EmberGpAddress,
143
+ EmberGpKeyType,
144
+ EmberGpSecurityLevel,
145
+ EmberGpSinkListEntry,
170
146
  EmberIncomingMessageType,
171
- EmberOutgoingMessageType,
172
- EmberMacPassthroughType,
173
- EmberBindingType,
174
- EmberApsOption,
175
- EzspNetworkScanType,
176
- EmberJoinDecision,
177
147
  EmberInitialSecurityBitmask,
178
- EmberCurrentSecurityBitmask,
179
- EmberKeyType,
180
- EmberKeyStructBitmask,
181
- EmberDeviceUpdate,
182
- EmberKeyStatus,
183
- EmberCounterType,
148
+ EmberInitialSecurityState,
149
+ EmberJoinDecision,
184
150
  EmberJoinMethod,
185
- EmberZdoConfigurationFlags,
186
- EmberConcentratorType,
187
- EmberZllState,
188
- EmberZllKeyIndex,
189
- EzspZllNetworkOperation,
190
- EzspSourceRouteOverheadInformation,
191
- EmberNetworkInitBitmask,
192
- EmberZDOCmd,
193
- EmberDerivedKeyType,
194
- /* Structs */
195
- EzspStruct,
196
- EmberNetworkParameters,
197
- EmberZigbeeNetwork,
198
- EmberApsFrame,
199
- EmberBindingTableEntry,
200
- EmberMulticastTableEntry,
201
151
  EmberKeyData,
202
- EmberCertificateData,
203
- EmberPublicKeyData,
204
- EmberPrivateKeyData,
205
- EmberSmacData,
206
- EmberSignatureData,
207
- EmberCertificate283k1Data,
208
- EmberPublicKey283k1Data,
209
- EmberPrivateKey283k1Data,
210
- EmberSignature283k1Data,
152
+ EmberKeyStatus,
153
+ EmberKeyStruct,
154
+ EmberKeyStructBitmask,
155
+ EmberKeyType,
156
+ EmberLibraryStatus,
157
+ EmberMacPassthroughType,
211
158
  EmberMessageDigest,
212
- EmberAesMmoHashContext,
159
+ EmberMultiAddress,
160
+ EmberMulticastId,
161
+ EmberMulticastTableEntry,
162
+ EmberNeighbors,
213
163
  EmberNeighborTableEntry,
214
- EmberRouteTableEntry,
215
- EmberInitialSecurityState,
216
- EmberCurrentSecurityState,
217
- EmberKeyStruct,
164
+ EmberNetworkInitBitmask,
218
165
  EmberNetworkInitStruct,
219
- EmberZllSecurityAlgorithmData,
220
- EmberZllNetwork,
221
- EmberZllInitialSecurityState,
222
- EmberZllDeviceInfoRecord,
223
- EmberZllAddressAssignment,
224
- EmberTokTypeStackZllData,
225
- EmberTokTypeStackZllSecurity,
226
- EmberRf4ceVendorInfo,
166
+ EmberNetworkParameters,
167
+ EmberNetworkStatus,
168
+ EmberNodeDescriptor,
169
+ EmberNodeId,
170
+ EmberNodeType,
171
+ EmberOutgoingMessageType,
172
+ EmberPanId,
173
+ EmberPrivateKey283k1Data,
174
+ EmberPrivateKeyData,
175
+ EmberPublicKey283k1Data,
176
+ EmberPublicKeyData,
177
+ EmberRf4ceApplicationCapabilities,
227
178
  EmberRf4ceApplicationInfo,
179
+ EmberRf4ceNodeCapabilities,
228
180
  EmberRf4cePairingTableEntry,
229
- EmberGpAddress,
230
- EmberGpSinkListEntry,
231
- EmberNodeDescriptor,
232
- EmberSimpleDescriptor,
233
- EmberMultiAddress,
234
- EmberNeighbors,
181
+ EmberRf4ceTxOption,
182
+ EmberRf4ceVendorInfo,
183
+ EmberRouteTableEntry,
235
184
  EmberRoutingTable,
236
185
  EmberRoutingTableEntry,
237
186
  EmberSecurityManagerContext,
238
187
  EmberSecurityManagerNetworkKeyInfo,
188
+ EmberSignature283k1Data,
189
+ EmberSignatureData,
190
+ EmberSimpleDescriptor,
191
+ EmberSmacData,
192
+ EmberStackError,
193
+ EmberStatus,
194
+ EmberTokTypeStackZllData,
195
+ EmberTokTypeStackZllSecurity,
196
+ EmberZDOCmd,
197
+ EmberZdoConfigurationFlags,
198
+ EmberZigbeeNetwork,
199
+ EmberZllAddressAssignment,
200
+ EmberZllDeviceInfoRecord,
201
+ EmberZllInitialSecurityState,
202
+ EmberZllKeyIndex,
203
+ EmberZllNetwork,
204
+ EmberZllSecurityAlgorithmData,
205
+ EmberZllState,
206
+ EzspConfigId,
207
+ EzspDecisionId,
208
+ EzspEndpointFlags,
209
+ EzspExtendedValueId,
210
+ EzspMfgTokenId,
211
+ EzspNetworkScanType,
212
+ EzspPolicyId,
213
+ EzspSourceRouteOverheadInformation,
214
+ EzspStatus,
215
+ /* Structs */
216
+ EzspStruct,
217
+ EzspValueId,
218
+ EzspZllNetworkOperation,
219
+ fixed_list,
220
+ /* Basic Types */
221
+ int8s,
222
+ LVBytes,
223
+ LVList,
224
+ list,
225
+ /* Named Types */
226
+ NcpResetCode,
227
+ SecureEzspRandomNumber,
228
+ SecureEzspSecurityLevel,
229
+ SecureEzspSecurityType,
230
+ SecureEzspSessionId,
231
+ SLStatus,
232
+ uint_t,
233
+ uint8_t,
234
+ uint16_t,
235
+ uint24_t,
236
+ uint32_t,
237
+ uint64_t,
238
+ WordList,
239
239
  };
@@ -1,5 +1,6 @@
1
1
  /* v8 ignore start */
2
2
 
3
+ import {platform} from "node:os";
3
4
  import {type AutoDetectTypes, autoDetect, type OpenOptionsFromBinding, type SetOptions} from "@serialport/bindings-cpp";
4
5
  // This file was copied from https://github.com/serialport/node-serialport/blob/master/packages/serialport/lib/serialport.ts.
5
6
  import {type ErrorCallback, type OpenOptions, SerialPortStream, type StreamOptions} from "@serialport/stream";
@@ -17,6 +18,14 @@ export class SerialPort<T extends AutoDetectTypes = AutoDetectTypes> extends Ser
17
18
  binding: DetectedBinding as T,
18
19
  ...options,
19
20
  };
21
+
22
+ if (platform() === "win32") {
23
+ // this controls `DTR` on "open", whereas on Unix, it's on "close"
24
+ // https://github.com/serialport/bindings-cpp/blob/19820c39fbbedc1b5f09d6508b5ef1268df3d455/src/serialport_win.cpp#L123-L127
25
+ // https://github.com/serialport/bindings-cpp/blob/19820c39fbbedc1b5f09d6508b5ef1268df3d455/src/serialport_unix.cpp#L254-L256
26
+ opts.hupcl = false;
27
+ }
28
+
20
29
  super(opts, openCallback);
21
30
  }
22
31