@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.
- package/.github/dependabot.yml +0 -3
- package/.github/workflows/ci.yml +1 -2
- package/.github/workflows/release-please.yml +1 -1
- package/.github/workflows/typedoc.yaml +3 -3
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +143 -0
- package/biome.json +1 -1
- package/dist/adapter/adapter.d.ts +14 -1
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js +17 -0
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
- package/dist/adapter/adapterDiscovery.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
- package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
- package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/index.js +1 -1
- package/dist/adapter/ezsp/driver/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.js +3 -3
- package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
- package/dist/adapter/serialPort.d.ts.map +1 -1
- package/dist/adapter/serialPort.js +7 -0
- package/dist/adapter/serialPort.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +12 -2
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
- package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/constants/index.js +1 -1
- package/dist/adapter/z-stack/constants/index.js.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.js +1 -1
- package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
- package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
- package/dist/adapter/zboss/driver.d.ts.map +1 -1
- package/dist/adapter/zboss/driver.js +8 -1
- package/dist/adapter/zboss/driver.js.map +1 -1
- package/dist/adapter/zboss/uart.d.ts.map +1 -1
- package/dist/adapter/zboss/uart.js +14 -2
- package/dist/adapter/zboss/uart.js.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
- package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
- package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +10 -2
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/greenPower.d.ts.map +1 -1
- package/dist/controller/greenPower.js +15 -9
- package/dist/controller/greenPower.js.map +1 -1
- package/dist/controller/helpers/ota.d.ts +4 -4
- package/dist/controller/helpers/ota.d.ts.map +1 -1
- package/dist/controller/helpers/ota.js +28 -9
- package/dist/controller/helpers/ota.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +17 -16
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts +14 -4
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +167 -85
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +7 -3
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +34 -21
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +0 -1
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +14 -19
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/touchlink.js +3 -3
- package/dist/controller/touchlink.js.map +1 -1
- package/dist/utils/timeService.js +2 -2
- package/dist/utils/timeService.js.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +198 -96
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +2699 -2808
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
- package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.d.ts +0 -1
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js +0 -1
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
- package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/foundation.js +552 -207
- package/dist/zspec/zcl/definition/foundation.js.map +1 -1
- package/dist/zspec/zcl/definition/status.d.ts +21 -10
- package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/status.js +11 -0
- package/dist/zspec/zcl/definition/status.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.d.ts +7 -4
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +133 -240
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts +4 -4
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +19 -103
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
- package/dist/zspec/zcl/zclStatusError.js +2 -2
- package/dist/zspec/zcl/zclStatusError.js.map +1 -1
- package/package.json +1 -1
- package/scripts/clusters-typegen.ts +44 -139
- package/src/adapter/adapter.ts +38 -3
- package/src/adapter/adapterDiscovery.ts +2 -1
- package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
- package/src/adapter/deconz/driver/constants.ts +1 -1
- package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
- package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
- package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
- package/src/adapter/ezsp/driver/index.ts +1 -1
- package/src/adapter/ezsp/driver/types/index.ts +99 -99
- package/src/adapter/serialPort.ts +9 -0
- package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
- package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
- package/src/adapter/z-stack/adapter/manager.ts +16 -2
- package/src/adapter/z-stack/adapter/tstype.ts +1 -0
- package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
- package/src/adapter/z-stack/constants/index.ts +1 -1
- package/src/adapter/z-stack/unpi/constants.ts +1 -1
- package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
- package/src/adapter/zboss/driver.ts +8 -1
- package/src/adapter/zboss/uart.ts +14 -1
- package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
- package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
- package/src/controller/controller.ts +12 -2
- package/src/controller/greenPower.ts +16 -9
- package/src/controller/helpers/ota.ts +37 -11
- package/src/controller/helpers/zclFrameConverter.ts +20 -17
- package/src/controller/model/device.ts +204 -97
- package/src/controller/model/endpoint.ts +36 -24
- package/src/controller/model/group.ts +14 -20
- package/src/controller/touchlink.ts +3 -3
- package/src/utils/timeService.ts +2 -2
- package/src/zspec/zcl/buffaloZcl.ts +226 -100
- package/src/zspec/zcl/definition/cluster.ts +2713 -2822
- package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
- package/src/zspec/zcl/definition/enums.ts +0 -1
- package/src/zspec/zcl/definition/foundation.ts +703 -216
- package/src/zspec/zcl/definition/status.ts +22 -11
- package/src/zspec/zcl/definition/tstype.ts +59 -58
- package/src/zspec/zcl/utils.ts +137 -264
- package/src/zspec/zcl/zclFrame.ts +25 -130
- package/src/zspec/zcl/zclStatusError.ts +2 -2
- package/test/adapter/ember/emberAdapter.test.ts +191 -4
- package/test/adapter/ezsp/uart.test.ts +10 -10
- package/test/adapter/z-stack/adapter.test.ts +88 -32
- package/test/adapter/zoh/zohAdapter.test.ts +4 -4
- package/test/controller.test.ts +822 -248
- package/test/device-ota.test.ts +141 -16
- package/test/device.test.ts +731 -0
- package/test/requests.bench.ts +2 -0
- package/test/zcl.test.ts +70 -95
- package/test/zspec/zcl/buffalo.test.ts +251 -11
- package/test/zspec/zcl/foundation.test.ts +990 -0
- package/test/zspec/zcl/frame.test.ts +84 -69
- package/test/zspec/zcl/utils.test.ts +105 -81
- package/tsconfig.json +0 -1
- package/scripts/check-clusters-changes.ts +0 -328
- package/scripts/clusters-changes.log +0 -584
- package/scripts/utils.ts +0 -88
- package/scripts/zap-update-clusters-report.json +0 -303
- package/scripts/zap-update-clusters.ts +0 -1520
- package/scripts/zap-update-types.ts +0 -707
- package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
- package/scripts/zap-xml-clusters-overrides.ts +0 -400
- package/scripts/zap-xml-types.ts +0 -146
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import "../../utils/patchBigIntSerialization";
|
|
2
3
|
|
|
3
4
|
import {BuffaloZcl} from "./buffaloZcl";
|
|
4
5
|
import type {TClusterPayload, TFoundationPayload} from "./definition/clusters-types";
|
|
5
|
-
import {BuffaloZclDataType, DataType, Direction, FrameType, ParameterCondition} from "./definition/enums";
|
|
6
|
-
import type {FoundationCommandName} from "./definition/foundation";
|
|
6
|
+
import {BuffaloZclDataType, type DataType, Direction, FrameType, ParameterCondition} from "./definition/enums";
|
|
7
|
+
import type {FoundationCommandName, FoundationDefinition} from "./definition/foundation";
|
|
8
|
+
import {Status} from "./definition/status";
|
|
7
9
|
import type {BuffaloZclOptions, Cluster, ClusterName, Command, CustomClusters, Parameter} from "./definition/tstype";
|
|
8
10
|
import * as Utils from "./utils";
|
|
9
11
|
import {ZclHeader} from "./zclHeader";
|
|
12
|
+
import {ZclStatusError} from "./zclStatusError";
|
|
10
13
|
|
|
11
14
|
// biome-ignore lint/suspicious/noExplicitAny: API
|
|
12
15
|
type ZclPayload = any;
|
|
13
16
|
|
|
14
|
-
const
|
|
17
|
+
const LIST_TYPES: readonly (DataType | BuffaloZclDataType)[] = [
|
|
15
18
|
BuffaloZclDataType.LIST_UINT8,
|
|
16
19
|
BuffaloZclDataType.LIST_UINT16,
|
|
17
20
|
BuffaloZclDataType.LIST_UINT24,
|
|
@@ -23,9 +26,9 @@ export class ZclFrame {
|
|
|
23
26
|
public readonly header: ZclHeader;
|
|
24
27
|
public readonly payload: ZclPayload;
|
|
25
28
|
public readonly cluster: Cluster;
|
|
26
|
-
public readonly command: Command;
|
|
29
|
+
public readonly command: Command | FoundationDefinition;
|
|
27
30
|
|
|
28
|
-
private constructor(header: ZclHeader, payload: ZclPayload, cluster: Cluster, command: Command) {
|
|
31
|
+
private constructor(header: ZclHeader, payload: ZclPayload, cluster: Cluster, command: Command | FoundationDefinition) {
|
|
29
32
|
this.header = header;
|
|
30
33
|
this.payload = payload;
|
|
31
34
|
this.cluster = cluster;
|
|
@@ -45,21 +48,21 @@ export class ZclFrame {
|
|
|
45
48
|
disableDefaultResponse: boolean,
|
|
46
49
|
manufacturerCode: number | undefined,
|
|
47
50
|
transactionSequenceNumber: number,
|
|
48
|
-
commandKey: number | string | Command,
|
|
51
|
+
commandKey: number | string | Command | FoundationDefinition,
|
|
49
52
|
clusterKey: number | string | Cluster,
|
|
50
53
|
payload: ZclPayload,
|
|
51
54
|
customClusters: CustomClusters,
|
|
52
55
|
reservedBits = 0,
|
|
53
56
|
): ZclFrame {
|
|
54
57
|
const cluster = typeof clusterKey === "object" ? clusterKey : Utils.getCluster(clusterKey, manufacturerCode, customClusters);
|
|
55
|
-
const command: Command =
|
|
58
|
+
const command: Command | FoundationDefinition =
|
|
56
59
|
typeof commandKey === "object"
|
|
57
60
|
? commandKey
|
|
58
61
|
: frameType === FrameType.GLOBAL
|
|
59
62
|
? Utils.getGlobalCommand(commandKey)
|
|
60
63
|
: direction === Direction.CLIENT_TO_SERVER
|
|
61
|
-
?
|
|
62
|
-
:
|
|
64
|
+
? Utils.getClusterCommand(cluster, commandKey)
|
|
65
|
+
: Utils.getClusterCommandResponse(cluster, commandKey);
|
|
63
66
|
|
|
64
67
|
const header = new ZclHeader(
|
|
65
68
|
{reservedBits, frameType, direction, disableDefaultResponse, manufacturerSpecific: manufacturerCode != null},
|
|
@@ -87,45 +90,14 @@ export class ZclFrame {
|
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
private writePayloadGlobal(buffalo: BuffaloZcl): void {
|
|
90
|
-
|
|
93
|
+
assert("write" in this.command);
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
for (const entry of this.payload) {
|
|
94
|
-
for (const parameter of command.parameters) {
|
|
95
|
-
const options: BuffaloZclOptions = {};
|
|
96
|
-
|
|
97
|
-
if (!ZclFrame.conditionsValid(parameter, entry, undefined)) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (parameter.type === BuffaloZclDataType.USE_DATA_TYPE && typeof entry.dataType === "number") {
|
|
102
|
-
// We need to grab the dataType to parse useDataType
|
|
103
|
-
options.dataType = entry.dataType;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
buffalo.write(parameter.type, entry[parameter.name], options);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
} else if (command.parseStrategy === "flat") {
|
|
110
|
-
for (const parameter of command.parameters) {
|
|
111
|
-
buffalo.write(parameter.type, this.payload[parameter.name], {});
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
if (command.parseStrategy === "oneof") {
|
|
115
|
-
if (Utils.isFoundationDiscoverRsp(command.ID)) {
|
|
116
|
-
buffalo.writeUInt8(this.payload.discComplete);
|
|
117
|
-
|
|
118
|
-
for (const entry of this.payload.attrInfos) {
|
|
119
|
-
for (const parameter of command.parameters) {
|
|
120
|
-
buffalo.write(parameter.type, entry[parameter.name], {});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
95
|
+
this.command.write(buffalo, this.payload);
|
|
126
96
|
}
|
|
127
97
|
|
|
128
98
|
private writePayloadCluster(buffalo: BuffaloZcl): void {
|
|
99
|
+
assert("parameters" in this.command);
|
|
100
|
+
|
|
129
101
|
for (const parameter of this.command.parameters) {
|
|
130
102
|
if (!ZclFrame.conditionsValid(parameter, this.payload, undefined)) {
|
|
131
103
|
continue;
|
|
@@ -159,11 +131,11 @@ export class ZclFrame {
|
|
|
159
131
|
|
|
160
132
|
const buffalo = new BuffaloZcl(buffer, header.length);
|
|
161
133
|
const cluster = Utils.getCluster(clusterID, header.manufacturerCode, customClusters);
|
|
162
|
-
const command: Command = header.isGlobal
|
|
134
|
+
const command: Command | FoundationDefinition = header.isGlobal
|
|
163
135
|
? Utils.getGlobalCommand(header.commandIdentifier)
|
|
164
136
|
: header.frameControl.direction === Direction.CLIENT_TO_SERVER
|
|
165
|
-
?
|
|
166
|
-
:
|
|
137
|
+
? Utils.getClusterCommand(cluster, header.commandIdentifier)
|
|
138
|
+
: Utils.getClusterCommandResponse(cluster, header.commandIdentifier);
|
|
167
139
|
const payload = ZclFrame.parsePayload(header, cluster, buffalo);
|
|
168
140
|
|
|
169
141
|
return new ZclFrame(header, payload, cluster, command);
|
|
@@ -184,8 +156,8 @@ export class ZclFrame {
|
|
|
184
156
|
private static parsePayloadCluster(header: ZclHeader, cluster: Cluster, buffalo: BuffaloZcl): ZclPayload {
|
|
185
157
|
const command =
|
|
186
158
|
header.frameControl.direction === Direction.CLIENT_TO_SERVER
|
|
187
|
-
?
|
|
188
|
-
:
|
|
159
|
+
? Utils.getClusterCommand(cluster, header.commandIdentifier)
|
|
160
|
+
: Utils.getClusterCommandResponse(cluster, header.commandIdentifier);
|
|
189
161
|
const payload: ZclPayload = {};
|
|
190
162
|
|
|
191
163
|
for (const parameter of command.parameters) {
|
|
@@ -195,7 +167,7 @@ export class ZclFrame {
|
|
|
195
167
|
continue;
|
|
196
168
|
}
|
|
197
169
|
|
|
198
|
-
if (
|
|
170
|
+
if (LIST_TYPES.includes(parameter.type)) {
|
|
199
171
|
const lengthParameter = command.parameters[command.parameters.indexOf(parameter) - 1];
|
|
200
172
|
const length = payload[lengthParameter.name];
|
|
201
173
|
|
|
@@ -208,7 +180,7 @@ export class ZclFrame {
|
|
|
208
180
|
const valueToProcess = buffalo.read(parameter.type, options);
|
|
209
181
|
payload[parameter.name] = Utils.processParameterRead(parameter, valueToProcess);
|
|
210
182
|
} catch (error) {
|
|
211
|
-
throw new
|
|
183
|
+
throw new ZclStatusError(Status.INVALID_FIELD, `${cluster.name}:${command.name}:${parameter.name} (${(error as Error).message})`);
|
|
212
184
|
}
|
|
213
185
|
}
|
|
214
186
|
|
|
@@ -218,78 +190,7 @@ export class ZclFrame {
|
|
|
218
190
|
private static parsePayloadGlobal(header: ZclHeader, buffalo: BuffaloZcl): ZclPayload {
|
|
219
191
|
const command = Utils.getFoundationCommand(header.commandIdentifier);
|
|
220
192
|
|
|
221
|
-
|
|
222
|
-
const payload = [];
|
|
223
|
-
|
|
224
|
-
while (buffalo.isMore()) {
|
|
225
|
-
// biome-ignore lint/suspicious/noExplicitAny: API
|
|
226
|
-
const entry: {[s: string]: any} = {};
|
|
227
|
-
|
|
228
|
-
for (const parameter of command.parameters) {
|
|
229
|
-
const options: BuffaloZclOptions = {};
|
|
230
|
-
|
|
231
|
-
if (!ZclFrame.conditionsValid(parameter, entry, buffalo.getBuffer().length - buffalo.getPosition())) {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (parameter.type === BuffaloZclDataType.USE_DATA_TYPE && typeof entry.dataType === "number") {
|
|
236
|
-
// We need to grab the dataType to parse useDataType
|
|
237
|
-
options.dataType = entry.dataType;
|
|
238
|
-
|
|
239
|
-
if (entry.dataType === DataType.CHAR_STR && entry.attrId === 65281) {
|
|
240
|
-
// [workaround] parse char str as Xiaomi struct
|
|
241
|
-
options.dataType = BuffaloZclDataType.MI_STRUCT;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
entry[parameter.name] = buffalo.read(parameter.type, options);
|
|
246
|
-
|
|
247
|
-
// TODO: not needed, but temp workaroudn to make payload equal to that of zcl-packet
|
|
248
|
-
// XXX: is this still needed?
|
|
249
|
-
if (parameter.type === BuffaloZclDataType.USE_DATA_TYPE && entry.dataType === DataType.STRUCT) {
|
|
250
|
-
entry.structElms = entry.attrData;
|
|
251
|
-
entry.numElms = entry.attrData.length;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
payload.push(entry);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return payload;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (command.parseStrategy === "flat") {
|
|
262
|
-
// biome-ignore lint/suspicious/noExplicitAny: API
|
|
263
|
-
const payload: {[s: string]: any} = {};
|
|
264
|
-
|
|
265
|
-
for (const parameter of command.parameters) {
|
|
266
|
-
payload[parameter.name] = buffalo.read(parameter.type, {});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return payload;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (command.parseStrategy === "oneof") {
|
|
273
|
-
if (Utils.isFoundationDiscoverRsp(command.ID)) {
|
|
274
|
-
// biome-ignore lint/suspicious/noExplicitAny: API
|
|
275
|
-
const payload: {discComplete: number; attrInfos: {[k: string]: any}[]} = {
|
|
276
|
-
discComplete: buffalo.readUInt8(),
|
|
277
|
-
attrInfos: [],
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
while (buffalo.isMore()) {
|
|
281
|
-
const entry: (typeof payload.attrInfos)[number] = {};
|
|
282
|
-
|
|
283
|
-
for (const parameter of command.parameters) {
|
|
284
|
-
entry[parameter.name] = buffalo.read(parameter.type, {});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
payload.attrInfos.push(entry);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return payload;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
193
|
+
return command.parse(buffalo);
|
|
293
194
|
}
|
|
294
195
|
|
|
295
196
|
/**
|
|
@@ -332,12 +233,6 @@ export class ZclFrame {
|
|
|
332
233
|
}
|
|
333
234
|
break;
|
|
334
235
|
}
|
|
335
|
-
case ParameterCondition.DATA_TYPE_CLASS_EQUAL: {
|
|
336
|
-
if (Utils.getDataTypeClass(entry.dataType) !== condition.value) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
341
236
|
case ParameterCondition.FIELD_GT: {
|
|
342
237
|
/*if (condition.reversed) {
|
|
343
238
|
if (entry[condition.field] >= condition.value) {
|
|
@@ -379,5 +274,5 @@ export interface TFoundationZclFrame<Co extends string> {
|
|
|
379
274
|
readonly header: ZclHeader;
|
|
380
275
|
readonly payload: TFoundationPayload<Co>;
|
|
381
276
|
readonly cluster: Cluster;
|
|
382
|
-
readonly command:
|
|
277
|
+
readonly command: FoundationDefinition;
|
|
383
278
|
}
|
|
@@ -3,8 +3,8 @@ import {Status} from "./definition/status";
|
|
|
3
3
|
export class ZclStatusError extends Error {
|
|
4
4
|
public code: Status;
|
|
5
5
|
|
|
6
|
-
constructor(code: Status) {
|
|
7
|
-
super(`Status '${Status[code]}'`);
|
|
6
|
+
constructor(code: Status, details?: string) {
|
|
7
|
+
super(`Status '${Status[code]}'${details ? ` ${details}` : ""}`);
|
|
8
8
|
this.code = code;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -2284,7 +2284,7 @@ describe("Ember Adapter Layer", () => {
|
|
|
2284
2284
|
});
|
|
2285
2285
|
|
|
2286
2286
|
it("Adapter impl: waitFor", () => {
|
|
2287
|
-
const waiter = adapter.waitFor(1234, 1, Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, 10, 0, 1, 15000);
|
|
2287
|
+
const waiter = adapter.waitFor(1234, 1, Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, 10, 0, 1, undefined, 15000);
|
|
2288
2288
|
const spyCancel = vi.spyOn(waiter, "cancel");
|
|
2289
2289
|
|
|
2290
2290
|
expect(typeof waiter.cancel).toStrictEqual("function");
|
|
@@ -2295,6 +2295,80 @@ describe("Ember Adapter Layer", () => {
|
|
|
2295
2295
|
expect(spyCancel).toHaveReturned();
|
|
2296
2296
|
});
|
|
2297
2297
|
|
|
2298
|
+
it("Adapter impl: waitFor resolves on cmd", async () => {
|
|
2299
|
+
const waiter = adapter.waitFor(1234, 1, Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, 10, 0, 1, undefined, 15000);
|
|
2300
|
+
const spyCancel = vi.spyOn(waiter, "cancel");
|
|
2301
|
+
|
|
2302
|
+
expect(typeof waiter.cancel).toStrictEqual("function");
|
|
2303
|
+
expect(waiter.promise).toBeDefined();
|
|
2304
|
+
|
|
2305
|
+
const messageContents = Zcl.Frame.create(
|
|
2306
|
+
Zcl.FrameType.GLOBAL,
|
|
2307
|
+
Zcl.Direction.SERVER_TO_CLIENT,
|
|
2308
|
+
true,
|
|
2309
|
+
undefined,
|
|
2310
|
+
10,
|
|
2311
|
+
"readRsp",
|
|
2312
|
+
"genBasic",
|
|
2313
|
+
[{attrId: 0, status: 0, dataType: Zcl.DataType.UINT8, attrData: 8}],
|
|
2314
|
+
{},
|
|
2315
|
+
).toBuffer();
|
|
2316
|
+
const expected = {
|
|
2317
|
+
clusterID: 0,
|
|
2318
|
+
header: Zcl.Header.fromBuffer(messageContents),
|
|
2319
|
+
address: 1234,
|
|
2320
|
+
data: messageContents,
|
|
2321
|
+
endpoint: 1,
|
|
2322
|
+
linkquality: 243,
|
|
2323
|
+
groupID: 0,
|
|
2324
|
+
wasBroadcast: false,
|
|
2325
|
+
destinationEndpoint: 1,
|
|
2326
|
+
};
|
|
2327
|
+
|
|
2328
|
+
// @ts-expect-error private
|
|
2329
|
+
adapter.oneWaitress.resolveZCL(expected);
|
|
2330
|
+
|
|
2331
|
+
await expect(waiter.promise).resolves.toStrictEqual(expected);
|
|
2332
|
+
expect(spyCancel).toHaveBeenCalledTimes(0);
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
it("Adapter impl: waitFor resolves on specified default response", async () => {
|
|
2336
|
+
const waiter = adapter.waitFor(1234, 1, Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, undefined, 0x0019, 3, 5, 15000);
|
|
2337
|
+
const spyCancel = vi.spyOn(waiter, "cancel");
|
|
2338
|
+
|
|
2339
|
+
expect(typeof waiter.cancel).toStrictEqual("function");
|
|
2340
|
+
expect(waiter.promise).toBeDefined();
|
|
2341
|
+
|
|
2342
|
+
const messageContents = Zcl.Frame.create(
|
|
2343
|
+
Zcl.FrameType.GLOBAL,
|
|
2344
|
+
Zcl.Direction.SERVER_TO_CLIENT,
|
|
2345
|
+
true,
|
|
2346
|
+
undefined,
|
|
2347
|
+
99,
|
|
2348
|
+
"defaultRsp",
|
|
2349
|
+
"genOta",
|
|
2350
|
+
{cmdId: 5, statusCode: Zcl.Status.MALFORMED_COMMAND},
|
|
2351
|
+
{},
|
|
2352
|
+
).toBuffer();
|
|
2353
|
+
const expected = {
|
|
2354
|
+
clusterID: 0x0019,
|
|
2355
|
+
header: Zcl.Header.fromBuffer(messageContents),
|
|
2356
|
+
address: 1234,
|
|
2357
|
+
data: messageContents,
|
|
2358
|
+
endpoint: 1,
|
|
2359
|
+
linkquality: 243,
|
|
2360
|
+
groupID: 0,
|
|
2361
|
+
wasBroadcast: false,
|
|
2362
|
+
destinationEndpoint: 1,
|
|
2363
|
+
};
|
|
2364
|
+
|
|
2365
|
+
// @ts-expect-error private
|
|
2366
|
+
adapter.oneWaitress.resolveZCL(expected);
|
|
2367
|
+
|
|
2368
|
+
await expect(waiter.promise).resolves.toStrictEqual(expected);
|
|
2369
|
+
expect(spyCancel).toHaveBeenCalledTimes(0);
|
|
2370
|
+
});
|
|
2371
|
+
|
|
2298
2372
|
it("Adapter impl: permitJoin on all", async () => {
|
|
2299
2373
|
const spyResolveEvent = vi.spyOn(
|
|
2300
2374
|
// @ts-expect-error private
|
|
@@ -3062,7 +3136,7 @@ describe("Ember Adapter Layer", () => {
|
|
|
3062
3136
|
]);
|
|
3063
3137
|
});
|
|
3064
3138
|
|
|
3065
|
-
it("Adapter impl: sendZclFrameToEndpoint with default response", async () => {
|
|
3139
|
+
it("Adapter impl: sendZclFrameToEndpoint with default response to global", async () => {
|
|
3066
3140
|
const networkAddress: NodeId = 1234;
|
|
3067
3141
|
const endpoint: number = 3;
|
|
3068
3142
|
const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
|
|
@@ -3087,8 +3161,17 @@ describe("Ember Adapter Layer", () => {
|
|
|
3087
3161
|
sequence: 0, // set by stack
|
|
3088
3162
|
};
|
|
3089
3163
|
const lastHopLqi: number = 234;
|
|
3090
|
-
|
|
3091
|
-
|
|
3164
|
+
const messageContents = Zcl.Frame.create(
|
|
3165
|
+
Zcl.FrameType.GLOBAL,
|
|
3166
|
+
Zcl.Direction.SERVER_TO_CLIENT,
|
|
3167
|
+
true,
|
|
3168
|
+
undefined,
|
|
3169
|
+
3,
|
|
3170
|
+
"defaultRsp",
|
|
3171
|
+
"genBasic",
|
|
3172
|
+
{cmdId: 0, statusCode: Zcl.Status.SUCCESS},
|
|
3173
|
+
{},
|
|
3174
|
+
).toBuffer();
|
|
3092
3175
|
|
|
3093
3176
|
mockEzspSend.mockImplementationOnce(() => {
|
|
3094
3177
|
setTimeout(async () => {
|
|
@@ -3123,6 +3206,76 @@ describe("Ember Adapter Layer", () => {
|
|
|
3123
3206
|
expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
|
|
3124
3207
|
});
|
|
3125
3208
|
|
|
3209
|
+
it("Adapter impl: sendZclFrameToEndpoint with default response to specific", async () => {
|
|
3210
|
+
const networkAddress: NodeId = 1234;
|
|
3211
|
+
const endpoint: number = 3;
|
|
3212
|
+
const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
|
|
3213
|
+
const zclFrame = Zcl.Frame.create(
|
|
3214
|
+
Zcl.FrameType.SPECIFIC,
|
|
3215
|
+
Zcl.Direction.CLIENT_TO_SERVER,
|
|
3216
|
+
false,
|
|
3217
|
+
undefined,
|
|
3218
|
+
3,
|
|
3219
|
+
"add",
|
|
3220
|
+
"genGroups",
|
|
3221
|
+
{groupid: 1, groupname: ""},
|
|
3222
|
+
{},
|
|
3223
|
+
);
|
|
3224
|
+
const apsFrame: EmberApsFrame = {
|
|
3225
|
+
profileId: FIXED_ENDPOINTS[0].profileId,
|
|
3226
|
+
clusterId: zclFrame.cluster.ID,
|
|
3227
|
+
sourceEndpoint,
|
|
3228
|
+
destinationEndpoint: endpoint,
|
|
3229
|
+
options: DEFAULT_APS_OPTIONS,
|
|
3230
|
+
groupId: 0,
|
|
3231
|
+
sequence: 0, // set by stack
|
|
3232
|
+
};
|
|
3233
|
+
const lastHopLqi: number = 234;
|
|
3234
|
+
const messageContents = Zcl.Frame.create(
|
|
3235
|
+
Zcl.FrameType.GLOBAL,
|
|
3236
|
+
Zcl.Direction.SERVER_TO_CLIENT,
|
|
3237
|
+
true,
|
|
3238
|
+
undefined,
|
|
3239
|
+
3,
|
|
3240
|
+
"defaultRsp",
|
|
3241
|
+
"genGroups",
|
|
3242
|
+
{cmdId: 0, statusCode: Zcl.Status.UNSUPPORTED_CLUSTER},
|
|
3243
|
+
{},
|
|
3244
|
+
).toBuffer();
|
|
3245
|
+
|
|
3246
|
+
mockEzspSend.mockImplementationOnce(() => {
|
|
3247
|
+
setTimeout(async () => {
|
|
3248
|
+
mockEzspEmitter.emit(
|
|
3249
|
+
"incomingMessage",
|
|
3250
|
+
EmberIncomingMessageType.UNICAST,
|
|
3251
|
+
reverseApsFrame(apsFrame),
|
|
3252
|
+
lastHopLqi,
|
|
3253
|
+
networkAddress,
|
|
3254
|
+
messageContents,
|
|
3255
|
+
);
|
|
3256
|
+
await flushPromises();
|
|
3257
|
+
}, 300);
|
|
3258
|
+
|
|
3259
|
+
return [SLStatus.OK, ++mockAPSSequence];
|
|
3260
|
+
});
|
|
3261
|
+
|
|
3262
|
+
const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, false, false, sourceEndpoint);
|
|
3263
|
+
|
|
3264
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
3265
|
+
await expect(p).resolves.toStrictEqual({
|
|
3266
|
+
clusterID: apsFrame.clusterId,
|
|
3267
|
+
header: Zcl.Header.fromBuffer(messageContents),
|
|
3268
|
+
address: networkAddress,
|
|
3269
|
+
data: messageContents,
|
|
3270
|
+
endpoint: apsFrame.destinationEndpoint,
|
|
3271
|
+
linkquality: lastHopLqi,
|
|
3272
|
+
groupID: apsFrame.groupId,
|
|
3273
|
+
wasBroadcast: false,
|
|
3274
|
+
destinationEndpoint: apsFrame.sourceEndpoint,
|
|
3275
|
+
} as ZclPayload);
|
|
3276
|
+
expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
|
|
3277
|
+
});
|
|
3278
|
+
|
|
3126
3279
|
it("Adapter impl: sendZclFrameToEndpoint without response", async () => {
|
|
3127
3280
|
const networkAddress: NodeId = 1234;
|
|
3128
3281
|
const endpoint: number = 3;
|
|
@@ -3157,6 +3310,40 @@ describe("Ember Adapter Layer", () => {
|
|
|
3157
3310
|
expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
|
|
3158
3311
|
});
|
|
3159
3312
|
|
|
3313
|
+
it("Adapter impl: sendZclFrameToEndpoint with encryption", async () => {
|
|
3314
|
+
const networkAddress: NodeId = 1234;
|
|
3315
|
+
const endpoint: number = 232;
|
|
3316
|
+
const sourceEndpoint = FIXED_ENDPOINTS[0].endpoint;
|
|
3317
|
+
const zclFrame = Zcl.Frame.create(
|
|
3318
|
+
Zcl.FrameType.GLOBAL,
|
|
3319
|
+
Zcl.Direction.CLIENT_TO_SERVER,
|
|
3320
|
+
true,
|
|
3321
|
+
undefined,
|
|
3322
|
+
3,
|
|
3323
|
+
"read",
|
|
3324
|
+
"zigbeeDirectConfiguration",
|
|
3325
|
+
[{attrId: 0}],
|
|
3326
|
+
{},
|
|
3327
|
+
);
|
|
3328
|
+
|
|
3329
|
+
const p = adapter.sendZclFrameToEndpoint("0x1122334455667788", networkAddress, endpoint, zclFrame, 10000, true, false, sourceEndpoint);
|
|
3330
|
+
|
|
3331
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
3332
|
+
await expect(p).resolves.toStrictEqual(undefined);
|
|
3333
|
+
|
|
3334
|
+
const apsFrame: EmberApsFrame = {
|
|
3335
|
+
profileId: FIXED_ENDPOINTS[0].profileId,
|
|
3336
|
+
clusterId: zclFrame.cluster.ID,
|
|
3337
|
+
sourceEndpoint,
|
|
3338
|
+
destinationEndpoint: endpoint,
|
|
3339
|
+
options: (DEFAULT_APS_OPTIONS & ~EmberApsOption.RETRY) | EmberApsOption.ENCRYPTION,
|
|
3340
|
+
groupId: 0,
|
|
3341
|
+
sequence: 0, // set by stack
|
|
3342
|
+
};
|
|
3343
|
+
|
|
3344
|
+
expect(mockEzspSend).toHaveBeenCalledWith(EmberOutgoingMessageType.DIRECT, networkAddress, apsFrame, zclFrame.toBuffer(), 0, 0);
|
|
3345
|
+
});
|
|
3346
|
+
|
|
3160
3347
|
it("Adapter impl: sendZclFrameToGroup with source endpoint", async () => {
|
|
3161
3348
|
const groupId: number = 32;
|
|
3162
3349
|
const zclFrame = Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 1, 1, 0, [{}], {});
|
|
@@ -110,18 +110,18 @@ describe("UART", () => {
|
|
|
110
110
|
it("Send data", async () => {
|
|
111
111
|
await serialDriver.connect("/dev/ttyACM0", {});
|
|
112
112
|
// send 8 frames
|
|
113
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
114
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
115
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
116
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
117
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
118
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
119
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
120
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
113
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
114
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
115
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
116
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
117
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
118
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
119
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
120
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
121
121
|
expect(writeBufferSpy).toHaveBeenCalledTimes(2);
|
|
122
122
|
// send another 2 frame - not counted, until resolve 8 promices
|
|
123
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
124
|
-
serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
123
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
124
|
+
void serialDriver.sendDATA(Buffer.from([1, 2, 3]));
|
|
125
125
|
expect(writeBufferSpy).toHaveBeenCalledTimes(2);
|
|
126
126
|
});
|
|
127
127
|
|