zigbee-herdsman 6.0.0 → 6.0.1
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/workflows/ci.yml +1 -1
- package/.github/workflows/typedoc.yaml +1 -1
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +10 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +7 -10
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/events.d.ts +1 -1
- package/dist/controller/events.d.ts.map +1 -1
- package/dist/controller/helpers/request.d.ts.map +1 -1
- package/dist/controller/helpers/request.js +2 -1
- package/dist/controller/helpers/request.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts +2 -4
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +2 -0
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts +13 -24
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +88 -129
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +17 -16
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +31 -16
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +6 -6
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +5 -3
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/model/index.d.ts +1 -0
- package/dist/controller/model/index.d.ts.map +1 -1
- package/dist/controller/model/index.js +3 -1
- package/dist/controller/model/index.js.map +1 -1
- package/dist/controller/model/zigbeeEntity.d.ts +8 -0
- package/dist/controller/model/zigbeeEntity.d.ts.map +1 -0
- package/dist/controller/model/zigbeeEntity.js +11 -0
- package/dist/controller/model/zigbeeEntity.js.map +1 -0
- package/dist/controller/tstype.d.ts +22 -0
- package/dist/controller/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +2 -9
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-typegen.js +61 -13
- package/dist/zspec/zcl/definition/clusters-typegen.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-types.d.ts +173 -140
- package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.d.ts +10 -0
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js +12 -1
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/index.d.ts +1 -0
- package/dist/zspec/zcl/index.d.ts.map +1 -1
- package/dist/zspec/zcl/index.js.map +1 -1
- package/dist/zspec/zcl/utils.d.ts +1 -1
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +1 -1
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/ezsp/driver/driver.ts +1 -1
- package/src/controller/controller.ts +11 -15
- package/src/controller/events.ts +1 -1
- package/src/controller/helpers/request.ts +3 -1
- package/src/controller/helpers/zclFrameConverter.ts +13 -17
- package/src/controller/model/device.ts +103 -148
- package/src/controller/model/endpoint.ts +112 -64
- package/src/controller/model/group.ts +33 -9
- package/src/controller/model/index.ts +1 -0
- package/src/controller/model/zigbeeEntity.ts +30 -0
- package/src/controller/tstype.ts +234 -0
- package/src/zspec/zcl/definition/cluster.ts +2 -9
- package/src/zspec/zcl/definition/clusters-typegen.ts +96 -19
- package/src/zspec/zcl/definition/clusters-types.ts +195 -146
- package/src/zspec/zcl/definition/enums.ts +11 -0
- package/src/zspec/zcl/definition/tstype.ts +0 -1
- package/src/zspec/zcl/index.ts +1 -0
- package/src/zspec/zcl/utils.ts +1 -1
- package/test/controller.test.ts +291 -93
- package/test/zspec/zcl/utils.test.ts +4 -4
package/test/controller.test.ts
CHANGED
|
@@ -199,9 +199,12 @@ let iasZoneReadState170Count = 0;
|
|
|
199
199
|
let enroll170 = true;
|
|
200
200
|
let configureReportStatus = 0;
|
|
201
201
|
let configureReportDefaultRsp = false;
|
|
202
|
+
let lastSentZclFrameToEndpoint: Buffer | undefined;
|
|
202
203
|
|
|
203
204
|
const restoreMocksendZclFrameToEndpoint = () => {
|
|
204
205
|
mocksendZclFrameToEndpoint.mockImplementation((_ieeeAddr, networkAddress, endpoint, frame: Zcl.Frame) => {
|
|
206
|
+
lastSentZclFrameToEndpoint = frame.toBuffer();
|
|
207
|
+
|
|
205
208
|
if (
|
|
206
209
|
frame.header.isGlobal &&
|
|
207
210
|
frame.isCommand("read") &&
|
|
@@ -401,6 +404,7 @@ const mocksRestore = [mockAdapterPermitJoin, mockAdapterStop, mocksendZclFrameTo
|
|
|
401
404
|
const events: {
|
|
402
405
|
deviceJoined: Events.DeviceJoinedPayload[];
|
|
403
406
|
deviceInterview: Events.DeviceInterviewPayload[];
|
|
407
|
+
deviceInterviewRaw: Events.DeviceInterviewPayload[];
|
|
404
408
|
adapterDisconnected: number[];
|
|
405
409
|
deviceAnnounce: Events.DeviceAnnouncePayload[];
|
|
406
410
|
deviceLeave: Events.DeviceLeavePayload[];
|
|
@@ -411,6 +415,7 @@ const events: {
|
|
|
411
415
|
} = {
|
|
412
416
|
deviceJoined: [],
|
|
413
417
|
deviceInterview: [],
|
|
418
|
+
deviceInterviewRaw: [],
|
|
414
419
|
adapterDisconnected: [],
|
|
415
420
|
deviceAnnounce: [],
|
|
416
421
|
deviceLeave: [],
|
|
@@ -490,7 +495,10 @@ describe("Controller", () => {
|
|
|
490
495
|
controller = new Controller(options);
|
|
491
496
|
controller.on("permitJoinChanged", (data) => events.permitJoinChanged.push(data));
|
|
492
497
|
controller.on("deviceJoined", (data) => events.deviceJoined.push(data));
|
|
493
|
-
controller.on("deviceInterview", (data) =>
|
|
498
|
+
controller.on("deviceInterview", (data) => {
|
|
499
|
+
events.deviceInterview.push(deepClone(data));
|
|
500
|
+
events.deviceInterviewRaw.push(data);
|
|
501
|
+
});
|
|
494
502
|
controller.on("adapterDisconnected", () => events.adapterDisconnected.push(1));
|
|
495
503
|
controller.on("deviceAnnounce", (data) => events.deviceAnnounce.push(data));
|
|
496
504
|
controller.on("deviceLeave", (data) => events.deviceLeave.push(data));
|
|
@@ -1286,18 +1294,21 @@ describe("Controller", () => {
|
|
|
1286
1294
|
},
|
|
1287
1295
|
],
|
|
1288
1296
|
_manufacturerID: 1212,
|
|
1289
|
-
_manufacturerName: "KoenAndCo",
|
|
1290
|
-
_powerSource: "Mains (single phase)",
|
|
1291
|
-
_modelID: "myModelID",
|
|
1292
|
-
_applicationVersion: 2,
|
|
1293
|
-
_stackVersion: 101,
|
|
1294
|
-
_zclVersion: 1,
|
|
1295
|
-
_hardwareVersion: 3,
|
|
1296
|
-
_dateCode: "201901",
|
|
1297
|
-
_softwareBuildID: "1.01",
|
|
1298
1297
|
_interviewState: InterviewState.Successful,
|
|
1299
1298
|
};
|
|
1299
|
+
const deviceGenBasic = {
|
|
1300
|
+
manufacturerName: "KoenAndCo",
|
|
1301
|
+
powerSource: Zcl.PowerSource["Mains (single phase)"],
|
|
1302
|
+
modelId: "myModelID",
|
|
1303
|
+
appVersion: 2,
|
|
1304
|
+
stackVersion: 101,
|
|
1305
|
+
zclVersion: 1,
|
|
1306
|
+
hwVersion: 3,
|
|
1307
|
+
dateCode: "201901",
|
|
1308
|
+
swBuildId: "1.01",
|
|
1309
|
+
};
|
|
1300
1310
|
expect(events.deviceInterview[1]).toStrictEqual({status: "successful", device: device});
|
|
1311
|
+
expect(events.deviceInterviewRaw[1].device.genBasic).toStrictEqual(deviceGenBasic);
|
|
1301
1312
|
expect(deepClone(controller.getDeviceByNetworkAddress(129))).toStrictEqual(device);
|
|
1302
1313
|
expect(events.deviceInterview.length).toBe(2);
|
|
1303
1314
|
expect(databaseContents()).toStrictEqual(
|
|
@@ -1316,7 +1327,10 @@ describe("Controller", () => {
|
|
|
1316
1327
|
it("Join a device and explictly accept it", async () => {
|
|
1317
1328
|
controller = new Controller(options);
|
|
1318
1329
|
controller.on("deviceJoined", (device) => events.deviceJoined.push(device));
|
|
1319
|
-
controller.on("deviceInterview", (
|
|
1330
|
+
controller.on("deviceInterview", (data) => {
|
|
1331
|
+
events.deviceInterview.push(deepClone(data));
|
|
1332
|
+
events.deviceInterviewRaw.push(data);
|
|
1333
|
+
});
|
|
1320
1334
|
await controller.start();
|
|
1321
1335
|
expect(databaseContents().includes("0x129")).toBeFalsy();
|
|
1322
1336
|
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
@@ -1371,18 +1385,21 @@ describe("Controller", () => {
|
|
|
1371
1385
|
},
|
|
1372
1386
|
],
|
|
1373
1387
|
_manufacturerID: 1212,
|
|
1374
|
-
_manufacturerName: "KoenAndCo",
|
|
1375
|
-
_powerSource: "Mains (single phase)",
|
|
1376
|
-
_modelID: "myModelID",
|
|
1377
|
-
_applicationVersion: 2,
|
|
1378
|
-
_stackVersion: 101,
|
|
1379
|
-
_zclVersion: 1,
|
|
1380
|
-
_hardwareVersion: 3,
|
|
1381
|
-
_dateCode: "201901",
|
|
1382
|
-
_softwareBuildID: "1.01",
|
|
1383
1388
|
_interviewState: InterviewState.Successful,
|
|
1384
1389
|
};
|
|
1390
|
+
const deviceGenBasic = {
|
|
1391
|
+
manufacturerName: "KoenAndCo",
|
|
1392
|
+
powerSource: Zcl.PowerSource["Mains (single phase)"],
|
|
1393
|
+
modelId: "myModelID",
|
|
1394
|
+
appVersion: 2,
|
|
1395
|
+
stackVersion: 101,
|
|
1396
|
+
zclVersion: 1,
|
|
1397
|
+
hwVersion: 3,
|
|
1398
|
+
dateCode: "201901",
|
|
1399
|
+
swBuildId: "1.01",
|
|
1400
|
+
};
|
|
1385
1401
|
expect(events.deviceInterview[1]).toStrictEqual({status: "successful", device: device});
|
|
1402
|
+
expect(events.deviceInterviewRaw[1].device.genBasic).toStrictEqual(deviceGenBasic);
|
|
1386
1403
|
expect(deepClone(controller.getDeviceByIeeeAddr("0x129"))).toStrictEqual(device);
|
|
1387
1404
|
expect(events.deviceInterview.length).toBe(2);
|
|
1388
1405
|
expect(databaseContents().includes("0x129")).toBeTruthy();
|
|
@@ -1429,8 +1446,8 @@ describe("Controller", () => {
|
|
|
1429
1446
|
await controller.start();
|
|
1430
1447
|
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
1431
1448
|
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
1432
|
-
device.powerSource = "
|
|
1433
|
-
expect(device.powerSource).toBe("
|
|
1449
|
+
device.powerSource = "DC Source";
|
|
1450
|
+
expect(device.powerSource).toBe("DC Source");
|
|
1434
1451
|
});
|
|
1435
1452
|
|
|
1436
1453
|
it("Get device should return same instance", async () => {
|
|
@@ -2245,8 +2262,7 @@ describe("Controller", () => {
|
|
|
2245
2262
|
expect(events.deviceInterview[1].status).toBe("successful");
|
|
2246
2263
|
// @ts-expect-error private but deep cloned
|
|
2247
2264
|
expect(events.deviceInterview[1].device._ieeeAddr).toBe("0x161");
|
|
2248
|
-
|
|
2249
|
-
expect(events.deviceInterview[1].device._modelID).toBe("myDevice9123");
|
|
2265
|
+
expect(events.deviceInterviewRaw[1].device.genBasic.modelId).toBe("myDevice9123");
|
|
2250
2266
|
});
|
|
2251
2267
|
|
|
2252
2268
|
it("Device joins with endpoints [2,1], as 2 is the only endpoint supporting genBasic it should read modelID from that", async () => {
|
|
@@ -2259,8 +2275,7 @@ describe("Controller", () => {
|
|
|
2259
2275
|
expect(events.deviceInterview[1].status).toBe("successful");
|
|
2260
2276
|
// @ts-expect-error private but deep cloned
|
|
2261
2277
|
expect(events.deviceInterview[1].device._ieeeAddr).toBe("0x162");
|
|
2262
|
-
|
|
2263
|
-
expect(events.deviceInterview[1].device._modelID).toBe("myDevice9124");
|
|
2278
|
+
expect(events.deviceInterviewRaw[1].device.genBasic.modelId).toBe("myDevice9124");
|
|
2264
2279
|
});
|
|
2265
2280
|
|
|
2266
2281
|
it("Device joins and interview iAs enrollment succeeds", async () => {
|
|
@@ -3107,12 +3122,20 @@ describe("Controller", () => {
|
|
|
3107
3122
|
],
|
|
3108
3123
|
_type: "EndDevice",
|
|
3109
3124
|
_manufacturerID: 4151,
|
|
3110
|
-
_manufacturerName: "LUMI",
|
|
3111
3125
|
meta: {},
|
|
3112
|
-
_powerSource: "Battery",
|
|
3113
|
-
_modelID: "lumi.occupancy",
|
|
3114
3126
|
_interviewState: InterviewState.Successful,
|
|
3115
3127
|
});
|
|
3128
|
+
expect(controller.getDeviceByIeeeAddr("0x150")?.genBasic).toStrictEqual({
|
|
3129
|
+
appVersion: undefined,
|
|
3130
|
+
dateCode: undefined,
|
|
3131
|
+
hwVersion: undefined,
|
|
3132
|
+
manufacturerName: "LUMI",
|
|
3133
|
+
modelId: "lumi.occupancy",
|
|
3134
|
+
powerSource: Zcl.PowerSource.Battery,
|
|
3135
|
+
stackVersion: undefined,
|
|
3136
|
+
swBuildId: undefined,
|
|
3137
|
+
zclVersion: undefined,
|
|
3138
|
+
});
|
|
3116
3139
|
});
|
|
3117
3140
|
|
|
3118
3141
|
it("Xiaomi end device joins (node descriptor succeeds, but active endpoint response fails)", async () => {
|
|
@@ -3160,12 +3183,20 @@ describe("Controller", () => {
|
|
|
3160
3183
|
],
|
|
3161
3184
|
_type: "EndDevice",
|
|
3162
3185
|
_manufacturerID: 1219,
|
|
3163
|
-
_manufacturerName: "LUMI",
|
|
3164
3186
|
meta: {},
|
|
3165
|
-
_powerSource: "Battery",
|
|
3166
|
-
_modelID: "lumi.occupancy",
|
|
3167
3187
|
_interviewState: InterviewState.Successful,
|
|
3168
3188
|
});
|
|
3189
|
+
expect(controller.getDeviceByIeeeAddr("0x151")?.genBasic).toStrictEqual({
|
|
3190
|
+
appVersion: undefined,
|
|
3191
|
+
dateCode: undefined,
|
|
3192
|
+
hwVersion: undefined,
|
|
3193
|
+
manufacturerName: "LUMI",
|
|
3194
|
+
modelId: "lumi.occupancy",
|
|
3195
|
+
powerSource: Zcl.PowerSource.Battery,
|
|
3196
|
+
stackVersion: undefined,
|
|
3197
|
+
swBuildId: undefined,
|
|
3198
|
+
zclVersion: undefined,
|
|
3199
|
+
});
|
|
3169
3200
|
});
|
|
3170
3201
|
|
|
3171
3202
|
it("Should use cached node descriptor when device is re-interviewed, but retrieve it when ignoreCache=true", async () => {
|
|
@@ -3640,7 +3671,7 @@ describe("Controller", () => {
|
|
|
3640
3671
|
expect(call[2]).toBe(1);
|
|
3641
3672
|
expect(call[3].cluster.name).toBe("genPollCtrl");
|
|
3642
3673
|
expect(call[3].command.name).toBe("checkinRsp");
|
|
3643
|
-
expect(call[3].payload).toStrictEqual({startFastPolling:
|
|
3674
|
+
expect(call[3].payload).toStrictEqual({startFastPolling: 0, fastPollTimeout: 0});
|
|
3644
3675
|
});
|
|
3645
3676
|
|
|
3646
3677
|
it("Poll control unsupported", async () => {
|
|
@@ -3888,6 +3919,36 @@ describe("Controller", () => {
|
|
|
3888
3919
|
);
|
|
3889
3920
|
});
|
|
3890
3921
|
|
|
3922
|
+
it("throws when trying to configure reporting on endpoint with bad attribute", async () => {
|
|
3923
|
+
await controller.start();
|
|
3924
|
+
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
3925
|
+
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
3926
|
+
const endpoint = device.getEndpoint(1)!;
|
|
3927
|
+
mocksendZclFrameToEndpoint.mockClear();
|
|
3928
|
+
|
|
3929
|
+
await expect(async () => {
|
|
3930
|
+
await endpoint.configureReporting("genPowerCfg", [
|
|
3931
|
+
{
|
|
3932
|
+
attribute: "doesnotexist",
|
|
3933
|
+
minimumReportInterval: 1,
|
|
3934
|
+
maximumReportInterval: 10,
|
|
3935
|
+
reportableChange: 1,
|
|
3936
|
+
},
|
|
3937
|
+
]);
|
|
3938
|
+
}).rejects.toThrow(`Invalid attribute 'doesnotexist' for cluster 'genPowerCfg'`);
|
|
3939
|
+
|
|
3940
|
+
await expect(async () => {
|
|
3941
|
+
await endpoint.configureReporting("genBasic", [
|
|
3942
|
+
{
|
|
3943
|
+
attribute: 99999,
|
|
3944
|
+
minimumReportInterval: 1,
|
|
3945
|
+
maximumReportInterval: 10,
|
|
3946
|
+
reportableChange: 1,
|
|
3947
|
+
},
|
|
3948
|
+
]);
|
|
3949
|
+
}).rejects.toThrow(`Invalid attribute '99999' for cluster 'genBasic'`);
|
|
3950
|
+
});
|
|
3951
|
+
|
|
3891
3952
|
it("Should replace legacy configured reportings without manufacturerCode", async () => {
|
|
3892
3953
|
await controller.start();
|
|
3893
3954
|
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
@@ -4451,6 +4512,24 @@ describe("Controller", () => {
|
|
|
4451
4512
|
expect(error).toStrictEqual(new Error("whoops!"));
|
|
4452
4513
|
});
|
|
4453
4514
|
|
|
4515
|
+
it("Endpoint waitForCommand frame fails to parse", async () => {
|
|
4516
|
+
await controller.start();
|
|
4517
|
+
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
4518
|
+
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
4519
|
+
const endpoint = device.getEndpoint(1)!;
|
|
4520
|
+
mocksendZclFrameToEndpoint.mockClear();
|
|
4521
|
+
// The buffer below ([24, 169, 10, 0, 0, 24]) is intentionally malformed:
|
|
4522
|
+
// It is missing expected payload bytes for a valid ZCL frame, causing Zcl.Frame.fromBuffer to throw a parsing error.
|
|
4523
|
+
// This triggers the error handling path being tested.
|
|
4524
|
+
const buffer = Buffer.from([24, 169, 10, 0, 0, 24]);
|
|
4525
|
+
const header = Zcl.Header.fromBuffer(buffer);
|
|
4526
|
+
const promise = new Promise((resolve, _reject) => resolve({clusterID: Zcl.Utils.getCluster("msOccupancySensing").ID, data: buffer, header}));
|
|
4527
|
+
mockAdapterWaitFor.mockReturnValueOnce({promise, cancel: () => {}});
|
|
4528
|
+
await expect(endpoint.waitForCommand("genOta", "upgradeEndRequest", 10, 20).promise).rejects.toThrow(
|
|
4529
|
+
`The value of "offset" is out of range. It must be >= 0 and <= 5. Received 6`,
|
|
4530
|
+
);
|
|
4531
|
+
});
|
|
4532
|
+
|
|
4454
4533
|
it("Device without meta should set meta to {}", async () => {
|
|
4455
4534
|
Device.resetCache();
|
|
4456
4535
|
const line = JSON.stringify({
|
|
@@ -4490,8 +4569,6 @@ describe("Controller", () => {
|
|
|
4490
4569
|
_eventsCount: 0,
|
|
4491
4570
|
_pendingRequestTimeout: 0,
|
|
4492
4571
|
_skipDefaultResponse: false,
|
|
4493
|
-
_applicationVersion: 17,
|
|
4494
|
-
_dateCode: "20170302",
|
|
4495
4572
|
_customClusters: {},
|
|
4496
4573
|
_endpoints: [
|
|
4497
4574
|
{
|
|
@@ -4511,21 +4588,25 @@ describe("Controller", () => {
|
|
|
4511
4588
|
profileID: 49246,
|
|
4512
4589
|
},
|
|
4513
4590
|
],
|
|
4514
|
-
_hardwareVersion: 1,
|
|
4515
4591
|
_ieeeAddr: "0x90fd9ffffe4b64ae",
|
|
4516
4592
|
_interviewState: InterviewState.Successful,
|
|
4517
4593
|
_manufacturerID: 4476,
|
|
4518
|
-
_manufacturerName: "IKEA of Sweden",
|
|
4519
4594
|
meta: {},
|
|
4520
|
-
_modelID: "TRADFRI remote control",
|
|
4521
4595
|
_networkAddress: 19468,
|
|
4522
|
-
_powerSource: "Battery",
|
|
4523
|
-
_softwareBuildID: "1.2.214",
|
|
4524
|
-
_stackVersion: 87,
|
|
4525
4596
|
_type: "EndDevice",
|
|
4526
|
-
_zclVersion: 1,
|
|
4527
4597
|
};
|
|
4528
4598
|
expect(deepClone(controller.getDeviceByIeeeAddr("0x90fd9ffffe4b64ae"))).toStrictEqual(expected);
|
|
4599
|
+
expect(controller.getDeviceByIeeeAddr("0x90fd9ffffe4b64ae")?.genBasic).toStrictEqual({
|
|
4600
|
+
manufacturerName: "IKEA of Sweden",
|
|
4601
|
+
modelId: "TRADFRI remote control",
|
|
4602
|
+
powerSource: Zcl.PowerSource.Battery,
|
|
4603
|
+
swBuildId: "1.2.214",
|
|
4604
|
+
stackVersion: 87,
|
|
4605
|
+
zclVersion: 1,
|
|
4606
|
+
appVersion: 17,
|
|
4607
|
+
dateCode: "20170302",
|
|
4608
|
+
hwVersion: 1,
|
|
4609
|
+
});
|
|
4529
4610
|
});
|
|
4530
4611
|
|
|
4531
4612
|
it("Read from group", async () => {
|
|
@@ -4573,7 +4654,7 @@ describe("Controller", () => {
|
|
|
4573
4654
|
it("Write to group", async () => {
|
|
4574
4655
|
await controller.start();
|
|
4575
4656
|
const group = await controller.createGroup(2);
|
|
4576
|
-
await group.write("genBasic", {49: {value: 0x000b, type: 0x19}, deviceEnabled:
|
|
4657
|
+
await group.write("genBasic", {49: {value: 0x000b, type: 0x19}, deviceEnabled: 1}, {});
|
|
4577
4658
|
expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(1);
|
|
4578
4659
|
expect(mocksendZclFrameToGroup.mock.calls[0][0]).toBe(2);
|
|
4579
4660
|
expect(deepClone(mocksendZclFrameToGroup.mock.calls[0][1])).toStrictEqual(
|
|
@@ -4588,7 +4669,7 @@ describe("Controller", () => {
|
|
|
4588
4669
|
0,
|
|
4589
4670
|
[
|
|
4590
4671
|
{attrData: 11, attrId: 49, dataType: 25},
|
|
4591
|
-
{attrData:
|
|
4672
|
+
{attrData: 1, attrId: 18, dataType: 16},
|
|
4592
4673
|
],
|
|
4593
4674
|
{},
|
|
4594
4675
|
),
|
|
@@ -4602,7 +4683,7 @@ describe("Controller", () => {
|
|
|
4602
4683
|
const group = await controller.createGroup(2);
|
|
4603
4684
|
let error;
|
|
4604
4685
|
try {
|
|
4605
|
-
await group.write("genBasic", {UNKNOWN: {value: 0x000b, type: 0x19}, deviceEnabled:
|
|
4686
|
+
await group.write("genBasic", {UNKNOWN: {value: 0x000b, type: 0x19}, deviceEnabled: 1}, {});
|
|
4606
4687
|
} catch (e) {
|
|
4607
4688
|
error = e;
|
|
4608
4689
|
}
|
|
@@ -5293,8 +5374,6 @@ describe("Controller", () => {
|
|
|
5293
5374
|
_eventsCount: 0,
|
|
5294
5375
|
_pendingRequestTimeout: 0,
|
|
5295
5376
|
_skipDefaultResponse: false,
|
|
5296
|
-
_applicationVersion: 17,
|
|
5297
|
-
_dateCode: "20170331",
|
|
5298
5377
|
_customClusters: {},
|
|
5299
5378
|
_endpoints: [
|
|
5300
5379
|
{
|
|
@@ -5314,27 +5393,29 @@ describe("Controller", () => {
|
|
|
5314
5393
|
profileID: 49246,
|
|
5315
5394
|
},
|
|
5316
5395
|
],
|
|
5317
|
-
_hardwareVersion: 1,
|
|
5318
5396
|
_ieeeAddr: "0x000b57fffec6a5b2",
|
|
5319
5397
|
_interviewState: InterviewState.Successful,
|
|
5320
5398
|
_manufacturerID: 4476,
|
|
5321
|
-
_manufacturerName: "IKEA of Sweden",
|
|
5322
5399
|
meta: {reporting: 1},
|
|
5323
|
-
_modelID: "TRADFRI bulb E27 WS opal 980lm",
|
|
5324
5400
|
_networkAddress: 40369,
|
|
5325
|
-
_powerSource: "Mains (single phase)",
|
|
5326
|
-
_softwareBuildID: "1.2.217",
|
|
5327
|
-
_stackVersion: 87,
|
|
5328
5401
|
_type: "Router",
|
|
5329
|
-
|
|
5402
|
+
});
|
|
5403
|
+
expect(controller.getDeviceByIeeeAddr("0x000b57fffec6a5b2")?.genBasic).toStrictEqual({
|
|
5404
|
+
appVersion: 17,
|
|
5405
|
+
dateCode: "20170331",
|
|
5406
|
+
hwVersion: 1,
|
|
5407
|
+
manufacturerName: "IKEA of Sweden",
|
|
5408
|
+
modelId: "TRADFRI bulb E27 WS opal 980lm",
|
|
5409
|
+
powerSource: Zcl.PowerSource["Mains (single phase)"],
|
|
5410
|
+
swBuildId: "1.2.217",
|
|
5411
|
+
stackVersion: 87,
|
|
5412
|
+
zclVersion: 1,
|
|
5330
5413
|
});
|
|
5331
5414
|
expect(deepClone(controller.getDeviceByIeeeAddr("0x0017880104e45517"))).toStrictEqual({
|
|
5332
5415
|
ID: 4,
|
|
5333
5416
|
_events: {},
|
|
5334
5417
|
_eventsCount: 0,
|
|
5335
5418
|
_pendingRequestTimeout: 0,
|
|
5336
|
-
_applicationVersion: 2,
|
|
5337
|
-
_dateCode: "20160302",
|
|
5338
5419
|
_customClusters: {},
|
|
5339
5420
|
_endpoints: [
|
|
5340
5421
|
{
|
|
@@ -5370,30 +5451,32 @@ describe("Controller", () => {
|
|
|
5370
5451
|
pendingRequests: {id: 2, deviceIeeeAddress: "0x0017880104e45517", sendInProgress: false},
|
|
5371
5452
|
},
|
|
5372
5453
|
],
|
|
5373
|
-
_hardwareVersion: 1,
|
|
5374
5454
|
_ieeeAddr: "0x0017880104e45517",
|
|
5375
5455
|
_interviewState: InterviewState.Successful,
|
|
5376
5456
|
_lastSeen: 123,
|
|
5377
5457
|
_manufacturerID: 4107,
|
|
5378
|
-
_manufacturerName: "Philips",
|
|
5379
|
-
_modelID: "RWL021",
|
|
5380
5458
|
_networkAddress: 6538,
|
|
5381
|
-
_powerSource: "Battery",
|
|
5382
|
-
_softwareBuildID: "5.45.1.17846",
|
|
5383
|
-
_stackVersion: 1,
|
|
5384
5459
|
_type: "EndDevice",
|
|
5385
|
-
_zclVersion: 1,
|
|
5386
5460
|
_skipDefaultResponse: false,
|
|
5387
5461
|
meta: {configured: 1},
|
|
5388
5462
|
});
|
|
5463
|
+
expect(controller.getDeviceByIeeeAddr("0x0017880104e45517")?.genBasic).toStrictEqual({
|
|
5464
|
+
appVersion: 2,
|
|
5465
|
+
dateCode: "20160302",
|
|
5466
|
+
hwVersion: 1,
|
|
5467
|
+
manufacturerName: "Philips",
|
|
5468
|
+
modelId: "RWL021",
|
|
5469
|
+
powerSource: Zcl.PowerSource.Battery,
|
|
5470
|
+
swBuildId: "5.45.1.17846",
|
|
5471
|
+
stackVersion: 1,
|
|
5472
|
+
zclVersion: 1,
|
|
5473
|
+
});
|
|
5389
5474
|
expect(deepClone(controller.getDeviceByIeeeAddr("0x0017880104e45518"))).toStrictEqual({
|
|
5390
5475
|
ID: 6,
|
|
5391
5476
|
_checkinInterval: 123456,
|
|
5392
5477
|
_events: {},
|
|
5393
5478
|
_eventsCount: 0,
|
|
5394
5479
|
_pendingRequestTimeout: 123456000,
|
|
5395
|
-
_applicationVersion: 2,
|
|
5396
|
-
_dateCode: "20160302",
|
|
5397
5480
|
_customClusters: {},
|
|
5398
5481
|
_endpoints: [
|
|
5399
5482
|
{
|
|
@@ -5429,21 +5512,25 @@ describe("Controller", () => {
|
|
|
5429
5512
|
pendingRequests: {id: 2, deviceIeeeAddress: "0x0017880104e45518", sendInProgress: false},
|
|
5430
5513
|
},
|
|
5431
5514
|
],
|
|
5432
|
-
_hardwareVersion: 1,
|
|
5433
5515
|
_ieeeAddr: "0x0017880104e45518",
|
|
5434
5516
|
_interviewState: InterviewState.Successful,
|
|
5435
5517
|
_manufacturerID: 4107,
|
|
5436
|
-
_manufacturerName: "Philips",
|
|
5437
|
-
_modelID: "RWL021",
|
|
5438
5518
|
_networkAddress: 6536,
|
|
5439
|
-
_powerSource: "Battery",
|
|
5440
|
-
_softwareBuildID: "5.45.1.17846",
|
|
5441
|
-
_stackVersion: 1,
|
|
5442
5519
|
_type: "EndDevice",
|
|
5443
|
-
_zclVersion: 1,
|
|
5444
5520
|
_skipDefaultResponse: false,
|
|
5445
5521
|
meta: {configured: 1},
|
|
5446
5522
|
});
|
|
5523
|
+
expect(controller.getDeviceByIeeeAddr("0x0017880104e45518")?.genBasic).toStrictEqual({
|
|
5524
|
+
appVersion: 2,
|
|
5525
|
+
dateCode: "20160302",
|
|
5526
|
+
hwVersion: 1,
|
|
5527
|
+
manufacturerName: "Philips",
|
|
5528
|
+
modelId: "RWL021",
|
|
5529
|
+
powerSource: Zcl.PowerSource.Battery,
|
|
5530
|
+
swBuildId: "5.45.1.17846",
|
|
5531
|
+
stackVersion: 1,
|
|
5532
|
+
zclVersion: 1,
|
|
5533
|
+
});
|
|
5447
5534
|
expect((await controller.getGroups()).length).toBe(2);
|
|
5448
5535
|
|
|
5449
5536
|
const group1 = controller.getGroupByID(1)!;
|
|
@@ -5957,25 +6044,23 @@ describe("Controller", () => {
|
|
|
5957
6044
|
});
|
|
5958
6045
|
|
|
5959
6046
|
it("Write structured", async () => {
|
|
5960
|
-
await controller.start();
|
|
5961
6047
|
await controller.start();
|
|
5962
6048
|
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
5963
6049
|
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
5964
6050
|
const endpoint = device.getEndpoint(1)!;
|
|
5965
6051
|
mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
|
|
5966
6052
|
|
|
5967
|
-
await endpoint.writeStructured("genPowerCfg",
|
|
6053
|
+
await endpoint.writeStructured("genPowerCfg", []);
|
|
5968
6054
|
});
|
|
5969
6055
|
|
|
5970
6056
|
it("Write structured with disable response", async () => {
|
|
5971
|
-
await controller.start();
|
|
5972
6057
|
await controller.start();
|
|
5973
6058
|
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
5974
6059
|
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
5975
6060
|
const endpoint = device.getEndpoint(1)!;
|
|
5976
6061
|
mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
|
|
5977
6062
|
|
|
5978
|
-
await endpoint.writeStructured("genPowerCfg",
|
|
6063
|
+
await endpoint.writeStructured("genPowerCfg", [], {disableResponse: true});
|
|
5979
6064
|
});
|
|
5980
6065
|
|
|
5981
6066
|
it("Write structured error", async () => {
|
|
@@ -5986,17 +6071,71 @@ describe("Controller", () => {
|
|
|
5986
6071
|
mocksendZclFrameToEndpoint.mockRejectedValueOnce(new Error("timeout occurred"));
|
|
5987
6072
|
let error;
|
|
5988
6073
|
try {
|
|
5989
|
-
await endpoint.writeStructured("genPowerCfg",
|
|
6074
|
+
await endpoint.writeStructured("genPowerCfg", []);
|
|
5990
6075
|
} catch (e) {
|
|
5991
6076
|
error = e;
|
|
5992
6077
|
}
|
|
5993
6078
|
expect(error).toStrictEqual(
|
|
5994
6079
|
new Error(
|
|
5995
|
-
`ZCL command 0x129/1 genPowerCfg.writeStructured(
|
|
6080
|
+
`ZCL command 0x129/1 genPowerCfg.writeStructured([], {"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"reservedBits":0,"writeUndiv":false}) failed (timeout occurred)`,
|
|
5996
6081
|
),
|
|
5997
6082
|
);
|
|
5998
6083
|
});
|
|
5999
6084
|
|
|
6085
|
+
it("Write with custom payload", async () => {
|
|
6086
|
+
await controller.start();
|
|
6087
|
+
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
6088
|
+
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
6089
|
+
const endpoint = device.getEndpoint(1)!;
|
|
6090
|
+
|
|
6091
|
+
const writeOptions = {
|
|
6092
|
+
frameType: 0,
|
|
6093
|
+
manufacturerCode: 0x1ad2,
|
|
6094
|
+
disableDefaultResponse: true,
|
|
6095
|
+
disableResponse: true,
|
|
6096
|
+
reservedBits: 3,
|
|
6097
|
+
direction: 1,
|
|
6098
|
+
writeUndiv: true,
|
|
6099
|
+
transactionSequenceNumber: 0xe9,
|
|
6100
|
+
};
|
|
6101
|
+
|
|
6102
|
+
await endpoint.writeStructured(
|
|
6103
|
+
"genPowerCfg",
|
|
6104
|
+
[
|
|
6105
|
+
{
|
|
6106
|
+
attrId: 0x0000,
|
|
6107
|
+
// @ts-expect-error workaround write custom payload, special case "do not write anything"
|
|
6108
|
+
selector: null,
|
|
6109
|
+
elementData: [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
6110
|
+
// dataType: undefined,
|
|
6111
|
+
},
|
|
6112
|
+
],
|
|
6113
|
+
writeOptions,
|
|
6114
|
+
);
|
|
6115
|
+
|
|
6116
|
+
expect(lastSentZclFrameToEndpoint).toStrictEqual(
|
|
6117
|
+
// Note: 0x00 before start of payload is from having dataType=undefined (gets written as zero)
|
|
6118
|
+
Buffer.from([0x7c, 0xd2, 0x1a, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
|
6119
|
+
);
|
|
6120
|
+
|
|
6121
|
+
await endpoint.write(
|
|
6122
|
+
"genPowerCfg",
|
|
6123
|
+
{
|
|
6124
|
+
// @ts-expect-error workaround write custom payload
|
|
6125
|
+
4865: {
|
|
6126
|
+
value: [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
6127
|
+
// type: undefined,
|
|
6128
|
+
},
|
|
6129
|
+
},
|
|
6130
|
+
writeOptions,
|
|
6131
|
+
);
|
|
6132
|
+
|
|
6133
|
+
expect(lastSentZclFrameToEndpoint).toStrictEqual(
|
|
6134
|
+
// Note: 0x00 before start of payload is from having dataType=undefined (gets written as zero)
|
|
6135
|
+
Buffer.from([0x7c, 0xd2, 0x1a, 0xe9, 0x03, 0x01, 0x13, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
|
6136
|
+
);
|
|
6137
|
+
});
|
|
6138
|
+
|
|
6000
6139
|
it("Green power", async () => {
|
|
6001
6140
|
await controller.start();
|
|
6002
6141
|
const data = {
|
|
@@ -6097,7 +6236,6 @@ describe("Controller", () => {
|
|
|
6097
6236
|
_interviewState: InterviewState.Successful,
|
|
6098
6237
|
_lastSeen: Date.now(),
|
|
6099
6238
|
_linkquality: 50,
|
|
6100
|
-
_modelID: "GreenPower_2",
|
|
6101
6239
|
_networkAddress: 0xf4fe,
|
|
6102
6240
|
_type: "GreenPower",
|
|
6103
6241
|
meta: {},
|
|
@@ -6117,13 +6255,16 @@ describe("Controller", () => {
|
|
|
6117
6255
|
_eventsCount: 0,
|
|
6118
6256
|
_ieeeAddr: "0x000000000046f4fe",
|
|
6119
6257
|
_interviewState: InterviewState.Successful,
|
|
6120
|
-
_modelID: "GreenPower_2",
|
|
6121
6258
|
_networkAddress: 0xf4fe,
|
|
6122
6259
|
_type: "GreenPower",
|
|
6123
6260
|
meta: {},
|
|
6124
6261
|
_gpSecurityKey: [0xf1, 0xec, 0x92, 0xab, 0xff, 0x8f, 0x13, 0x63, 0xe1, 0x46, 0xbe, 0xb5, 0x18, 0xc9, 0x0c, 0xab],
|
|
6125
6262
|
},
|
|
6126
6263
|
});
|
|
6264
|
+
expect(deepClone(events.deviceInterviewRaw[0].device.genBasic)).toStrictEqual({
|
|
6265
|
+
modelId: "GreenPower_2",
|
|
6266
|
+
powerSource: 0,
|
|
6267
|
+
});
|
|
6127
6268
|
expect(controller.getDeviceByIeeeAddr("0x000000000046f4fe")!.networkAddress).toBe(0xf4fe);
|
|
6128
6269
|
expect(events.message.length).toBe(2);
|
|
6129
6270
|
|
|
@@ -6692,13 +6833,13 @@ describe("Controller", () => {
|
|
|
6692
6833
|
_interviewState: InterviewState.Successful,
|
|
6693
6834
|
_lastSeen: Date.now(),
|
|
6694
6835
|
_linkquality: 50,
|
|
6695
|
-
_modelID: "GreenPower_2",
|
|
6696
6836
|
_networkAddress: 0x71f8,
|
|
6697
6837
|
_type: "GreenPower",
|
|
6698
6838
|
meta: {},
|
|
6699
6839
|
_gpSecurityKey: [0x21, 0x7f, 0x8c, 0xb2, 0x90, 0xd9, 0x90, 0x14, 0x15, 0xd0, 0x5c, 0xb1, 0x64, 0x7c, 0x44, 0x6c],
|
|
6700
6840
|
},
|
|
6701
6841
|
});
|
|
6842
|
+
expect(controller.getDeviceByIeeeAddr("0x00000000017171f8")?.genBasic.modelId).toStrictEqual("GreenPower_2");
|
|
6702
6843
|
expect(events.deviceInterview.length).toBe(3); // gpp[started] + gpp[successful] + gpd
|
|
6703
6844
|
expect(deepClone(events.deviceInterview[2])).toStrictEqual({
|
|
6704
6845
|
status: "successful",
|
|
@@ -6712,13 +6853,16 @@ describe("Controller", () => {
|
|
|
6712
6853
|
_endpoints: [],
|
|
6713
6854
|
_ieeeAddr: "0x00000000017171f8",
|
|
6714
6855
|
_interviewState: InterviewState.Successful,
|
|
6715
|
-
_modelID: "GreenPower_2",
|
|
6716
6856
|
_networkAddress: 0x71f8,
|
|
6717
6857
|
_type: "GreenPower",
|
|
6718
6858
|
meta: {},
|
|
6719
6859
|
_gpSecurityKey: [0x21, 0x7f, 0x8c, 0xb2, 0x90, 0xd9, 0x90, 0x14, 0x15, 0xd0, 0x5c, 0xb1, 0x64, 0x7c, 0x44, 0x6c],
|
|
6720
6860
|
},
|
|
6721
6861
|
});
|
|
6862
|
+
expect(deepClone(events.deviceInterviewRaw[2].device.genBasic)).toStrictEqual({
|
|
6863
|
+
modelId: "GreenPower_2",
|
|
6864
|
+
powerSource: Zcl.PowerSource.Unknown,
|
|
6865
|
+
});
|
|
6722
6866
|
expect(controller.getDeviceByIeeeAddr("0x00000000017171f8")!.networkAddress).toBe(0x71f8);
|
|
6723
6867
|
expect(events.message.length).toBe(2);
|
|
6724
6868
|
|
|
@@ -6818,12 +6962,12 @@ describe("Controller", () => {
|
|
|
6818
6962
|
_interviewState: InterviewState.Successful,
|
|
6819
6963
|
_lastSeen: Date.now(),
|
|
6820
6964
|
_linkquality: 50,
|
|
6821
|
-
_modelID: "GreenPower_2",
|
|
6822
6965
|
_networkAddress: 0x71f8,
|
|
6823
6966
|
_type: "GreenPower",
|
|
6824
6967
|
meta: {},
|
|
6825
6968
|
_gpSecurityKey: [0x21, 0x7f, 0x8c, 0xb2, 0x90, 0xd9, 0x90, 0x14, 0x15, 0xd0, 0x5c, 0xb1, 0x64, 0x7c, 0x44, 0x6c],
|
|
6826
6969
|
});
|
|
6970
|
+
expect(Device.byIeeeAddr("0x00000000017171f8", true)?.genBasic.modelId).toStrictEqual("GreenPower_2");
|
|
6827
6971
|
|
|
6828
6972
|
// Re-add device
|
|
6829
6973
|
vi.spyOn(Zcl.Frame, "fromBuffer").mockReturnValueOnce(expectedFrame); // Mock because no Buffalo write for 0xe0 is implemented
|
|
@@ -6865,12 +7009,12 @@ describe("Controller", () => {
|
|
|
6865
7009
|
_interviewState: InterviewState.Successful,
|
|
6866
7010
|
_lastSeen: Date.now(),
|
|
6867
7011
|
_linkquality: 50,
|
|
6868
|
-
_modelID: "GreenPower_2",
|
|
6869
7012
|
_networkAddress: 0x71f8,
|
|
6870
7013
|
_type: "GreenPower",
|
|
6871
7014
|
meta: {},
|
|
6872
7015
|
_gpSecurityKey: [0x21, 0x7f, 0x8c, 0xb2, 0x90, 0xd9, 0x90, 0x14, 0x15, 0xd0, 0x5c, 0xb1, 0x64, 0x7c, 0x44, 0x6c],
|
|
6873
7016
|
});
|
|
7017
|
+
expect(Device.byIeeeAddr("0x00000000017171f8")?.genBasic.modelId).toStrictEqual("GreenPower_2");
|
|
6874
7018
|
});
|
|
6875
7019
|
|
|
6876
7020
|
it("Get input/ouptut clusters", async () => {
|
|
@@ -7455,7 +7599,7 @@ describe("Controller", () => {
|
|
|
7455
7599
|
expect(checkinrsp[2]).toBe(1);
|
|
7456
7600
|
expect(checkinrsp[3].cluster.name).toBe("genPollCtrl");
|
|
7457
7601
|
expect(checkinrsp[3].command.name).toBe("checkinRsp");
|
|
7458
|
-
expect(checkinrsp[3].payload).toStrictEqual({startFastPolling:
|
|
7602
|
+
expect(checkinrsp[3].payload).toStrictEqual({startFastPolling: 1, fastPollTimeout: 0});
|
|
7459
7603
|
|
|
7460
7604
|
expect(await result).toBe(undefined);
|
|
7461
7605
|
|
|
@@ -8223,6 +8367,12 @@ describe("Controller", () => {
|
|
|
8223
8367
|
});
|
|
8224
8368
|
|
|
8225
8369
|
it("reads/writes to group with custom cluster when common to all members", async () => {
|
|
8370
|
+
interface CustomManuHerdsman {
|
|
8371
|
+
attributes: {customAttr: number};
|
|
8372
|
+
commands: never;
|
|
8373
|
+
commandResponses: never;
|
|
8374
|
+
}
|
|
8375
|
+
|
|
8226
8376
|
await controller.start();
|
|
8227
8377
|
await mockAdapterEvents.deviceJoined({networkAddress: 177, ieeeAddr: "0x177"});
|
|
8228
8378
|
|
|
@@ -8239,8 +8389,8 @@ describe("Controller", () => {
|
|
|
8239
8389
|
|
|
8240
8390
|
group.addMember(device.getEndpoint(1)!);
|
|
8241
8391
|
|
|
8242
|
-
await group.write("manuHerdsman", {customAttr: 15}, {});
|
|
8243
|
-
await group.read("manuHerdsman", ["customAttr"], {});
|
|
8392
|
+
await group.write<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", {customAttr: 15}, {});
|
|
8393
|
+
await group.read<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", ["customAttr"], {});
|
|
8244
8394
|
|
|
8245
8395
|
expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(2);
|
|
8246
8396
|
expect(mocksendZclFrameToGroup.mock.calls[0][0]).toBe(34);
|
|
@@ -8299,22 +8449,22 @@ describe("Controller", () => {
|
|
|
8299
8449
|
await group.read("manuHerdsman", ["customAttr"], {});
|
|
8300
8450
|
}).rejects.toThrow(new Error(`Cluster with name 'manuHerdsman' does not exist`));
|
|
8301
8451
|
|
|
8302
|
-
await group.write("manuHerdsman", {customAttr: 14}, {direction: Zcl.Direction.SERVER_TO_CLIENT});
|
|
8303
|
-
await group.read("manuHerdsman", ["customAttr"], {direction: Zcl.Direction.SERVER_TO_CLIENT});
|
|
8452
|
+
await group.write<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", {customAttr: 14}, {direction: Zcl.Direction.SERVER_TO_CLIENT});
|
|
8453
|
+
await group.read<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", ["customAttr"], {direction: Zcl.Direction.SERVER_TO_CLIENT});
|
|
8304
8454
|
|
|
8305
8455
|
expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(4);
|
|
8306
8456
|
|
|
8307
8457
|
group.removeMember(device2.getEndpoint(2)!);
|
|
8308
8458
|
|
|
8309
|
-
await group.write("manuHerdsman", {customAttr: 16}, {});
|
|
8310
|
-
await group.read("manuHerdsman", ["customAttr"], {});
|
|
8459
|
+
await group.write<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", {customAttr: 16}, {});
|
|
8460
|
+
await group.read<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", ["customAttr"], {});
|
|
8311
8461
|
|
|
8312
8462
|
expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(6);
|
|
8313
8463
|
|
|
8314
8464
|
group.addMember(device2.getEndpoint(1)!);
|
|
8315
8465
|
|
|
8316
|
-
await group.write("manuHerdsman", {customAttr: 8}, {});
|
|
8317
|
-
await group.read("manuHerdsman", ["customAttr"], {});
|
|
8466
|
+
await group.write<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", {customAttr: 8}, {});
|
|
8467
|
+
await group.read<"manuHerdsman", CustomManuHerdsman>("manuHerdsman", ["customAttr"], {});
|
|
8318
8468
|
|
|
8319
8469
|
expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(8);
|
|
8320
8470
|
|
|
@@ -8501,4 +8651,52 @@ describe("Controller", () => {
|
|
|
8501
8651
|
});
|
|
8502
8652
|
}).rejects.toThrow(new Error(`Cluster with name 'manuSpecificInovelli' does not exist`));
|
|
8503
8653
|
});
|
|
8654
|
+
|
|
8655
|
+
it("Updates a device genBasic properties", async () => {
|
|
8656
|
+
await controller.start();
|
|
8657
|
+
expect(databaseContents().includes("0x129")).toBeFalsy();
|
|
8658
|
+
await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
|
|
8659
|
+
|
|
8660
|
+
const device = controller.getDeviceByIeeeAddr("0x129")!;
|
|
8661
|
+
|
|
8662
|
+
expect(device.applicationVersion).toStrictEqual(2);
|
|
8663
|
+
expect(device.dateCode).toStrictEqual("201901");
|
|
8664
|
+
expect(device.hardwareVersion).toStrictEqual(3);
|
|
8665
|
+
expect(device.manufacturerName).toStrictEqual("KoenAndCo");
|
|
8666
|
+
expect(device.modelID).toStrictEqual("myModelID");
|
|
8667
|
+
expect(device.powerSource).toStrictEqual("Mains (single phase)");
|
|
8668
|
+
expect(device.softwareBuildID).toStrictEqual("1.01");
|
|
8669
|
+
expect(device.stackVersion).toStrictEqual(101);
|
|
8670
|
+
expect(device.zclVersion).toStrictEqual(1);
|
|
8671
|
+
|
|
8672
|
+
device.applicationVersion = 3;
|
|
8673
|
+
device.dateCode = "202501";
|
|
8674
|
+
device.hardwareVersion = 4;
|
|
8675
|
+
device.manufacturerName = "Test";
|
|
8676
|
+
device.modelID = "Me";
|
|
8677
|
+
device.powerSource = "DC Source";
|
|
8678
|
+
device.softwareBuildID = "2.01";
|
|
8679
|
+
device.stackVersion = 202;
|
|
8680
|
+
device.zclVersion = 2;
|
|
8681
|
+
|
|
8682
|
+
expect(device.applicationVersion).toStrictEqual(3);
|
|
8683
|
+
expect(device.dateCode).toStrictEqual("202501");
|
|
8684
|
+
expect(device.hardwareVersion).toStrictEqual(4);
|
|
8685
|
+
expect(device.manufacturerName).toStrictEqual("Test");
|
|
8686
|
+
expect(device.modelID).toStrictEqual("Me");
|
|
8687
|
+
expect(device.powerSource).toStrictEqual("DC Source");
|
|
8688
|
+
expect(device.softwareBuildID).toStrictEqual("2.01");
|
|
8689
|
+
expect(device.stackVersion).toStrictEqual(202);
|
|
8690
|
+
expect(device.zclVersion).toStrictEqual(2);
|
|
8691
|
+
|
|
8692
|
+
expect(device.genBasic.appVersion).toStrictEqual(3);
|
|
8693
|
+
expect(device.genBasic.dateCode).toStrictEqual("202501");
|
|
8694
|
+
expect(device.genBasic.hwVersion).toStrictEqual(4);
|
|
8695
|
+
expect(device.genBasic.manufacturerName).toStrictEqual("Test");
|
|
8696
|
+
expect(device.genBasic.modelId).toStrictEqual("Me");
|
|
8697
|
+
expect(device.genBasic.powerSource).toStrictEqual(Zcl.PowerSource["DC Source"]);
|
|
8698
|
+
expect(device.genBasic.swBuildId).toStrictEqual("2.01");
|
|
8699
|
+
expect(device.genBasic.stackVersion).toStrictEqual(202);
|
|
8700
|
+
expect(device.genBasic.zclVersion).toStrictEqual(2);
|
|
8701
|
+
});
|
|
8504
8702
|
});
|