zigbee-herdsman 4.4.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +1 -0
- package/.github/workflows/ci.yml +20 -1
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +26 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +5 -6
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +2 -14
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +3 -13
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +42 -22
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +4 -0
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +69 -10
- package/dist/controller/model/group.js.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +5 -5
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +1 -2
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +19 -34
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/package.json +5 -3
- package/src/controller/controller.ts +5 -7
- package/src/controller/helpers/zclFrameConverter.ts +14 -14
- package/src/controller/model/device.ts +5 -15
- package/src/controller/model/endpoint.ts +51 -23
- package/src/controller/model/group.ts +83 -11
- package/src/zspec/zcl/buffaloZcl.ts +6 -4
- package/src/zspec/zcl/definition/tstype.ts +1 -2
- package/src/zspec/zcl/utils.ts +23 -43
- package/test/controller.bench.ts +193 -0
- package/test/controller.test.ts +554 -1294
- package/test/mockDevices.ts +127 -1
- package/test/requests.bench.ts +206 -0
- package/test/vitest.config.mts +2 -0
- package/test/zcl.test.ts +11 -15
- package/test/zspec/zcl/frame.test.ts +25 -25
- package/test/zspec/zcl/utils.test.ts +6 -14
package/test/mockDevices.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Zcl from "../src/zspec/zcl";
|
|
1
2
|
import * as Zdo from "../src/zspec/zdo";
|
|
2
3
|
import type * as ZdoTypes from "../src/zspec/zdo/definition/tstypes";
|
|
3
4
|
|
|
@@ -438,7 +439,10 @@ export const MOCK_DEVICES: {
|
|
|
438
439
|
},
|
|
439
440
|
},
|
|
440
441
|
177: {
|
|
441
|
-
nodeDescriptor: [
|
|
442
|
+
nodeDescriptor: [
|
|
443
|
+
Zdo.Status.SUCCESS,
|
|
444
|
+
{...NODE_DESC_DEFAULTS, nwkAddress: 177, logicalType: 0b001, manufacturerCode: Zcl.ManufacturerCode.LEGRAND_GROUP},
|
|
445
|
+
],
|
|
442
446
|
activeEndpoints: [Zdo.Status.SUCCESS, {nwkAddress: 177, endpointList: [1]}],
|
|
443
447
|
simpleDescriptor: {
|
|
444
448
|
1: [
|
|
@@ -469,4 +473,126 @@ export const MOCK_DEVICES: {
|
|
|
469
473
|
},
|
|
470
474
|
},
|
|
471
475
|
},
|
|
476
|
+
178: {
|
|
477
|
+
nodeDescriptor: [
|
|
478
|
+
Zdo.Status.SUCCESS,
|
|
479
|
+
{...NODE_DESC_DEFAULTS, nwkAddress: 178, logicalType: 0b001, manufacturerCode: Zcl.ManufacturerCode.LEGRAND_GROUP},
|
|
480
|
+
],
|
|
481
|
+
activeEndpoints: [Zdo.Status.SUCCESS, {nwkAddress: 178, endpointList: [1, 2]}],
|
|
482
|
+
simpleDescriptor: {
|
|
483
|
+
1: [
|
|
484
|
+
Zdo.Status.SUCCESS,
|
|
485
|
+
{
|
|
486
|
+
nwkAddress: 178,
|
|
487
|
+
length: 32,
|
|
488
|
+
endpoint: 1,
|
|
489
|
+
profileId: 260,
|
|
490
|
+
deviceId: 514,
|
|
491
|
+
deviceVersion: 1,
|
|
492
|
+
inClusterList: [0, 3, 258, 4, 5, 15, 64513],
|
|
493
|
+
outClusterList: [258, 0, 64513, 5, 25],
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
2: [
|
|
497
|
+
Zdo.Status.SUCCESS,
|
|
498
|
+
{
|
|
499
|
+
nwkAddress: 178,
|
|
500
|
+
length: 32,
|
|
501
|
+
endpoint: 2,
|
|
502
|
+
profileId: 260,
|
|
503
|
+
deviceId: 514,
|
|
504
|
+
deviceVersion: 1,
|
|
505
|
+
inClusterList: [0, 3, 258, 4, 5, 15],
|
|
506
|
+
outClusterList: [258, 0, 64513, 5, 25],
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
attributes: {
|
|
511
|
+
1: {
|
|
512
|
+
modelId: " some other multi-endpoint device",
|
|
513
|
+
manufacturerName: "Legrand",
|
|
514
|
+
zclVersion: 2,
|
|
515
|
+
appVersion: 0,
|
|
516
|
+
hwVersion: 8,
|
|
517
|
+
dateCode: "241030",
|
|
518
|
+
swBuildId: "0039",
|
|
519
|
+
powerSource: 1,
|
|
520
|
+
stackVersion: 67,
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
179: {
|
|
525
|
+
nodeDescriptor: [
|
|
526
|
+
Zdo.Status.SUCCESS,
|
|
527
|
+
{...NODE_DESC_DEFAULTS, nwkAddress: 179, logicalType: 0b001, manufacturerCode: Zcl.ManufacturerCode.V_MARK_ENTERPRISES_INC},
|
|
528
|
+
],
|
|
529
|
+
activeEndpoints: [Zdo.Status.SUCCESS, {nwkAddress: 179, endpointList: [1, 2, 3, 4]}],
|
|
530
|
+
simpleDescriptor: {
|
|
531
|
+
1: [
|
|
532
|
+
Zdo.Status.SUCCESS,
|
|
533
|
+
{
|
|
534
|
+
nwkAddress: 179,
|
|
535
|
+
length: 32,
|
|
536
|
+
endpoint: 1,
|
|
537
|
+
profileId: 260,
|
|
538
|
+
deviceId: 514,
|
|
539
|
+
deviceVersion: 1,
|
|
540
|
+
inClusterList: [0, 64561],
|
|
541
|
+
outClusterList: [64561],
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
2: [
|
|
545
|
+
Zdo.Status.SUCCESS,
|
|
546
|
+
{
|
|
547
|
+
nwkAddress: 179,
|
|
548
|
+
length: 32,
|
|
549
|
+
endpoint: 1,
|
|
550
|
+
profileId: 260,
|
|
551
|
+
deviceId: 514,
|
|
552
|
+
deviceVersion: 1,
|
|
553
|
+
inClusterList: [0, 64561],
|
|
554
|
+
outClusterList: [64561],
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
3: [
|
|
558
|
+
Zdo.Status.SUCCESS,
|
|
559
|
+
{
|
|
560
|
+
nwkAddress: 179,
|
|
561
|
+
length: 32,
|
|
562
|
+
endpoint: 1,
|
|
563
|
+
profileId: 260,
|
|
564
|
+
deviceId: 514,
|
|
565
|
+
deviceVersion: 1,
|
|
566
|
+
inClusterList: [0, 64561],
|
|
567
|
+
outClusterList: [64561],
|
|
568
|
+
},
|
|
569
|
+
],
|
|
570
|
+
4: [
|
|
571
|
+
Zdo.Status.SUCCESS,
|
|
572
|
+
{
|
|
573
|
+
nwkAddress: 179,
|
|
574
|
+
length: 32,
|
|
575
|
+
endpoint: 1,
|
|
576
|
+
profileId: 260,
|
|
577
|
+
deviceId: 514,
|
|
578
|
+
deviceVersion: 1,
|
|
579
|
+
inClusterList: [0, 64561],
|
|
580
|
+
outClusterList: [64561],
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
},
|
|
584
|
+
attributes: {
|
|
585
|
+
1: {
|
|
586
|
+
modelId: "VZM30-SN",
|
|
587
|
+
manufacturerName: "Inovelli",
|
|
588
|
+
zclVersion: 3,
|
|
589
|
+
appVersion: 0,
|
|
590
|
+
hwVersion: 8,
|
|
591
|
+
dateCode: "2025",
|
|
592
|
+
swBuildId: "0001",
|
|
593
|
+
powerSource: 1,
|
|
594
|
+
stackVersion: 67,
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
472
598
|
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import {bench, describe} from "vitest";
|
|
2
|
+
import type {Adapter} from "../src/adapter";
|
|
3
|
+
import type {ZclPayload} from "../src/adapter/events";
|
|
4
|
+
import Database from "../src/controller/database";
|
|
5
|
+
import {Device, Entity, Group} from "../src/controller/model";
|
|
6
|
+
import {InterviewState} from "../src/controller/model/device";
|
|
7
|
+
import {setLogger} from "../src/utils/logger";
|
|
8
|
+
import * as Zcl from "../src/zspec/zcl";
|
|
9
|
+
import * as Zdo from "../src/zspec/zdo";
|
|
10
|
+
import {uint16To8Array} from "./utils/math";
|
|
11
|
+
|
|
12
|
+
let sendZclFrameToEndpointResponse: ZclPayload | undefined;
|
|
13
|
+
let sendZdoResponse: unknown | undefined;
|
|
14
|
+
|
|
15
|
+
// no-op, makes up for too much of the perf loss (with console logging by default)
|
|
16
|
+
setLogger({
|
|
17
|
+
debug: () => {},
|
|
18
|
+
info: () => {},
|
|
19
|
+
warning: () => {},
|
|
20
|
+
error: () => {},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const database = Database.open("dummy");
|
|
24
|
+
// no-op
|
|
25
|
+
database.write = () => {};
|
|
26
|
+
|
|
27
|
+
const adapter = {
|
|
28
|
+
sendZclFrameToEndpoint: async () => Promise.resolve(sendZclFrameToEndpointResponse),
|
|
29
|
+
sendZclFrameToGroup: async () => Promise.resolve(),
|
|
30
|
+
sendZdo: async () => Promise.resolve(sendZdoResponse),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
Entity.injectDatabase(database);
|
|
34
|
+
Entity.injectAdapter(adapter as unknown as Adapter);
|
|
35
|
+
|
|
36
|
+
const device = Device.create(
|
|
37
|
+
"Router",
|
|
38
|
+
"0xfe34ac2385ff8311",
|
|
39
|
+
0x0001,
|
|
40
|
+
0x0102,
|
|
41
|
+
"Herdsman",
|
|
42
|
+
"Mains (single phase)",
|
|
43
|
+
"Herd-01",
|
|
44
|
+
InterviewState.Successful,
|
|
45
|
+
undefined,
|
|
46
|
+
);
|
|
47
|
+
const endpoint = device.createEndpoint(1);
|
|
48
|
+
const group = Group.create(1);
|
|
49
|
+
|
|
50
|
+
group.addMember(endpoint);
|
|
51
|
+
|
|
52
|
+
const IEEE_ADDRESS1 = "0xfe34ac2385ff8311";
|
|
53
|
+
const IEEE_ADDRESS1_BYTES = [0x11, 0x83, 0xff, 0x85, 0x23, 0xac, 0x34, 0xfe];
|
|
54
|
+
const IEEE_ADDRESS2 = "0x28373fecd834ba37";
|
|
55
|
+
const IEEE_ADDRESS2_BYTES = [0x37, 0xba, 0x34, 0xd8, 0xec, 0x3f, 0x37, 0x28];
|
|
56
|
+
const NODE_ID1 = 0xfe32;
|
|
57
|
+
const NODE_ID1_BYTES = uint16To8Array(NODE_ID1);
|
|
58
|
+
const NODE_ID2 = 0xab39;
|
|
59
|
+
const NODE_ID2_BYTES = uint16To8Array(NODE_ID2);
|
|
60
|
+
const EXT_PAN_ID1 = [3, 43, 56, 23, 65, 23, 67, 23];
|
|
61
|
+
const EXT_PAN_ID2 = [253, 231, 21, 3, 0, 44, 24, 46];
|
|
62
|
+
const LQI_TABLE_RESPONSE = Buffer.from([
|
|
63
|
+
1,
|
|
64
|
+
Zdo.Status.SUCCESS,
|
|
65
|
+
2,
|
|
66
|
+
3,
|
|
67
|
+
2,
|
|
68
|
+
...EXT_PAN_ID2,
|
|
69
|
+
...IEEE_ADDRESS1_BYTES,
|
|
70
|
+
...NODE_ID2_BYTES,
|
|
71
|
+
0b00100101,
|
|
72
|
+
0b00000001,
|
|
73
|
+
1,
|
|
74
|
+
235,
|
|
75
|
+
...EXT_PAN_ID1,
|
|
76
|
+
...IEEE_ADDRESS2_BYTES,
|
|
77
|
+
...NODE_ID1_BYTES,
|
|
78
|
+
0b01000010,
|
|
79
|
+
0b00000000,
|
|
80
|
+
1,
|
|
81
|
+
179,
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
const BASIC_RESP = Zcl.Frame.create(
|
|
85
|
+
0,
|
|
86
|
+
1,
|
|
87
|
+
true,
|
|
88
|
+
undefined,
|
|
89
|
+
10,
|
|
90
|
+
"readRsp",
|
|
91
|
+
0,
|
|
92
|
+
[
|
|
93
|
+
{
|
|
94
|
+
attrId: 5,
|
|
95
|
+
dataType: Zcl.DataType.CHAR_STR,
|
|
96
|
+
attrData: device.modelID,
|
|
97
|
+
status: 0,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
attrId: 4,
|
|
101
|
+
dataType: Zcl.DataType.CHAR_STR,
|
|
102
|
+
attrData: device.manufacturerName,
|
|
103
|
+
status: 0,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
{},
|
|
107
|
+
).toBuffer();
|
|
108
|
+
|
|
109
|
+
describe("Requests", () => {
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
sendZclFrameToEndpointResponse = undefined;
|
|
112
|
+
sendZdoResponse = undefined;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
bench(
|
|
116
|
+
"device lqi",
|
|
117
|
+
async () => {
|
|
118
|
+
sendZdoResponse = Zdo.Buffalo.readResponse(true, Zdo.ClusterId.LQI_TABLE_RESPONSE, LQI_TABLE_RESPONSE);
|
|
119
|
+
const resp = await device.lqi();
|
|
120
|
+
|
|
121
|
+
if (resp.neighbors[0].ieeeAddr !== IEEE_ADDRESS1 || resp.neighbors[1].ieeeAddr !== IEEE_ADDRESS2) {
|
|
122
|
+
throw new Error("Invalid response");
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{throws: true},
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
bench(
|
|
129
|
+
"device.endpoint write basic",
|
|
130
|
+
async () => {
|
|
131
|
+
await endpoint.write("genBasic", {modelId: "Herd-02", manufacturerName: "HerdsmanNew"}, {sendPolicy: "immediate"});
|
|
132
|
+
},
|
|
133
|
+
{throws: true},
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
bench(
|
|
137
|
+
"device.endpoint read basic",
|
|
138
|
+
async () => {
|
|
139
|
+
sendZclFrameToEndpointResponse = {
|
|
140
|
+
clusterID: Zcl.Clusters.genBasic.ID,
|
|
141
|
+
header: Zcl.Header.fromBuffer(BASIC_RESP),
|
|
142
|
+
address: 0x0001,
|
|
143
|
+
data: BASIC_RESP,
|
|
144
|
+
endpoint: 1,
|
|
145
|
+
linkquality: 200,
|
|
146
|
+
groupID: 0,
|
|
147
|
+
wasBroadcast: false,
|
|
148
|
+
destinationEndpoint: 1,
|
|
149
|
+
};
|
|
150
|
+
const resp = await endpoint.read("genBasic", ["modelId", "manufacturerName"], {sendPolicy: "immediate"});
|
|
151
|
+
|
|
152
|
+
if (resp.modelId !== device.modelID || resp.manufacturerName !== device.manufacturerName) {
|
|
153
|
+
throw new Error("Invalid response");
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
{throws: true},
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
bench(
|
|
160
|
+
"device.endpoint defaultRsp",
|
|
161
|
+
async () => {
|
|
162
|
+
await endpoint.defaultResponse(0, 0, 0, 1);
|
|
163
|
+
},
|
|
164
|
+
{throws: true},
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
bench(
|
|
168
|
+
"device.endpoint command",
|
|
169
|
+
async () => {
|
|
170
|
+
await endpoint.command("genOnOff", "offWithEffect", {effectid: 1, effectvariant: 2}, {sendPolicy: "immediate"});
|
|
171
|
+
},
|
|
172
|
+
{throws: true},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
bench(
|
|
176
|
+
"device.endpoint commandResponse",
|
|
177
|
+
async () => {
|
|
178
|
+
await endpoint.commandResponse("genAlarms", "alarm", {alarmcode: 123, clusterid: 456}, {sendPolicy: "immediate"});
|
|
179
|
+
},
|
|
180
|
+
{throws: true},
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
bench(
|
|
184
|
+
"group write basic",
|
|
185
|
+
async () => {
|
|
186
|
+
await group.write("genBasic", {modelId: "Herd-02", manufacturerName: "HerdsmanNew"});
|
|
187
|
+
},
|
|
188
|
+
{throws: true},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
bench(
|
|
192
|
+
"group read basic",
|
|
193
|
+
async () => {
|
|
194
|
+
await group.read("genBasic", ["modelId", "manufacturerName"]);
|
|
195
|
+
},
|
|
196
|
+
{throws: true},
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
bench(
|
|
200
|
+
"group command",
|
|
201
|
+
async () => {
|
|
202
|
+
await group.command("genRssiLocation", "getDevCfg", {targetaddr: IEEE_ADDRESS1}, {});
|
|
203
|
+
},
|
|
204
|
+
{throws: true},
|
|
205
|
+
);
|
|
206
|
+
});
|
package/test/vitest.config.mts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import codspeedPlugin from "@codspeed/vitest-plugin";
|
|
1
2
|
import {defineConfig} from "vitest/config";
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
plugins: [codspeedPlugin()],
|
|
4
6
|
test: {
|
|
5
7
|
globals: true,
|
|
6
8
|
onConsoleLog(_log: string, _type: "stdout" | "stderr"): boolean | undefined {
|
package/test/zcl.test.ts
CHANGED
|
@@ -20,8 +20,6 @@ describe("Zcl", () => {
|
|
|
20
20
|
// @ts-expect-error testing
|
|
21
21
|
delete cluster1.getCommand;
|
|
22
22
|
// @ts-expect-error testing
|
|
23
|
-
delete cluster1.hasAttribute;
|
|
24
|
-
// @ts-expect-error testing
|
|
25
23
|
delete cluster1.getCommandResponse;
|
|
26
24
|
const cluster2 = Zcl.Utils.getCluster("genBasic", undefined, {});
|
|
27
25
|
// @ts-expect-error testing
|
|
@@ -29,8 +27,6 @@ describe("Zcl", () => {
|
|
|
29
27
|
// @ts-expect-error testing
|
|
30
28
|
delete cluster2.getCommand;
|
|
31
29
|
// @ts-expect-error testing
|
|
32
|
-
delete cluster2.hasAttribute;
|
|
33
|
-
// @ts-expect-error testing
|
|
34
30
|
delete cluster2.getCommandResponse;
|
|
35
31
|
expect(cluster1).toStrictEqual(cluster2);
|
|
36
32
|
});
|
|
@@ -43,10 +39,10 @@ describe("Zcl", () => {
|
|
|
43
39
|
|
|
44
40
|
it("Cluster has attribute", () => {
|
|
45
41
|
const cluster = Zcl.Utils.getCluster(0, undefined, {});
|
|
46
|
-
expect(cluster.
|
|
47
|
-
expect(cluster.
|
|
48
|
-
expect(cluster.
|
|
49
|
-
expect(cluster.
|
|
42
|
+
expect(cluster.getAttribute("zclVersion")).not.toBeUndefined();
|
|
43
|
+
expect(cluster.getAttribute("NOTEXISTING")).toBeUndefined();
|
|
44
|
+
expect(cluster.getAttribute(0)).not.toBeUndefined();
|
|
45
|
+
expect(cluster.getAttribute(910293)).toBeUndefined();
|
|
50
46
|
});
|
|
51
47
|
|
|
52
48
|
it("Get specific command by name", () => {
|
|
@@ -1917,26 +1913,26 @@ describe("Zcl", () => {
|
|
|
1917
1913
|
|
|
1918
1914
|
it("Zcl utils get cluster attributes manufacturerCode wrong", () => {
|
|
1919
1915
|
const cluster = Zcl.Utils.getCluster("closuresWindowCovering", 123, {});
|
|
1920
|
-
expect(
|
|
1916
|
+
expect(cluster.getAttribute(0x1000)).toBeUndefined();
|
|
1921
1917
|
});
|
|
1922
1918
|
|
|
1923
1919
|
it("Zcl utils get command", () => {
|
|
1924
1920
|
const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
|
|
1925
1921
|
const command = cluster.getCommand(0);
|
|
1926
|
-
expect(command.name).
|
|
1927
|
-
expect(cluster.getCommand("off")).
|
|
1922
|
+
expect(command.name).toStrictEqual("off");
|
|
1923
|
+
expect(cluster.getCommand("off")).toStrictEqual(command);
|
|
1928
1924
|
});
|
|
1929
1925
|
|
|
1930
1926
|
it("Zcl utils get attribute", () => {
|
|
1931
1927
|
const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
|
|
1932
|
-
const
|
|
1933
|
-
expect(
|
|
1934
|
-
expect(cluster.getAttribute("onTime")).
|
|
1928
|
+
const attribute = cluster.getAttribute(16385);
|
|
1929
|
+
expect(attribute?.name).toStrictEqual("onTime");
|
|
1930
|
+
expect(cluster.getAttribute("onTime")).toStrictEqual(attribute);
|
|
1935
1931
|
});
|
|
1936
1932
|
|
|
1937
1933
|
it("Zcl utils get attribute non-existing", () => {
|
|
1938
1934
|
const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
|
|
1939
|
-
expect(
|
|
1935
|
+
expect(cluster.getAttribute("notExisting")).toBeUndefined();
|
|
1940
1936
|
});
|
|
1941
1937
|
|
|
1942
1938
|
it("Zcl utils get command non-existing", () => {
|
|
@@ -280,13 +280,13 @@ const MANUF_SPE_FRAME_STRING = `{"header":{"frameControl":{"reservedBits":0,"fra
|
|
|
280
280
|
describe("ZCL Frame", () => {
|
|
281
281
|
describe("Validates Parameter Condition", () => {
|
|
282
282
|
it("STATUS_EQUAL", () => {
|
|
283
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 0},
|
|
284
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 1},
|
|
283
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 0}, undefined)).toBeTruthy();
|
|
284
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.readRsp.parameters[2], {status: 1}, undefined)).toBeFalsy();
|
|
285
285
|
});
|
|
286
286
|
|
|
287
287
|
it("STATUS_NOT_EQUAL", () => {
|
|
288
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 1},
|
|
289
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 0},
|
|
288
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 1}, undefined)).toBeTruthy();
|
|
289
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Foundation.writeRsp.parameters[1], {status: 0}, undefined)).toBeFalsy();
|
|
290
290
|
});
|
|
291
291
|
|
|
292
292
|
it("MINIMUM_REMAINING_BUFFER_BYTES", () => {
|
|
@@ -296,34 +296,34 @@ describe("ZCL Frame", () => {
|
|
|
296
296
|
|
|
297
297
|
it("DIRECTION_EQUAL", () => {
|
|
298
298
|
expect(
|
|
299
|
-
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.CLIENT_TO_SERVER},
|
|
299
|
+
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.CLIENT_TO_SERVER}, undefined),
|
|
300
300
|
).toBeTruthy();
|
|
301
301
|
expect(
|
|
302
|
-
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.SERVER_TO_CLIENT},
|
|
302
|
+
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[2], {direction: Zcl.Direction.SERVER_TO_CLIENT}, undefined),
|
|
303
303
|
).toBeFalsy();
|
|
304
304
|
expect(
|
|
305
|
-
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.SERVER_TO_CLIENT},
|
|
305
|
+
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.SERVER_TO_CLIENT}, undefined),
|
|
306
306
|
).toBeTruthy();
|
|
307
307
|
expect(
|
|
308
|
-
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.CLIENT_TO_SERVER},
|
|
308
|
+
Zcl.Frame.conditionsValid(Zcl.Foundation.configReport.parameters[6], {direction: Zcl.Direction.CLIENT_TO_SERVER}, undefined),
|
|
309
309
|
).toBeFalsy();
|
|
310
310
|
});
|
|
311
311
|
|
|
312
312
|
it("BITMASK_SET", () => {
|
|
313
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4000},
|
|
314
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4150},
|
|
315
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x0400},
|
|
316
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x1400},
|
|
313
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4000}, undefined)).toBeTruthy();
|
|
314
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x4150}, undefined)).toBeTruthy();
|
|
315
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x0400}, undefined)).toBeFalsy();
|
|
316
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[8], {options: 0x1400}, undefined)).toBeFalsy();
|
|
317
317
|
});
|
|
318
318
|
|
|
319
319
|
it("BITFIELD_ENUM", () => {
|
|
320
320
|
// {param:'options', offset: 0, size: 3, value: 0b000}
|
|
321
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b000},
|
|
322
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1000},
|
|
323
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b001},
|
|
324
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b011},
|
|
325
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b100},
|
|
326
|
-
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1010},
|
|
321
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b000}, undefined)).toBeTruthy();
|
|
322
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1000}, undefined)).toBeTruthy();
|
|
323
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b001}, undefined)).toBeFalsy();
|
|
324
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b011}, undefined)).toBeFalsy();
|
|
325
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b100}, undefined)).toBeFalsy();
|
|
326
|
+
expect(Zcl.Frame.conditionsValid(Zcl.Clusters.greenPower.commands.notification.parameters[1], {options: 0b1010}, undefined)).toBeFalsy();
|
|
327
327
|
});
|
|
328
328
|
|
|
329
329
|
it("multiple including DATA_TYPE_CLASS_EQUAL", () => {
|
|
@@ -331,41 +331,41 @@ describe("ZCL Frame", () => {
|
|
|
331
331
|
Zcl.Frame.conditionsValid(
|
|
332
332
|
Zcl.Foundation.configReport.parameters[5],
|
|
333
333
|
{direction: Zcl.Direction.CLIENT_TO_SERVER, dataType: Zcl.DataType.UINT8},
|
|
334
|
-
|
|
334
|
+
undefined,
|
|
335
335
|
),
|
|
336
336
|
).toBeTruthy();
|
|
337
337
|
expect(
|
|
338
338
|
Zcl.Frame.conditionsValid(
|
|
339
339
|
Zcl.Foundation.configReport.parameters[5],
|
|
340
340
|
{direction: Zcl.Direction.CLIENT_TO_SERVER, dataType: Zcl.DataType.DATA8},
|
|
341
|
-
|
|
341
|
+
undefined,
|
|
342
342
|
),
|
|
343
343
|
).toBeFalsy();
|
|
344
344
|
expect(
|
|
345
345
|
Zcl.Frame.conditionsValid(
|
|
346
346
|
Zcl.Foundation.configReport.parameters[5],
|
|
347
347
|
{direction: Zcl.Direction.SERVER_TO_CLIENT, dataType: Zcl.DataType.UINT8},
|
|
348
|
-
|
|
348
|
+
undefined,
|
|
349
349
|
),
|
|
350
350
|
).toBeFalsy();
|
|
351
351
|
expect(
|
|
352
352
|
Zcl.Frame.conditionsValid(
|
|
353
353
|
Zcl.Foundation.configReport.parameters[5],
|
|
354
354
|
{direction: Zcl.Direction.SERVER_TO_CLIENT, dataType: Zcl.DataType.DATA8},
|
|
355
|
-
|
|
355
|
+
undefined,
|
|
356
356
|
),
|
|
357
357
|
).toBeFalsy();
|
|
358
358
|
});
|
|
359
359
|
|
|
360
360
|
it("FIELD_EQUAL", () => {
|
|
361
361
|
expect(
|
|
362
|
-
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 1},
|
|
362
|
+
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 1}, undefined),
|
|
363
363
|
).toBeTruthy();
|
|
364
364
|
expect(
|
|
365
|
-
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 0},
|
|
365
|
+
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 0}, undefined),
|
|
366
366
|
).toBeFalsy();
|
|
367
367
|
expect(
|
|
368
|
-
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 3},
|
|
368
|
+
Zcl.Frame.conditionsValid(Zcl.Clusters.touchlink.commandsResponse.scanResponse.parameters[13], {numberOfSubDevices: 3}, undefined),
|
|
369
369
|
).toBeFalsy();
|
|
370
370
|
});
|
|
371
371
|
});
|
|
@@ -116,7 +116,6 @@ describe("ZCL Utils", () => {
|
|
|
116
116
|
expect(cluster.getAttribute).toBeInstanceOf(Function);
|
|
117
117
|
expect(cluster.getCommand).toBeInstanceOf(Function);
|
|
118
118
|
expect(cluster.getCommandResponse).toBeInstanceOf(Function);
|
|
119
|
-
expect(cluster.hasAttribute).toBeInstanceOf(Function);
|
|
120
119
|
});
|
|
121
120
|
|
|
122
121
|
it("Creates empty cluster when getting by invalid ID", () => {
|
|
@@ -130,7 +129,6 @@ describe("ZCL Utils", () => {
|
|
|
130
129
|
expect(cluster.getAttribute).toBeInstanceOf(Function);
|
|
131
130
|
expect(cluster.getCommand).toBeInstanceOf(Function);
|
|
132
131
|
expect(cluster.getCommandResponse).toBeInstanceOf(Function);
|
|
133
|
-
expect(cluster.hasAttribute).toBeInstanceOf(Function);
|
|
134
132
|
});
|
|
135
133
|
|
|
136
134
|
it("Throws when getting invalid cluster name", () => {
|
|
@@ -173,25 +171,19 @@ describe("ZCL Utils", () => {
|
|
|
173
171
|
])("Gets and checks cluster attribute %s", (_name, payload, expected) => {
|
|
174
172
|
const cluster = Zcl.Utils.getCluster(expected.cluster.ID, payload.manufacturerCode, payload.customClusters);
|
|
175
173
|
const attribute = cluster.getAttribute(payload.key);
|
|
176
|
-
expect(
|
|
174
|
+
expect(attribute).not.toBeUndefined();
|
|
177
175
|
expect(attribute).toStrictEqual(cluster.attributes[expected.name]);
|
|
178
176
|
});
|
|
179
177
|
|
|
180
|
-
it("
|
|
178
|
+
it("Returns undefined when getting invalid attribute", () => {
|
|
181
179
|
const cluster = Zcl.Utils.getCluster(Zcl.Clusters.genAlarms.ID, undefined, {});
|
|
182
|
-
expect(()
|
|
183
|
-
|
|
184
|
-
}).toThrow();
|
|
185
|
-
expect(() => {
|
|
186
|
-
cluster.getAttribute(99999);
|
|
187
|
-
}).toThrow();
|
|
180
|
+
expect(cluster.getAttribute("abcd")).toBeUndefined();
|
|
181
|
+
expect(cluster.getAttribute(99999)).toBeUndefined();
|
|
188
182
|
});
|
|
189
183
|
|
|
190
|
-
it("
|
|
184
|
+
it("Returns undefined when getting attribute with invalid manufacturer code", () => {
|
|
191
185
|
const cluster = Zcl.Utils.getCluster(Zcl.Clusters.haDiagnostic.ID, 123, {});
|
|
192
|
-
expect(()
|
|
193
|
-
cluster.getAttribute(Zcl.Clusters.haDiagnostic.attributes.danfossSystemStatusCode.ID);
|
|
194
|
-
}).toThrow();
|
|
186
|
+
expect(cluster.getAttribute(Zcl.Clusters.haDiagnostic.attributes.danfossSystemStatusCode.ID)).toBeUndefined();
|
|
195
187
|
});
|
|
196
188
|
|
|
197
189
|
it.each([
|