zigbee-herdsman 4.5.0 → 5.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.
Files changed (40) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
  4. package/dist/controller/helpers/zclFrameConverter.js +2 -14
  5. package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
  6. package/dist/controller/model/device.js +3 -5
  7. package/dist/controller/model/device.js.map +1 -1
  8. package/dist/controller/model/endpoint.d.ts +1 -1
  9. package/dist/controller/model/endpoint.d.ts.map +1 -1
  10. package/dist/controller/model/endpoint.js +67 -43
  11. package/dist/controller/model/endpoint.js.map +1 -1
  12. package/dist/controller/model/group.d.ts.map +1 -1
  13. package/dist/controller/model/group.js +28 -17
  14. package/dist/controller/model/group.js.map +1 -1
  15. package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
  16. package/dist/zspec/zcl/buffaloZcl.js +5 -5
  17. package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
  18. package/dist/zspec/zcl/definition/tstype.d.ts +1 -2
  19. package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
  20. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  21. package/dist/zspec/zcl/utils.js +8 -30
  22. package/dist/zspec/zcl/utils.js.map +1 -1
  23. package/dist/zspec/zcl/zclFrame.d.ts +1 -1
  24. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  25. package/dist/zspec/zcl/zclFrame.js +8 -6
  26. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/controller/helpers/zclFrameConverter.ts +4 -12
  29. package/src/controller/model/device.ts +5 -5
  30. package/src/controller/model/endpoint.ts +86 -49
  31. package/src/controller/model/group.ts +33 -18
  32. package/src/zspec/zcl/buffaloZcl.ts +6 -4
  33. package/src/zspec/zcl/definition/tstype.ts +1 -2
  34. package/src/zspec/zcl/utils.ts +8 -35
  35. package/src/zspec/zcl/zclFrame.ts +10 -8
  36. package/test/controller.test.ts +352 -1360
  37. package/test/requests.bench.ts +5 -0
  38. package/test/zcl.test.ts +11 -15
  39. package/test/zspec/zcl/frame.test.ts +25 -25
  40. package/test/zspec/zcl/utils.test.ts +6 -14
@@ -211,21 +211,24 @@ const restoreMocksendZclFrameToEndpoint = () => {
211
211
  for (const item of frame.payload) {
212
212
  if (item.attrId !== 65314) {
213
213
  const attribute = cluster.getAttribute(item.attrId);
214
- if (frame.isCluster("ssIasZone") && item.attrId === 0) {
215
- iasZoneReadState170Count++;
216
- payload.push({
217
- attrId: item.attrId,
218
- dataType: attribute.type,
219
- attrData: iasZoneReadState170Count === 2 && enroll170 ? 1 : 0,
220
- status: 0,
221
- });
222
- } else {
223
- payload.push({
224
- attrId: item.attrId,
225
- dataType: attribute.type,
226
- attrData: MOCK_DEVICES[networkAddress]!.attributes![endpoint][attribute.name],
227
- status: 0,
228
- });
214
+
215
+ if (attribute) {
216
+ if (frame.isCluster("ssIasZone") && item.attrId === 0) {
217
+ iasZoneReadState170Count++;
218
+ payload.push({
219
+ attrId: item.attrId,
220
+ dataType: attribute.type,
221
+ attrData: iasZoneReadState170Count === 2 && enroll170 ? 1 : 0,
222
+ status: 0,
223
+ });
224
+ } else {
225
+ payload.push({
226
+ attrId: item.attrId,
227
+ dataType: attribute.type,
228
+ attrData: MOCK_DEVICES[networkAddress]!.attributes![endpoint][attribute.name],
229
+ status: 0,
230
+ });
231
+ }
229
232
  }
230
233
  }
231
234
  }
@@ -3040,218 +3043,21 @@ describe("Controller", () => {
3040
3043
  expect(call[0]).toBe("0x129");
3041
3044
  expect(call[1]).toBe(129);
3042
3045
  expect(call[2]).toBe(1);
3043
- expect(deepClone(call[3])).toStrictEqual({
3044
- header: {
3045
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
3046
- transactionSequenceNumber: 29,
3047
- commandIdentifier: 11,
3048
- },
3049
- payload: {cmdId: 1, statusCode: 0},
3050
- cluster: {
3051
- ID: 5,
3052
- attributes: {
3053
- count: {ID: 0, type: 32, name: "count"},
3054
- currentScene: {ID: 1, type: 32, name: "currentScene"},
3055
- currentGroup: {ID: 2, type: 33, name: "currentGroup"},
3056
- sceneValid: {ID: 3, type: 16, name: "sceneValid"},
3057
- nameSupport: {ID: 4, type: 24, name: "nameSupport"},
3058
- lastCfgBy: {ID: 5, type: 240, name: "lastCfgBy"},
3059
- },
3060
- name: "genScenes",
3061
- commands: {
3062
- add: {
3063
- ID: 0,
3064
- response: 0,
3065
- parameters: [
3066
- {name: "groupid", type: 33},
3067
- {name: "sceneid", type: 32},
3068
- {name: "transtime", type: 33},
3069
- {name: "scenename", type: 66},
3070
- {name: "extensionfieldsets", type: 1006},
3071
- ],
3072
- name: "add",
3073
- },
3074
- view: {
3075
- ID: 1,
3076
- response: 1,
3077
- parameters: [
3078
- {name: "groupid", type: 33},
3079
- {name: "sceneid", type: 32},
3080
- ],
3081
- name: "view",
3082
- },
3083
- remove: {
3084
- ID: 2,
3085
- response: 2,
3086
- parameters: [
3087
- {name: "groupid", type: 33},
3088
- {name: "sceneid", type: 32},
3089
- ],
3090
- name: "remove",
3091
- },
3092
- removeAll: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "removeAll"},
3093
- store: {
3094
- ID: 4,
3095
- response: 4,
3096
- parameters: [
3097
- {name: "groupid", type: 33},
3098
- {name: "sceneid", type: 32},
3099
- ],
3100
- name: "store",
3101
- },
3102
- recall: {
3103
- ID: 5,
3104
- parameters: [
3105
- {name: "groupid", type: 33},
3106
- {name: "sceneid", type: 32},
3107
- ],
3108
- name: "recall",
3109
- },
3110
- getSceneMembership: {ID: 6, response: 6, parameters: [{name: "groupid", type: 33}], name: "getSceneMembership"},
3111
- enhancedAdd: {
3112
- ID: 64,
3113
- response: 64,
3114
- parameters: [
3115
- {name: "groupid", type: 33},
3116
- {name: "sceneid", type: 32},
3117
- {name: "transtime", type: 33},
3118
- {name: "scenename", type: 66},
3119
- {name: "extensionfieldsets", type: 1006},
3120
- ],
3121
- name: "enhancedAdd",
3122
- },
3123
- enhancedView: {
3124
- ID: 65,
3125
- response: 65,
3126
- parameters: [
3127
- {name: "groupid", type: 33},
3128
- {name: "sceneid", type: 32},
3129
- ],
3130
- name: "enhancedView",
3131
- },
3132
- copy: {
3133
- ID: 66,
3134
- response: 66,
3135
- parameters: [
3136
- {name: "mode", type: 32},
3137
- {name: "groupidfrom", type: 33},
3138
- {name: "sceneidfrom", type: 32},
3139
- {name: "groupidto", type: 33},
3140
- {name: "sceneidto", type: 32},
3141
- ],
3142
- name: "copy",
3143
- },
3144
- tradfriArrowSingle: {
3145
- ID: 7,
3146
- parameters: [
3147
- {name: "value", type: 33},
3148
- {name: "value2", type: 33},
3149
- ],
3150
- name: "tradfriArrowSingle",
3151
- },
3152
- tradfriArrowHold: {ID: 8, parameters: [{name: "value", type: 33}], name: "tradfriArrowHold"},
3153
- tradfriArrowRelease: {ID: 9, parameters: [{name: "value", type: 33}], name: "tradfriArrowRelease"},
3154
- },
3155
- commandsResponse: {
3156
- addRsp: {
3157
- ID: 0,
3158
- parameters: [
3159
- {name: "status", type: 32},
3160
- {name: "groupId", type: 33},
3161
- {name: "sceneId", type: 32},
3162
- ],
3163
- name: "addRsp",
3164
- },
3165
- viewRsp: {
3166
- ID: 1,
3167
- parameters: [
3168
- {name: "status", type: 32},
3169
- {name: "groupid", type: 33},
3170
- {name: "sceneid", type: 32},
3171
- {name: "transtime", type: 33, conditions: [{type: "statusEquals", value: 0}]},
3172
- {name: "scenename", type: 66, conditions: [{type: "statusEquals", value: 0}]},
3173
- {name: "extensionfieldsets", type: 1006, conditions: [{type: "statusEquals", value: 0}]},
3174
- ],
3175
- name: "viewRsp",
3176
- },
3177
- removeRsp: {
3178
- ID: 2,
3179
- parameters: [
3180
- {name: "status", type: 32},
3181
- {name: "groupid", type: 33},
3182
- {name: "sceneid", type: 32},
3183
- ],
3184
- name: "removeRsp",
3185
- },
3186
- removeAllRsp: {
3187
- ID: 3,
3188
- parameters: [
3189
- {name: "status", type: 32},
3190
- {name: "groupid", type: 33},
3191
- ],
3192
- name: "removeAllRsp",
3193
- },
3194
- storeRsp: {
3195
- ID: 4,
3196
- parameters: [
3197
- {name: "status", type: 32},
3198
- {name: "groupid", type: 33},
3199
- {name: "sceneid", type: 32},
3200
- ],
3201
- name: "storeRsp",
3202
- },
3203
- getSceneMembershipRsp: {
3204
- ID: 6,
3205
- parameters: [
3206
- {name: "status", type: 32},
3207
- {name: "capacity", type: 32},
3208
- {name: "groupid", type: 33},
3209
- {name: "scenecount", type: 32, conditions: [{type: "statusEquals", value: 0}]},
3210
- {name: "scenelist", type: 1001, conditions: [{type: "statusEquals", value: 0}]},
3211
- ],
3212
- name: "getSceneMembershipRsp",
3213
- },
3214
- enhancedAddRsp: {
3215
- ID: 64,
3216
- parameters: [
3217
- {name: "status", type: 32},
3218
- {name: "groupId", type: 33},
3219
- {name: "sceneId", type: 32},
3220
- ],
3221
- name: "enhancedAddRsp",
3222
- },
3223
- enhancedViewRsp: {
3224
- ID: 65,
3225
- parameters: [
3226
- {name: "status", type: 32},
3227
- {name: "groupid", type: 33},
3228
- {name: "sceneid", type: 32},
3229
- {name: "transtime", type: 33, conditions: [{type: "statusEquals", value: 0}]},
3230
- {name: "scenename", type: 66, conditions: [{type: "statusEquals", value: 0}]},
3231
- {name: "extensionfieldsets", type: 1006, conditions: [{type: "statusEquals", value: 0}]},
3232
- ],
3233
- name: "enhancedViewRsp",
3234
- },
3235
- copyRsp: {
3236
- ID: 66,
3237
- parameters: [
3238
- {name: "status", type: 32},
3239
- {name: "groupidfrom", type: 33},
3240
- {name: "sceneidfrom", type: 32},
3241
- ],
3242
- name: "copyRsp",
3243
- },
3244
- },
3245
- },
3246
- command: {
3247
- ID: 11,
3248
- name: "defaultRsp",
3249
- parameters: [
3250
- {name: "cmdId", type: 32},
3251
- {name: "statusCode", type: 32},
3252
- ],
3253
- },
3254
- });
3046
+ expect(deepClone(call[3])).toStrictEqual(
3047
+ deepClone(
3048
+ Zcl.Frame.create(
3049
+ Zcl.FrameType.GLOBAL,
3050
+ Zcl.Direction.CLIENT_TO_SERVER,
3051
+ true,
3052
+ undefined,
3053
+ 29,
3054
+ "defaultRsp",
3055
+ 5,
3056
+ {cmdId: 1, statusCode: 0},
3057
+ {},
3058
+ ),
3059
+ ),
3060
+ );
3255
3061
  });
3256
3062
 
3257
3063
  it("Receive zclData dont send default resopnse with skipDefaultResponse", async () => {
@@ -3410,41 +3216,9 @@ describe("Controller", () => {
3410
3216
  expect(call[0]).toBe("0x129");
3411
3217
  expect(call[1]).toBe(129);
3412
3218
  expect(call[2]).toBe(1);
3413
- expect(deepClone(call[3])).toStrictEqual({
3414
- header: {
3415
- frameControl: {reservedBits: 0, frameType: 0, direction: 1, disableDefaultResponse: true, manufacturerSpecific: false},
3416
- transactionSequenceNumber: 40,
3417
- commandIdentifier: 1,
3418
- },
3419
- cluster: {
3420
- ID: 10,
3421
- attributes: {
3422
- time: {ID: 0, type: 226, name: "time"},
3423
- timeStatus: {ID: 1, type: 24, name: "timeStatus"},
3424
- timeZone: {ID: 2, type: 43, name: "timeZone"},
3425
- dstStart: {ID: 3, type: 35, name: "dstStart"},
3426
- dstEnd: {ID: 4, type: 35, name: "dstEnd"},
3427
- dstShift: {ID: 5, type: 43, name: "dstShift"},
3428
- standardTime: {ID: 6, type: 35, name: "standardTime"},
3429
- localTime: {ID: 7, type: 35, name: "localTime"},
3430
- lastSetTime: {ID: 8, type: 226, name: "lastSetTime"},
3431
- validUntilTime: {ID: 9, type: 226, name: "validUntilTime"},
3432
- },
3433
- name: "genTime",
3434
- commands: {},
3435
- commandsResponse: {},
3436
- },
3437
- command: {
3438
- ID: 1,
3439
- name: "readRsp",
3440
- parameters: [
3441
- {name: "attrId", type: 33},
3442
- {name: "status", type: 32},
3443
- {name: "dataType", type: 32, conditions: [{type: "statusEquals", value: 0}]},
3444
- {name: "attrData", type: 1000, conditions: [{type: "statusEquals", value: 0}]},
3445
- ],
3446
- },
3447
- });
3219
+ expect(deepClone(call[3])).toStrictEqual(
3220
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.SERVER_TO_CLIENT, true, undefined, 40, "readRsp", 10, undefined, {})),
3221
+ );
3448
3222
  });
3449
3223
 
3450
3224
  it("Allow to override read response through `device.customReadResponse", async () => {
@@ -4142,88 +3916,9 @@ describe("Controller", () => {
4142
3916
  expect(call[0]).toBe("0x129");
4143
3917
  expect(call[1]).toBe(129);
4144
3918
  expect(call[2]).toBe(1);
4145
- expect(deepClone(call[3])).toStrictEqual({
4146
- header: {
4147
- frameControl: {reservedBits: 0, frameType: 1, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
4148
- transactionSequenceNumber: 12,
4149
- commandIdentifier: 3,
4150
- },
4151
- payload: {groupid: 4},
4152
- cluster: {
4153
- ID: 4,
4154
- attributes: {nameSupport: {ID: 0, type: 24, name: "nameSupport"}},
4155
- name: "genGroups",
4156
- commands: {
4157
- add: {
4158
- ID: 0,
4159
- response: 0,
4160
- parameters: [
4161
- {name: "groupid", type: 33},
4162
- {name: "groupname", type: 66},
4163
- ],
4164
- name: "add",
4165
- },
4166
- view: {ID: 1, response: 1, parameters: [{name: "groupid", type: 33}], name: "view"},
4167
- getMembership: {
4168
- ID: 2,
4169
- response: 2,
4170
- parameters: [
4171
- {name: "groupcount", type: 32},
4172
- {name: "grouplist", type: 1002},
4173
- ],
4174
- name: "getMembership",
4175
- },
4176
- miboxerSetZones: {ID: 240, name: "miboxerSetZones", parameters: [{name: "zones", type: 1012}]},
4177
- remove: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
4178
- removeAll: {ID: 4, parameters: [], name: "removeAll"},
4179
- addIfIdentifying: {
4180
- ID: 5,
4181
- parameters: [
4182
- {name: "groupid", type: 33},
4183
- {name: "groupname", type: 66},
4184
- ],
4185
- name: "addIfIdentifying",
4186
- },
4187
- },
4188
- commandsResponse: {
4189
- addRsp: {
4190
- ID: 0,
4191
- parameters: [
4192
- {name: "status", type: 32},
4193
- {name: "groupid", type: 33},
4194
- ],
4195
- name: "addRsp",
4196
- },
4197
- viewRsp: {
4198
- ID: 1,
4199
- parameters: [
4200
- {name: "status", type: 32},
4201
- {name: "groupid", type: 33},
4202
- {name: "groupname", type: 66},
4203
- ],
4204
- name: "viewRsp",
4205
- },
4206
- getMembershipRsp: {
4207
- ID: 2,
4208
- parameters: [
4209
- {name: "capacity", type: 32},
4210
- {name: "groupcount", type: 32},
4211
- {name: "grouplist", type: 1002},
4212
- ],
4213
- name: "getMembershipRsp",
4214
- },
4215
- removeRsp: {
4216
- ID: 3,
4217
- parameters: [
4218
- {name: "status", type: 32},
4219
- {name: "groupid", type: 33},
4220
- ],
4221
- name: "removeRsp",
4222
- },
4223
- },
4224
- },
4225
- command: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
4226
- });
3919
+ expect(deepClone(call[3])).toStrictEqual(
3920
+ deepClone(Zcl.Frame.create(Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 12, "remove", 4, {groupid: 4}, {})),
3921
+ );
4227
3922
  });
4228
3923
 
4229
3924
  it("Remove group from database", async () => {
@@ -4272,48 +3967,9 @@ describe("Controller", () => {
4272
3967
  expect(call[0]).toBe("0x176");
4273
3968
  expect(call[1]).toBe(176);
4274
3969
  expect(call[2]).toBe(1);
4275
- expect(deepClone(call[3])).toStrictEqual({
4276
- header: {
4277
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
4278
- transactionSequenceNumber: 2,
4279
- commandIdentifier: 0,
4280
- },
4281
- payload: [{attrId: 0}],
4282
- cluster: {
4283
- ID: 0,
4284
- attributes: {
4285
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
4286
- appVersion: {ID: 1, type: 32, name: "appVersion"},
4287
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
4288
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
4289
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
4290
- modelId: {ID: 5, type: 66, name: "modelId"},
4291
- dateCode: {ID: 6, type: 66, name: "dateCode"},
4292
- powerSource: {ID: 7, type: 48, name: "powerSource"},
4293
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
4294
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
4295
- productCode: {ID: 10, type: 65, name: "productCode"},
4296
- productUrl: {ID: 11, type: 66, name: "productUrl"},
4297
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
4298
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
4299
- productLabel: {ID: 14, type: 66, name: "productLabel"},
4300
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
4301
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
4302
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
4303
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
4304
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
4305
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
4306
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
4307
- },
4308
- name: "genBasic",
4309
- commands: {
4310
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
4311
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
4312
- },
4313
- commandsResponse: {},
4314
- },
4315
- command: {ID: 0, name: "read", parameters: [{name: "attrId", type: 33}], response: 1},
4316
- });
3970
+ expect(deepClone(call[3])).toStrictEqual(
3971
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 2, "read", 0, [{attrId: 0}], {})),
3972
+ );
4317
3973
  expect(call[4]).toBe(10000);
4318
3974
  expect(call[5]).toBe(false);
4319
3975
  expect(call[6]).toBe(true);
@@ -4627,66 +4283,21 @@ describe("Controller", () => {
4627
4283
  expect(call[0]).toBe("0x129");
4628
4284
  expect(call[1]).toBe(129);
4629
4285
  expect(call[2]).toBe(1);
4630
- expect(deepClone(call[3])).toStrictEqual({
4631
- header: {
4632
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
4633
- transactionSequenceNumber: 11,
4634
- commandIdentifier: 6,
4635
- },
4636
- payload: [{direction: 0, attrId: 1, dataType: 32, minRepIntval: 1, maxRepIntval: 10, repChange: 1}],
4637
- cluster: {
4638
- ID: 1,
4639
- attributes: {
4640
- mainsVoltage: {ID: 0, type: 33, name: "mainsVoltage"},
4641
- mainsFrequency: {ID: 1, type: 32, name: "mainsFrequency"},
4642
- mainsAlarmMask: {ID: 16, type: 24, name: "mainsAlarmMask"},
4643
- mainsVoltMinThres: {ID: 17, type: 33, name: "mainsVoltMinThres"},
4644
- mainsVoltMaxThres: {ID: 18, type: 33, name: "mainsVoltMaxThres"},
4645
- mainsVoltageDwellTripPoint: {ID: 19, type: 33, name: "mainsVoltageDwellTripPoint"},
4646
- batteryVoltage: {ID: 32, type: 32, name: "batteryVoltage"},
4647
- batteryPercentageRemaining: {ID: 33, type: 32, name: "batteryPercentageRemaining"},
4648
- batteryManufacturer: {ID: 48, type: 66, name: "batteryManufacturer"},
4649
- batterySize: {ID: 49, type: 48, name: "batterySize"},
4650
- batteryAHrRating: {ID: 50, type: 33, name: "batteryAHrRating"},
4651
- batteryQuantity: {ID: 51, type: 32, name: "batteryQuantity"},
4652
- batteryRatedVoltage: {ID: 52, type: 32, name: "batteryRatedVoltage"},
4653
- batteryAlarmMask: {ID: 53, type: 24, name: "batteryAlarmMask"},
4654
- batteryVoltMinThres: {ID: 54, type: 32, name: "batteryVoltMinThres"},
4655
- batteryVoltThres1: {ID: 55, type: 32, name: "batteryVoltThres1"},
4656
- batteryVoltThres2: {ID: 56, type: 32, name: "batteryVoltThres2"},
4657
- batteryVoltThres3: {ID: 57, type: 32, name: "batteryVoltThres3"},
4658
- batteryPercentMinThres: {ID: 58, type: 32, name: "batteryPercentMinThres"},
4659
- batteryPercentThres1: {ID: 59, type: 32, name: "batteryPercentThres1"},
4660
- batteryPercentThres2: {ID: 60, type: 32, name: "batteryPercentThres2"},
4661
- batteryPercentThres3: {ID: 61, type: 32, name: "batteryPercentThres3"},
4662
- batteryAlarmState: {ID: 62, type: 27, name: "batteryAlarmState"},
4663
- },
4664
- name: "genPowerCfg",
4665
- commands: {},
4666
- commandsResponse: {},
4667
- },
4668
- command: {
4669
- ID: 6,
4670
- name: "configReport",
4671
- parameters: [
4672
- {name: "direction", type: 32},
4673
- {name: "attrId", type: 33},
4674
- {name: "dataType", type: 32, conditions: [{type: "directionEquals", value: 0}]},
4675
- {name: "minRepIntval", type: 33, conditions: [{type: "directionEquals", value: 0}]},
4676
- {name: "maxRepIntval", type: 33, conditions: [{type: "directionEquals", value: 0}]},
4677
- {
4678
- name: "repChange",
4679
- type: 1000,
4680
- conditions: [
4681
- {type: "directionEquals", value: 0},
4682
- {type: "dataTypeValueTypeEquals", value: "ANALOG"},
4683
- ],
4684
- },
4685
- {name: "timeout", type: 33, conditions: [{type: "directionEquals", value: 1}]},
4686
- ],
4687
- response: 7,
4688
- },
4689
- });
4286
+ expect(deepClone(call[3])).toStrictEqual(
4287
+ deepClone(
4288
+ Zcl.Frame.create(
4289
+ Zcl.FrameType.GLOBAL,
4290
+ Zcl.Direction.CLIENT_TO_SERVER,
4291
+ true,
4292
+ undefined,
4293
+ 11,
4294
+ "configReport",
4295
+ 1,
4296
+ [{direction: 0, attrId: 1, dataType: 32, minRepIntval: 1, maxRepIntval: 10, repChange: 1}],
4297
+ {},
4298
+ ),
4299
+ ),
4300
+ );
4690
4301
  });
4691
4302
 
4692
4303
  it("Should replace legacy configured reportings without manufacturerCode", async () => {
@@ -4738,37 +4349,21 @@ describe("Controller", () => {
4738
4349
  expect(call[0]).toBe("0x129");
4739
4350
  expect(call[1]).toBe(129);
4740
4351
  expect(call[2]).toBe(1);
4741
- expect({...deepClone(call[3]), cluster: {}}).toStrictEqual({
4742
- cluster: {},
4743
- command: {
4744
- ID: 6,
4745
- name: "configReport",
4746
- parameters: [
4747
- {name: "direction", type: 32},
4748
- {name: "attrId", type: 33},
4749
- {conditions: [{type: "directionEquals", value: 0}], name: "dataType", type: 32},
4750
- {conditions: [{type: "directionEquals", value: 0}], name: "minRepIntval", type: 33},
4751
- {conditions: [{type: "directionEquals", value: 0}], name: "maxRepIntval", type: 33},
4752
- {
4753
- conditions: [
4754
- {type: "directionEquals", value: 0},
4755
- {type: "dataTypeValueTypeEquals", value: "ANALOG"},
4756
- ],
4757
- name: "repChange",
4758
- type: 1000,
4759
- },
4760
- {conditions: [{type: "directionEquals", value: 1}], name: "timeout", type: 33},
4761
- ],
4762
- response: 7,
4763
- },
4764
- header: {
4765
- commandIdentifier: 6,
4766
- frameControl: {direction: 0, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: true, reservedBits: 0},
4767
- manufacturerCode: 4641,
4768
- transactionSequenceNumber: 11,
4769
- },
4770
- payload: [{attrId: 16384, dataType: 48, direction: 0, maxRepIntval: 10, minRepIntval: 1, repChange: 1}],
4771
- });
4352
+ expect(deepClone(call[3])).toStrictEqual(
4353
+ deepClone(
4354
+ Zcl.Frame.create(
4355
+ Zcl.FrameType.GLOBAL,
4356
+ Zcl.Direction.CLIENT_TO_SERVER,
4357
+ true,
4358
+ 4641,
4359
+ 11,
4360
+ "configReport",
4361
+ 513,
4362
+ [{attrId: 16384, dataType: 48, direction: 0, maxRepIntval: 10, minRepIntval: 1, repChange: 1}],
4363
+ {},
4364
+ ),
4365
+ ),
4366
+ );
4772
4367
 
4773
4368
  expect(endpoint.configuredReportings.length).toBe(1);
4774
4369
  expect({...endpoint.configuredReportings[0], cluster: undefined}).toStrictEqual({
@@ -4785,7 +4380,7 @@ describe("Controller", () => {
4785
4380
  await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
4786
4381
  const device = controller.getDeviceByIeeeAddr("0x129")!;
4787
4382
  // @ts-expect-error private
4788
- device._manufacturerID = 0x10f2;
4383
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
4789
4384
  const endpoint = device.getEndpoint(1)!;
4790
4385
  mocksendZclFrameToEndpoint.mockClear();
4791
4386
  await endpoint.configureReporting("hvacThermostat", [
@@ -4801,37 +4396,21 @@ describe("Controller", () => {
4801
4396
  expect(call[0]).toBe("0x129");
4802
4397
  expect(call[1]).toBe(129);
4803
4398
  expect(call[2]).toBe(1);
4804
- expect({...deepClone(call[3]), cluster: {}}).toStrictEqual({
4805
- cluster: {},
4806
- command: {
4807
- ID: 6,
4808
- name: "configReport",
4809
- parameters: [
4810
- {name: "direction", type: 32},
4811
- {name: "attrId", type: 33},
4812
- {conditions: [{type: "directionEquals", value: 0}], name: "dataType", type: 32},
4813
- {conditions: [{type: "directionEquals", value: 0}], name: "minRepIntval", type: 33},
4814
- {conditions: [{type: "directionEquals", value: 0}], name: "maxRepIntval", type: 33},
4815
- {
4816
- conditions: [
4817
- {type: "directionEquals", value: 0},
4818
- {type: "dataTypeValueTypeEquals", value: "ANALOG"},
4819
- ],
4820
- name: "repChange",
4821
- type: 1000,
4822
- },
4823
- {conditions: [{type: "directionEquals", value: 1}], name: "timeout", type: 33},
4824
- ],
4825
- response: 7,
4826
- },
4827
- header: {
4828
- commandIdentifier: 6,
4829
- frameControl: {direction: 0, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: true, reservedBits: 0},
4830
- manufacturerCode: 4641,
4831
- transactionSequenceNumber: 11,
4832
- },
4833
- payload: [{attrId: 16384, dataType: 48, direction: 0, maxRepIntval: 10, minRepIntval: 1, repChange: 1}],
4834
- });
4399
+ expect(deepClone(call[3])).toStrictEqual(
4400
+ deepClone(
4401
+ Zcl.Frame.create(
4402
+ Zcl.FrameType.GLOBAL,
4403
+ Zcl.Direction.CLIENT_TO_SERVER,
4404
+ true,
4405
+ 4641,
4406
+ 11,
4407
+ "configReport",
4408
+ 513,
4409
+ [{attrId: 16384, dataType: 48, direction: 0, maxRepIntval: 10, minRepIntval: 1, repChange: 1}],
4410
+ {},
4411
+ ),
4412
+ ),
4413
+ );
4835
4414
 
4836
4415
  expect(endpoint.configuredReportings.length).toBe(1);
4837
4416
  expect({...endpoint.configuredReportings[0], cluster: undefined}).toStrictEqual({
@@ -4848,7 +4427,7 @@ describe("Controller", () => {
4848
4427
  await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
4849
4428
  const device = controller.getDeviceByIeeeAddr("0x129")!;
4850
4429
  // @ts-expect-error private
4851
- device._manufacturerID = 0x10f2;
4430
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
4852
4431
  const endpoint = device.getEndpoint(1)!;
4853
4432
  mocksendZclFrameToEndpoint.mockClear();
4854
4433
  let error;
@@ -5003,24 +4582,19 @@ describe("Controller", () => {
5003
4582
  const device = controller.getDeviceByIeeeAddr("0x129")!;
5004
4583
  const endpoint = device.getEndpoint(1)!;
5005
4584
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
5006
- let error;
5007
- try {
5008
- await endpoint.configureReporting(
5009
- "genPowerCfg",
5010
- [
5011
- {
5012
- attribute: "mainsFrequency",
5013
- minimumReportInterval: 1,
5014
- maximumReportInterval: 10,
5015
- reportableChange: 1,
5016
- },
5017
- ],
5018
- {disableResponse: true},
5019
- );
5020
- } catch (e) {
5021
- error = e;
5022
- }
5023
- expect(error).toBeUndefined();
4585
+
4586
+ await endpoint.configureReporting(
4587
+ "genPowerCfg",
4588
+ [
4589
+ {
4590
+ attribute: "mainsFrequency",
4591
+ minimumReportInterval: 1,
4592
+ maximumReportInterval: 10,
4593
+ reportableChange: 1,
4594
+ },
4595
+ ],
4596
+ {disableResponse: true},
4597
+ );
5024
4598
  });
5025
4599
 
5026
4600
  it("Return group from databse when not in lookup", async () => {
@@ -5054,96 +4628,21 @@ describe("Controller", () => {
5054
4628
  expect(call[0]).toBe("0x129");
5055
4629
  expect(call[1]).toBe(129);
5056
4630
  expect(call[2]).toBe(1);
5057
- expect(deepClone(call[3])).toStrictEqual({
5058
- header: {
5059
- frameControl: {reservedBits: 0, frameType: 1, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
5060
- transactionSequenceNumber: 11,
5061
- commandIdentifier: 0,
5062
- },
5063
- payload: {groupid: 2, groupname: ""},
5064
- cluster: {
5065
- ID: 4,
5066
- attributes: {nameSupport: {ID: 0, type: 24, name: "nameSupport"}},
5067
- name: "genGroups",
5068
- commands: {
5069
- add: {
5070
- ID: 0,
5071
- response: 0,
5072
- parameters: [
5073
- {name: "groupid", type: 33},
5074
- {name: "groupname", type: 66},
5075
- ],
5076
- name: "add",
5077
- },
5078
- view: {ID: 1, response: 1, parameters: [{name: "groupid", type: 33}], name: "view"},
5079
- getMembership: {
5080
- ID: 2,
5081
- response: 2,
5082
- parameters: [
5083
- {name: "groupcount", type: 32},
5084
- {name: "grouplist", type: 1002},
5085
- ],
5086
- name: "getMembership",
5087
- },
5088
- miboxerSetZones: {ID: 240, name: "miboxerSetZones", parameters: [{name: "zones", type: 1012}]},
5089
- remove: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
5090
- removeAll: {ID: 4, parameters: [], name: "removeAll"},
5091
- addIfIdentifying: {
5092
- ID: 5,
5093
- parameters: [
5094
- {name: "groupid", type: 33},
5095
- {name: "groupname", type: 66},
5096
- ],
5097
- name: "addIfIdentifying",
5098
- },
5099
- },
5100
- commandsResponse: {
5101
- addRsp: {
5102
- ID: 0,
5103
- parameters: [
5104
- {name: "status", type: 32},
5105
- {name: "groupid", type: 33},
5106
- ],
5107
- name: "addRsp",
5108
- },
5109
- viewRsp: {
5110
- ID: 1,
5111
- parameters: [
5112
- {name: "status", type: 32},
5113
- {name: "groupid", type: 33},
5114
- {name: "groupname", type: 66},
5115
- ],
5116
- name: "viewRsp",
5117
- },
5118
- getMembershipRsp: {
5119
- ID: 2,
5120
- parameters: [
5121
- {name: "capacity", type: 32},
5122
- {name: "groupcount", type: 32},
5123
- {name: "grouplist", type: 1002},
5124
- ],
5125
- name: "getMembershipRsp",
5126
- },
5127
- removeRsp: {
5128
- ID: 3,
5129
- parameters: [
5130
- {name: "status", type: 32},
5131
- {name: "groupid", type: 33},
5132
- ],
5133
- name: "removeRsp",
5134
- },
5135
- },
5136
- },
5137
- command: {
5138
- ID: 0,
5139
- response: 0,
5140
- parameters: [
5141
- {name: "groupid", type: 33},
5142
- {name: "groupname", type: 66},
5143
- ],
5144
- name: "add",
5145
- },
5146
- });
4631
+ expect(deepClone(call[3])).toStrictEqual(
4632
+ deepClone(
4633
+ Zcl.Frame.create(
4634
+ Zcl.FrameType.SPECIFIC,
4635
+ Zcl.Direction.CLIENT_TO_SERVER,
4636
+ true,
4637
+ undefined,
4638
+ 11,
4639
+ "add",
4640
+ 4,
4641
+ {groupid: 2, groupname: ""},
4642
+ {},
4643
+ ),
4644
+ ),
4645
+ );
5147
4646
  expect(group.members).toContain(endpoint);
5148
4647
  expect(databaseContents()).toContain(
5149
4648
  `
@@ -5170,88 +4669,9 @@ describe("Controller", () => {
5170
4669
  expect(call[0]).toBe("0x129");
5171
4670
  expect(call[1]).toBe(129);
5172
4671
  expect(call[2]).toBe(1);
5173
- expect(deepClone(call[3])).toStrictEqual({
5174
- header: {
5175
- frameControl: {reservedBits: 0, frameType: 1, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
5176
- transactionSequenceNumber: 11,
5177
- commandIdentifier: 3,
5178
- },
5179
- payload: {groupid: 2},
5180
- cluster: {
5181
- ID: 4,
5182
- attributes: {nameSupport: {ID: 0, type: 24, name: "nameSupport"}},
5183
- name: "genGroups",
5184
- commands: {
5185
- add: {
5186
- ID: 0,
5187
- response: 0,
5188
- parameters: [
5189
- {name: "groupid", type: 33},
5190
- {name: "groupname", type: 66},
5191
- ],
5192
- name: "add",
5193
- },
5194
- view: {ID: 1, response: 1, parameters: [{name: "groupid", type: 33}], name: "view"},
5195
- getMembership: {
5196
- ID: 2,
5197
- response: 2,
5198
- parameters: [
5199
- {name: "groupcount", type: 32},
5200
- {name: "grouplist", type: 1002},
5201
- ],
5202
- name: "getMembership",
5203
- },
5204
- miboxerSetZones: {ID: 240, name: "miboxerSetZones", parameters: [{name: "zones", type: 1012}]},
5205
- remove: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
5206
- removeAll: {ID: 4, parameters: [], name: "removeAll"},
5207
- addIfIdentifying: {
5208
- ID: 5,
5209
- parameters: [
5210
- {name: "groupid", type: 33},
5211
- {name: "groupname", type: 66},
5212
- ],
5213
- name: "addIfIdentifying",
5214
- },
5215
- },
5216
- commandsResponse: {
5217
- addRsp: {
5218
- ID: 0,
5219
- parameters: [
5220
- {name: "status", type: 32},
5221
- {name: "groupid", type: 33},
5222
- ],
5223
- name: "addRsp",
5224
- },
5225
- viewRsp: {
5226
- ID: 1,
5227
- parameters: [
5228
- {name: "status", type: 32},
5229
- {name: "groupid", type: 33},
5230
- {name: "groupname", type: 66},
5231
- ],
5232
- name: "viewRsp",
5233
- },
5234
- getMembershipRsp: {
5235
- ID: 2,
5236
- parameters: [
5237
- {name: "capacity", type: 32},
5238
- {name: "groupcount", type: 32},
5239
- {name: "grouplist", type: 1002},
5240
- ],
5241
- name: "getMembershipRsp",
5242
- },
5243
- removeRsp: {
5244
- ID: 3,
5245
- parameters: [
5246
- {name: "status", type: 32},
5247
- {name: "groupid", type: 33},
5248
- ],
5249
- name: "removeRsp",
5250
- },
5251
- },
5252
- },
5253
- command: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
5254
- });
4672
+ expect(deepClone(call[3])).toStrictEqual(
4673
+ deepClone(Zcl.Frame.create(Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 11, "remove", 4, {groupid: 2}, {})),
4674
+ );
5255
4675
  expect(group.members).toStrictEqual([]);
5256
4676
  });
5257
4677
 
@@ -5266,88 +4686,9 @@ describe("Controller", () => {
5266
4686
  expect(call[0]).toBe("0x129");
5267
4687
  expect(call[1]).toBe(129);
5268
4688
  expect(call[2]).toBe(1);
5269
- expect(deepClone(call[3])).toStrictEqual({
5270
- header: {
5271
- frameControl: {reservedBits: 0, frameType: 1, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
5272
- transactionSequenceNumber: 11,
5273
- commandIdentifier: 3,
5274
- },
5275
- payload: {groupid: 4},
5276
- cluster: {
5277
- ID: 4,
5278
- attributes: {nameSupport: {ID: 0, type: 24, name: "nameSupport"}},
5279
- name: "genGroups",
5280
- commands: {
5281
- add: {
5282
- ID: 0,
5283
- response: 0,
5284
- parameters: [
5285
- {name: "groupid", type: 33},
5286
- {name: "groupname", type: 66},
5287
- ],
5288
- name: "add",
5289
- },
5290
- view: {ID: 1, response: 1, parameters: [{name: "groupid", type: 33}], name: "view"},
5291
- getMembership: {
5292
- ID: 2,
5293
- response: 2,
5294
- parameters: [
5295
- {name: "groupcount", type: 32},
5296
- {name: "grouplist", type: 1002},
5297
- ],
5298
- name: "getMembership",
5299
- },
5300
- miboxerSetZones: {ID: 240, name: "miboxerSetZones", parameters: [{name: "zones", type: 1012}]},
5301
- remove: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
5302
- removeAll: {ID: 4, parameters: [], name: "removeAll"},
5303
- addIfIdentifying: {
5304
- ID: 5,
5305
- parameters: [
5306
- {name: "groupid", type: 33},
5307
- {name: "groupname", type: 66},
5308
- ],
5309
- name: "addIfIdentifying",
5310
- },
5311
- },
5312
- commandsResponse: {
5313
- addRsp: {
5314
- ID: 0,
5315
- parameters: [
5316
- {name: "status", type: 32},
5317
- {name: "groupid", type: 33},
5318
- ],
5319
- name: "addRsp",
5320
- },
5321
- viewRsp: {
5322
- ID: 1,
5323
- parameters: [
5324
- {name: "status", type: 32},
5325
- {name: "groupid", type: 33},
5326
- {name: "groupname", type: 66},
5327
- ],
5328
- name: "viewRsp",
5329
- },
5330
- getMembershipRsp: {
5331
- ID: 2,
5332
- parameters: [
5333
- {name: "capacity", type: 32},
5334
- {name: "groupcount", type: 32},
5335
- {name: "grouplist", type: 1002},
5336
- ],
5337
- name: "getMembershipRsp",
5338
- },
5339
- removeRsp: {
5340
- ID: 3,
5341
- parameters: [
5342
- {name: "status", type: 32},
5343
- {name: "groupid", type: 33},
5344
- ],
5345
- name: "removeRsp",
5346
- },
5347
- },
5348
- },
5349
- command: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
5350
- });
4689
+ expect(deepClone(call[3])).toStrictEqual(
4690
+ deepClone(Zcl.Frame.create(Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 11, "remove", 4, {groupid: 4}, {})),
4691
+ );
5351
4692
  });
5352
4693
 
5353
4694
  it("Try to get deleted device from endpoint", async () => {
@@ -5617,6 +4958,21 @@ describe("Controller", () => {
5617
4958
  expect(mocksendZclFrameToGroup.mock.calls[0][2]).toBeUndefined();
5618
4959
  });
5619
4960
 
4961
+ it("Read from group ignores unknown attributes", async () => {
4962
+ await controller.start();
4963
+ const group = await controller.createGroup(2);
4964
+ await group.read("genBasic", ["modelId", 0x01, "notanattr"], {});
4965
+ expect(mocksendZclFrameToGroup).toHaveBeenCalledTimes(1);
4966
+ expect(mocksendZclFrameToGroup.mock.calls[0][0]).toBe(2);
4967
+ expect(deepClone(mocksendZclFrameToGroup.mock.calls[0][1])).toStrictEqual(
4968
+ deepClone(
4969
+ Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 2, "read", 0, [{attrId: 5}, {attrId: 1}], {}),
4970
+ ),
4971
+ );
4972
+ expect(mocksendZclFrameToGroup.mock.calls[0][2]).toBeUndefined();
4973
+ expect(mockLogger.warning).toHaveBeenCalledWith("Ignoring unknown attribute notanattr in cluster genBasic", "zh:controller:group");
4974
+ });
4975
+
5620
4976
  it("Read from group fails", async () => {
5621
4977
  await controller.start();
5622
4978
  const group = await controller.createGroup(2);
@@ -5695,58 +5051,21 @@ describe("Controller", () => {
5695
5051
  expect(call[0]).toBe("0x129");
5696
5052
  expect(call[1]).toBe(129);
5697
5053
  expect(call[2]).toBe(1);
5698
- expect(deepClone(call[3])).toStrictEqual({
5699
- header: {
5700
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
5701
- transactionSequenceNumber: 11,
5702
- manufacturerCode: 4107,
5703
- commandIdentifier: 2,
5704
- },
5705
- payload: [{attrId: 49, attrData: 11, dataType: 25}],
5706
- cluster: {
5707
- ID: 0,
5708
- attributes: {
5709
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
5710
- appVersion: {ID: 1, type: 32, name: "appVersion"},
5711
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
5712
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
5713
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
5714
- modelId: {ID: 5, type: 66, name: "modelId"},
5715
- dateCode: {ID: 6, type: 66, name: "dateCode"},
5716
- powerSource: {ID: 7, type: 48, name: "powerSource"},
5717
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
5718
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
5719
- productCode: {ID: 10, type: 65, name: "productCode"},
5720
- productUrl: {ID: 11, type: 66, name: "productUrl"},
5721
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
5722
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
5723
- productLabel: {ID: 14, type: 66, name: "productLabel"},
5724
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
5725
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
5726
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
5727
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
5728
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
5729
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
5730
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
5731
- },
5732
- name: "genBasic",
5733
- commands: {
5734
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
5735
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
5736
- },
5737
- commandsResponse: {},
5738
- },
5739
- command: {
5740
- ID: 2,
5741
- name: "write",
5742
- parameters: [
5743
- {name: "attrId", type: 33},
5744
- {name: "dataType", type: 32},
5745
- {name: "attrData", type: 1000},
5746
- ],
5747
- response: 4,
5748
- },
5749
- });
5054
+ expect(deepClone(call[3])).toStrictEqual(
5055
+ deepClone(
5056
+ Zcl.Frame.create(
5057
+ Zcl.FrameType.GLOBAL,
5058
+ Zcl.Direction.CLIENT_TO_SERVER,
5059
+ true,
5060
+ 4107,
5061
+ 11,
5062
+ "write",
5063
+ 0,
5064
+ [{attrId: 49, attrData: 11, dataType: 25}],
5065
+ {},
5066
+ ),
5067
+ ),
5068
+ );
5750
5069
  expect(call[4]).toBe(12);
5751
5070
  });
5752
5071
 
@@ -5756,7 +5075,7 @@ describe("Controller", () => {
5756
5075
  mocksendZclFrameToEndpoint.mockClear();
5757
5076
  const device = controller.getDeviceByIeeeAddr("0x129")!;
5758
5077
  // @ts-expect-error private
5759
- device._manufacturerID = 0x10f2;
5078
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
5760
5079
  const endpoint = device.getEndpoint(1)!;
5761
5080
  await endpoint.write("hvacThermostat", {viessmannWindowOpenInternal: 1});
5762
5081
  expect(mocksendZclFrameToEndpoint).toHaveBeenCalledTimes(1);
@@ -5764,26 +5083,21 @@ describe("Controller", () => {
5764
5083
  expect(call[0]).toBe("0x129");
5765
5084
  expect(call[1]).toBe(129);
5766
5085
  expect(call[2]).toBe(1);
5767
- expect({...deepClone(call[3]), cluster: {}}).toStrictEqual({
5768
- header: {
5769
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
5770
- transactionSequenceNumber: 11,
5771
- manufacturerCode: 4641,
5772
- commandIdentifier: 2,
5773
- },
5774
- payload: [{attrId: 16384, attrData: 1, dataType: 48}],
5775
- cluster: {},
5776
- command: {
5777
- ID: 2,
5778
- name: "write",
5779
- parameters: [
5780
- {name: "attrId", type: 33},
5781
- {name: "dataType", type: 32},
5782
- {name: "attrData", type: 1000},
5783
- ],
5784
- response: 4,
5785
- },
5786
- });
5086
+ expect(deepClone(call[3])).toStrictEqual(
5087
+ deepClone(
5088
+ Zcl.Frame.create(
5089
+ Zcl.FrameType.GLOBAL,
5090
+ Zcl.Direction.CLIENT_TO_SERVER,
5091
+ true,
5092
+ 4641,
5093
+ 11,
5094
+ "write",
5095
+ 513,
5096
+ [{attrId: 16384, attrData: 1, dataType: 48}],
5097
+ {},
5098
+ ),
5099
+ ),
5100
+ );
5787
5101
  expect(call[4]).toBe(10000);
5788
5102
  });
5789
5103
 
@@ -5807,57 +5121,21 @@ describe("Controller", () => {
5807
5121
  expect(call[0]).toBe("0x129");
5808
5122
  expect(call[1]).toBe(129);
5809
5123
  expect(call[2]).toBe(1);
5810
- expect(deepClone(call[3])).toStrictEqual({
5811
- header: {
5812
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
5813
- transactionSequenceNumber: 11,
5814
- manufacturerCode: 4107,
5815
- commandIdentifier: 3,
5816
- },
5817
- payload: [{attrId: 49, attrData: 11, dataType: 25}],
5818
- cluster: {
5819
- ID: 0,
5820
- attributes: {
5821
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
5822
- appVersion: {ID: 1, type: 32, name: "appVersion"},
5823
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
5824
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
5825
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
5826
- modelId: {ID: 5, type: 66, name: "modelId"},
5827
- dateCode: {ID: 6, type: 66, name: "dateCode"},
5828
- powerSource: {ID: 7, type: 48, name: "powerSource"},
5829
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
5830
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
5831
- productCode: {ID: 10, type: 65, name: "productCode"},
5832
- productUrl: {ID: 11, type: 66, name: "productUrl"},
5833
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
5834
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
5835
- productLabel: {ID: 14, type: 66, name: "productLabel"},
5836
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
5837
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
5838
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
5839
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
5840
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
5841
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
5842
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
5843
- },
5844
- name: "genBasic",
5845
- commands: {
5846
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
5847
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
5848
- },
5849
- commandsResponse: {},
5850
- },
5851
- command: {
5852
- ID: 3,
5853
- name: "writeUndiv",
5854
- parameters: [
5855
- {name: "attrId", type: 33},
5856
- {name: "dataType", type: 32},
5857
- {name: "attrData", type: 1000},
5858
- ],
5859
- },
5860
- });
5124
+ expect(deepClone(call[3])).toStrictEqual(
5125
+ deepClone(
5126
+ Zcl.Frame.create(
5127
+ Zcl.FrameType.GLOBAL,
5128
+ Zcl.Direction.CLIENT_TO_SERVER,
5129
+ true,
5130
+ 4107,
5131
+ 11,
5132
+ "writeUndiv",
5133
+ 0,
5134
+ [{attrId: 49, attrData: 11, dataType: 25}],
5135
+ {},
5136
+ ),
5137
+ ),
5138
+ );
5861
5139
  expect(call[4]).toBe(12);
5862
5140
  });
5863
5141
 
@@ -5883,7 +5161,7 @@ describe("Controller", () => {
5883
5161
  mocksendZclFrameToEndpoint.mockClear();
5884
5162
  const device = controller.getDeviceByIeeeAddr("0x129")!;
5885
5163
  // @ts-expect-error private
5886
- device._manufacturerID = 0x10f2;
5164
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
5887
5165
  const endpoint = device.getEndpoint(1)!;
5888
5166
  let error;
5889
5167
  try {
@@ -5906,55 +5184,21 @@ describe("Controller", () => {
5906
5184
  expect(call[0]).toBe("0x129");
5907
5185
  expect(call[1]).toBe(129);
5908
5186
  expect(call[2]).toBe(1);
5909
- expect(deepClone(call[3])).toStrictEqual({
5910
- header: {
5911
- frameControl: {reservedBits: 0, frameType: 0, direction: 1, disableDefaultResponse: true, manufacturerSpecific: false},
5912
- transactionSequenceNumber: 99,
5913
- commandIdentifier: 4,
5914
- },
5915
- payload: [{attrId: 85, status: 1}],
5916
- cluster: {
5917
- ID: 0,
5918
- attributes: {
5919
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
5920
- appVersion: {ID: 1, type: 32, name: "appVersion"},
5921
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
5922
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
5923
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
5924
- modelId: {ID: 5, type: 66, name: "modelId"},
5925
- dateCode: {ID: 6, type: 66, name: "dateCode"},
5926
- powerSource: {ID: 7, type: 48, name: "powerSource"},
5927
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
5928
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
5929
- productCode: {ID: 10, type: 65, name: "productCode"},
5930
- productUrl: {ID: 11, type: 66, name: "productUrl"},
5931
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
5932
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
5933
- productLabel: {ID: 14, type: 66, name: "productLabel"},
5934
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
5935
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
5936
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
5937
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
5938
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
5939
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
5940
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
5941
- },
5942
- name: "genBasic",
5943
- commands: {
5944
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
5945
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
5946
- },
5947
- commandsResponse: {},
5948
- },
5949
- command: {
5950
- ID: 4,
5951
- name: "writeRsp",
5952
- parameters: [
5953
- {name: "status", type: 32},
5954
- {conditions: [{type: "statusNotEquals", value: 0}], name: "attrId", type: 33},
5955
- ],
5956
- },
5957
- });
5187
+ expect(deepClone(call[3])).toStrictEqual(
5188
+ deepClone(
5189
+ Zcl.Frame.create(
5190
+ Zcl.FrameType.GLOBAL,
5191
+ Zcl.Direction.SERVER_TO_CLIENT,
5192
+ true,
5193
+ undefined,
5194
+ 99,
5195
+ "writeRsp",
5196
+ 0,
5197
+ [{attrId: 85, status: 1}],
5198
+ {},
5199
+ ),
5200
+ ),
5201
+ );
5958
5202
  expect(call[4]).toBe(10000);
5959
5203
  });
5960
5204
 
@@ -6014,59 +5258,25 @@ describe("Controller", () => {
6014
5258
  const endpoint = device.getEndpoint(1)!;
6015
5259
  await endpoint.writeResponse("genBasic", 99, {zclVersion: {status: 0x01}});
6016
5260
  expect(mocksendZclFrameToEndpoint).toHaveBeenCalledTimes(1);
6017
- const call = mocksendZclFrameToEndpoint.mock.calls[0];
6018
- expect(call[0]).toBe("0x129");
6019
- expect(call[1]).toBe(129);
6020
- expect(call[2]).toBe(1);
6021
- expect(deepClone(call[3])).toStrictEqual({
6022
- header: {
6023
- frameControl: {reservedBits: 0, frameType: 0, direction: 1, disableDefaultResponse: true, manufacturerSpecific: false},
6024
- transactionSequenceNumber: 99,
6025
- commandIdentifier: 4,
6026
- },
6027
- payload: [{attrId: 0, status: 1}],
6028
- cluster: {
6029
- ID: 0,
6030
- attributes: {
6031
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
6032
- appVersion: {ID: 1, type: 32, name: "appVersion"},
6033
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
6034
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
6035
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
6036
- modelId: {ID: 5, type: 66, name: "modelId"},
6037
- dateCode: {ID: 6, type: 66, name: "dateCode"},
6038
- powerSource: {ID: 7, type: 48, name: "powerSource"},
6039
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
6040
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
6041
- productCode: {ID: 10, type: 65, name: "productCode"},
6042
- productUrl: {ID: 11, type: 66, name: "productUrl"},
6043
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
6044
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
6045
- productLabel: {ID: 14, type: 66, name: "productLabel"},
6046
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
6047
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
6048
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
6049
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
6050
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
6051
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
6052
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
6053
- },
6054
- name: "genBasic",
6055
- commands: {
6056
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
6057
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
6058
- },
6059
- commandsResponse: {},
6060
- },
6061
- command: {
6062
- ID: 4,
6063
- name: "writeRsp",
6064
- parameters: [
6065
- {name: "status", type: 32},
6066
- {conditions: [{type: "statusNotEquals", value: 0}], name: "attrId", type: 33},
6067
- ],
6068
- },
6069
- });
5261
+ const call = mocksendZclFrameToEndpoint.mock.calls[0];
5262
+ expect(call[0]).toBe("0x129");
5263
+ expect(call[1]).toBe(129);
5264
+ expect(call[2]).toBe(1);
5265
+ expect(deepClone(call[3])).toStrictEqual(
5266
+ deepClone(
5267
+ Zcl.Frame.create(
5268
+ Zcl.FrameType.GLOBAL,
5269
+ Zcl.Direction.SERVER_TO_CLIENT,
5270
+ true,
5271
+ undefined,
5272
+ 99,
5273
+ "writeRsp",
5274
+ 0,
5275
+ [{attrId: 0, status: 1}],
5276
+ {},
5277
+ ),
5278
+ ),
5279
+ );
6070
5280
  expect(call[4]).toBe(10000);
6071
5281
  });
6072
5282
 
@@ -6089,6 +5299,36 @@ describe("Controller", () => {
6089
5299
  );
6090
5300
  });
6091
5301
 
5302
+ it("Write response to endpoint with options", async () => {
5303
+ await controller.start();
5304
+ await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
5305
+ mocksendZclFrameToEndpoint.mockClear();
5306
+ const device = controller.getDeviceByIeeeAddr("0x129")!;
5307
+ const endpoint = device.getEndpoint(1)!;
5308
+ await endpoint.writeResponse("genBasic", 99, {zclVersion: {status: 0x03}}, {manufacturerCode: Zcl.ManufacturerCode.INOVELLI});
5309
+ expect(mocksendZclFrameToEndpoint).toHaveBeenCalledTimes(1);
5310
+ const call = mocksendZclFrameToEndpoint.mock.calls[0];
5311
+ expect(call[0]).toBe("0x129");
5312
+ expect(call[1]).toBe(129);
5313
+ expect(call[2]).toBe(1);
5314
+ expect(deepClone(call[3])).toStrictEqual(
5315
+ deepClone(
5316
+ Zcl.Frame.create(
5317
+ Zcl.FrameType.GLOBAL,
5318
+ Zcl.Direction.SERVER_TO_CLIENT,
5319
+ true,
5320
+ Zcl.ManufacturerCode.INOVELLI,
5321
+ 99,
5322
+ "writeRsp",
5323
+ 0,
5324
+ [{attrId: 0, status: 0x03}],
5325
+ {},
5326
+ ),
5327
+ ),
5328
+ );
5329
+ expect(call[4]).toBe(10000);
5330
+ });
5331
+
6092
5332
  it("Read from endpoint with string", async () => {
6093
5333
  await controller.start();
6094
5334
  await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
@@ -6101,49 +5341,29 @@ describe("Controller", () => {
6101
5341
  expect(call[0]).toBe("0x129");
6102
5342
  expect(call[1]).toBe(129);
6103
5343
  expect(call[2]).toBe(1);
6104
- expect(deepClone(call[3])).toStrictEqual({
6105
- header: {
6106
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
6107
- transactionSequenceNumber: 11,
6108
- commandIdentifier: 0,
6109
- },
6110
- payload: [{attrId: 2}],
6111
- cluster: {
6112
- ID: 0,
6113
- attributes: {
6114
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
6115
- appVersion: {ID: 1, type: 32, name: "appVersion"},
6116
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
6117
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
6118
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
6119
- modelId: {ID: 5, type: 66, name: "modelId"},
6120
- dateCode: {ID: 6, type: 66, name: "dateCode"},
6121
- powerSource: {ID: 7, type: 48, name: "powerSource"},
6122
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
6123
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
6124
- productCode: {ID: 10, type: 65, name: "productCode"},
6125
- productUrl: {ID: 11, type: 66, name: "productUrl"},
6126
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
6127
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
6128
- productLabel: {ID: 14, type: 66, name: "productLabel"},
6129
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
6130
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
6131
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
6132
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
6133
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
6134
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
6135
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
6136
- },
6137
- name: "genBasic",
6138
- commands: {
6139
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
6140
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
6141
- },
6142
- commandsResponse: {},
6143
- },
6144
- command: {ID: 0, name: "read", parameters: [{name: "attrId", type: 33}], response: 1},
6145
- });
5344
+ expect(deepClone(call[3])).toStrictEqual(
5345
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 11, "read", 0, [{attrId: 2}], {})),
5346
+ );
5347
+ expect(call[4]).toBe(10000);
5348
+ });
5349
+
5350
+ it("Read from endpoint with string ignores unknown", async () => {
5351
+ await controller.start();
5352
+ await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
5353
+ mocksendZclFrameToEndpoint.mockClear();
5354
+ const device = controller.getDeviceByIeeeAddr("0x129")!;
5355
+ const endpoint = device.getEndpoint(1)!;
5356
+ await endpoint.read("genBasic", ["stackVersion", "notanattr"]);
5357
+ expect(mocksendZclFrameToEndpoint).toHaveBeenCalledTimes(1);
5358
+ const call = mocksendZclFrameToEndpoint.mock.calls[0];
5359
+ expect(call[0]).toBe("0x129");
5360
+ expect(call[1]).toBe(129);
5361
+ expect(call[2]).toBe(1);
5362
+ expect(deepClone(call[3])).toStrictEqual(
5363
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 11, "read", 0, [{attrId: 2}], {})),
5364
+ );
6146
5365
  expect(call[4]).toBe(10000);
5366
+ expect(mockLogger.warning).toHaveBeenCalledWith("Ignoring unknown attribute notanattr in cluster genBasic", "zh:controller:endpoint");
6147
5367
  });
6148
5368
 
6149
5369
  it("Read from endpoint with custom attribute", async () => {
@@ -6152,7 +5372,7 @@ describe("Controller", () => {
6152
5372
  mocksendZclFrameToEndpoint.mockClear();
6153
5373
  const device = controller.getDeviceByIeeeAddr("0x129")!;
6154
5374
  // @ts-expect-error private
6155
- device._manufacturerID = 0x10f2;
5375
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
6156
5376
  const endpoint = device.getEndpoint(1)!;
6157
5377
  await endpoint.read("hvacThermostat", ["viessmannWindowOpenInternal"]);
6158
5378
  expect(mocksendZclFrameToEndpoint).toHaveBeenCalledTimes(1);
@@ -6160,17 +5380,9 @@ describe("Controller", () => {
6160
5380
  expect(call[0]).toBe("0x129");
6161
5381
  expect(call[1]).toBe(129);
6162
5382
  expect(call[2]).toBe(1);
6163
- expect({...deepClone(call[3]), cluster: {}}).toStrictEqual({
6164
- header: {
6165
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
6166
- transactionSequenceNumber: 11,
6167
- manufacturerCode: 4641,
6168
- commandIdentifier: 0,
6169
- },
6170
- payload: [{attrId: 16384}],
6171
- cluster: {},
6172
- command: {ID: 0, name: "read", parameters: [{name: "attrId", type: 33}], response: 1},
6173
- });
5383
+ expect(deepClone(call[3])).toStrictEqual(
5384
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, 4641, 11, "read", 513, [{attrId: 16384}], {})),
5385
+ );
6174
5386
  expect(call[4]).toBe(10000);
6175
5387
  });
6176
5388
 
@@ -6180,7 +5392,7 @@ describe("Controller", () => {
6180
5392
  mocksendZclFrameToEndpoint.mockClear();
6181
5393
  const device = controller.getDeviceByIeeeAddr("0x129")!;
6182
5394
  // @ts-expect-error private
6183
- device._manufacturerID = 0x10f2;
5395
+ device._manufacturerID = Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH;
6184
5396
  const endpoint = device.getEndpoint(1)!;
6185
5397
  let error;
6186
5398
  try {
@@ -6203,49 +5415,9 @@ describe("Controller", () => {
6203
5415
  expect(call[0]).toBe("0x129");
6204
5416
  expect(call[1]).toBe(129);
6205
5417
  expect(call[2]).toBe(1);
6206
- expect(deepClone(call[3])).toStrictEqual({
6207
- header: {
6208
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
6209
- transactionSequenceNumber: 11,
6210
- manufacturerCode: 4447,
6211
- commandIdentifier: 0,
6212
- },
6213
- payload: [{attrId: 65314}],
6214
- cluster: {
6215
- ID: 0,
6216
- attributes: {
6217
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
6218
- appVersion: {ID: 1, type: 32, name: "appVersion"},
6219
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
6220
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
6221
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
6222
- modelId: {ID: 5, type: 66, name: "modelId"},
6223
- dateCode: {ID: 6, type: 66, name: "dateCode"},
6224
- powerSource: {ID: 7, type: 48, name: "powerSource"},
6225
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
6226
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
6227
- productCode: {ID: 10, type: 65, name: "productCode"},
6228
- productUrl: {ID: 11, type: 66, name: "productUrl"},
6229
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
6230
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
6231
- productLabel: {ID: 14, type: 66, name: "productLabel"},
6232
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
6233
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
6234
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
6235
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
6236
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
6237
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
6238
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
6239
- },
6240
- name: "genBasic",
6241
- commands: {
6242
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
6243
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
6244
- },
6245
- commandsResponse: {},
6246
- },
6247
- command: {ID: 0, name: "read", parameters: [{name: "attrId", type: 33}], response: 1},
6248
- });
5418
+ expect(deepClone(call[3])).toStrictEqual(
5419
+ deepClone(Zcl.Frame.create(Zcl.FrameType.GLOBAL, Zcl.Direction.CLIENT_TO_SERVER, true, 4447, 11, "read", 0, [{attrId: 65314}], {})),
5420
+ );
6249
5421
  expect(call[4]).toBe(10000);
6250
5422
  });
6251
5423
 
@@ -6261,57 +5433,21 @@ describe("Controller", () => {
6261
5433
  expect(call[0]).toBe("0x129");
6262
5434
  expect(call[1]).toBe(129);
6263
5435
  expect(call[2]).toBe(1);
6264
- expect(deepClone(call[3])).toStrictEqual({
6265
- header: {
6266
- frameControl: {reservedBits: 0, frameType: 0, direction: 1, disableDefaultResponse: true, manufacturerSpecific: false},
6267
- transactionSequenceNumber: 99,
6268
- commandIdentifier: 1,
6269
- },
6270
- payload: [{attrId: 85, attrData: 11, dataType: 25, status: 0}],
6271
- cluster: {
6272
- ID: 0,
6273
- attributes: {
6274
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
6275
- appVersion: {ID: 1, type: 32, name: "appVersion"},
6276
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
6277
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
6278
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
6279
- modelId: {ID: 5, type: 66, name: "modelId"},
6280
- dateCode: {ID: 6, type: 66, name: "dateCode"},
6281
- powerSource: {ID: 7, type: 48, name: "powerSource"},
6282
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
6283
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
6284
- productCode: {ID: 10, type: 65, name: "productCode"},
6285
- productUrl: {ID: 11, type: 66, name: "productUrl"},
6286
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
6287
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
6288
- productLabel: {ID: 14, type: 66, name: "productLabel"},
6289
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
6290
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
6291
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
6292
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
6293
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
6294
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
6295
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
6296
- },
6297
- name: "genBasic",
6298
- commands: {
6299
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
6300
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
6301
- },
6302
- commandsResponse: {},
6303
- },
6304
- command: {
6305
- ID: 1,
6306
- name: "readRsp",
6307
- parameters: [
6308
- {name: "attrId", type: 33},
6309
- {name: "status", type: 32},
6310
- {name: "dataType", type: 32, conditions: [{type: "statusEquals", value: 0}]},
6311
- {name: "attrData", type: 1000, conditions: [{type: "statusEquals", value: 0}]},
6312
- ],
6313
- },
6314
- });
5436
+ expect(deepClone(call[3])).toStrictEqual(
5437
+ deepClone(
5438
+ Zcl.Frame.create(
5439
+ Zcl.FrameType.GLOBAL,
5440
+ Zcl.Direction.SERVER_TO_CLIENT,
5441
+ true,
5442
+ undefined,
5443
+ 99,
5444
+ "readRsp",
5445
+ 0,
5446
+ [{attrId: 85, attrData: 11, dataType: 25, status: 0}],
5447
+ {},
5448
+ ),
5449
+ ),
5450
+ );
6315
5451
  expect(call[4]).toBe(10000);
6316
5452
  });
6317
5453
 
@@ -6367,36 +5503,21 @@ describe("Controller", () => {
6367
5503
  expect(call[0]).toBe("0x129");
6368
5504
  expect(call[1]).toBe(129);
6369
5505
  expect(call[2]).toBe(1);
6370
- expect({...deepClone(call[3]), cluster: {}}).toStrictEqual({
6371
- cluster: {},
6372
- command: {
6373
- ID: 6,
6374
- name: "configReport",
6375
- parameters: [
6376
- {name: "direction", type: 32},
6377
- {name: "attrId", type: 33},
6378
- {conditions: [{type: "directionEquals", value: 0}], name: "dataType", type: 32},
6379
- {conditions: [{type: "directionEquals", value: 0}], name: "minRepIntval", type: 33},
6380
- {conditions: [{type: "directionEquals", value: 0}], name: "maxRepIntval", type: 33},
6381
- {
6382
- conditions: [
6383
- {type: "directionEquals", value: 0},
6384
- {type: "dataTypeValueTypeEquals", value: "ANALOG"},
6385
- ],
6386
- name: "repChange",
6387
- type: 1000,
6388
- },
6389
- {conditions: [{type: "directionEquals", value: 1}], name: "timeout", type: 33},
6390
- ],
6391
- response: 7,
6392
- },
6393
- header: {
6394
- commandIdentifier: 6,
6395
- frameControl: {direction: 0, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, reservedBits: 0},
6396
- transactionSequenceNumber: 11,
6397
- },
6398
- payload: [{attrId: 16388, dataType: 41, direction: 0, maxRepIntval: 3600, minRepIntval: 0, repChange: 25}],
6399
- });
5506
+ expect(deepClone(call[3])).toStrictEqual(
5507
+ deepClone(
5508
+ Zcl.Frame.create(
5509
+ Zcl.FrameType.GLOBAL,
5510
+ Zcl.Direction.CLIENT_TO_SERVER,
5511
+ true,
5512
+ undefined,
5513
+ 11,
5514
+ "configReport",
5515
+ 513,
5516
+ [{attrId: 16388, dataType: 41, direction: 0, maxRepIntval: 3600, minRepIntval: 0, repChange: 25}],
5517
+ {},
5518
+ ),
5519
+ ),
5520
+ );
6400
5521
  expect(call[4]).toBe(10000);
6401
5522
 
6402
5523
  const hvacThermostat = Zcl.Utils.getCluster("hvacThermostat", undefined, {});
@@ -6434,88 +5555,9 @@ describe("Controller", () => {
6434
5555
  expect(group1.members).toStrictEqual([]);
6435
5556
  expect(Array.from(group6.members)).toStrictEqual([device2.getEndpoint(1)]);
6436
5557
  expect(Array.from(group7.members)).toStrictEqual([device2.getEndpoint(1)]);
6437
- expect(deepClone(call[3])).toStrictEqual({
6438
- header: {
6439
- frameControl: {reservedBits: 0, frameType: 1, direction: 0, disableDefaultResponse: true, manufacturerSpecific: false},
6440
- transactionSequenceNumber: 25,
6441
- commandIdentifier: 4,
6442
- },
6443
- payload: {},
6444
- cluster: {
6445
- ID: 4,
6446
- attributes: {nameSupport: {ID: 0, type: 24, name: "nameSupport"}},
6447
- name: "genGroups",
6448
- commands: {
6449
- add: {
6450
- ID: 0,
6451
- response: 0,
6452
- parameters: [
6453
- {name: "groupid", type: 33},
6454
- {name: "groupname", type: 66},
6455
- ],
6456
- name: "add",
6457
- },
6458
- view: {ID: 1, response: 1, parameters: [{name: "groupid", type: 33}], name: "view"},
6459
- getMembership: {
6460
- ID: 2,
6461
- response: 2,
6462
- parameters: [
6463
- {name: "groupcount", type: 32},
6464
- {name: "grouplist", type: 1002},
6465
- ],
6466
- name: "getMembership",
6467
- },
6468
- miboxerSetZones: {ID: 240, name: "miboxerSetZones", parameters: [{name: "zones", type: 1012}]},
6469
- remove: {ID: 3, response: 3, parameters: [{name: "groupid", type: 33}], name: "remove"},
6470
- removeAll: {ID: 4, parameters: [], name: "removeAll"},
6471
- addIfIdentifying: {
6472
- ID: 5,
6473
- parameters: [
6474
- {name: "groupid", type: 33},
6475
- {name: "groupname", type: 66},
6476
- ],
6477
- name: "addIfIdentifying",
6478
- },
6479
- },
6480
- commandsResponse: {
6481
- addRsp: {
6482
- ID: 0,
6483
- parameters: [
6484
- {name: "status", type: 32},
6485
- {name: "groupid", type: 33},
6486
- ],
6487
- name: "addRsp",
6488
- },
6489
- viewRsp: {
6490
- ID: 1,
6491
- parameters: [
6492
- {name: "status", type: 32},
6493
- {name: "groupid", type: 33},
6494
- {name: "groupname", type: 66},
6495
- ],
6496
- name: "viewRsp",
6497
- },
6498
- getMembershipRsp: {
6499
- ID: 2,
6500
- parameters: [
6501
- {name: "capacity", type: 32},
6502
- {name: "groupcount", type: 32},
6503
- {name: "grouplist", type: 1002},
6504
- ],
6505
- name: "getMembershipRsp",
6506
- },
6507
- removeRsp: {
6508
- ID: 3,
6509
- parameters: [
6510
- {name: "status", type: 32},
6511
- {name: "groupid", type: 33},
6512
- ],
6513
- name: "removeRsp",
6514
- },
6515
- },
6516
- },
6517
- command: {ID: 4, parameters: [], name: "removeAll"},
6518
- });
5558
+ expect(deepClone(call[3])).toStrictEqual(
5559
+ deepClone(Zcl.Frame.create(Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, true, undefined, 25, "removeAll", 4, {}, {})),
5560
+ );
6519
5561
  });
6520
5562
 
6521
5563
  it("Load database", async () => {
@@ -7394,13 +6436,8 @@ describe("Controller", () => {
7394
6436
  const device = controller.getDeviceByIeeeAddr("0x129")!;
7395
6437
  const endpoint = device.getEndpoint(1)!;
7396
6438
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
7397
- let error;
7398
- try {
7399
- await endpoint.read("genOnOff", ["onOff"], {disableResponse: true});
7400
- } catch (e) {
7401
- error = e;
7402
- }
7403
- expect(error).toBeUndefined();
6439
+
6440
+ await endpoint.read("genOnOff", ["onOff"], {disableResponse: true});
7404
6441
  });
7405
6442
 
7406
6443
  it("Write error", async () => {
@@ -7428,13 +6465,8 @@ describe("Controller", () => {
7428
6465
  const device = controller.getDeviceByIeeeAddr("0x129")!;
7429
6466
  const endpoint = device.getEndpoint(1)!;
7430
6467
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
7431
- let error;
7432
- try {
7433
- await endpoint.write("genOnOff", {onOff: 1}, {disableResponse: true});
7434
- } catch (e) {
7435
- error = e;
7436
- }
7437
- expect(error).toBeUndefined();
6468
+
6469
+ await endpoint.write("genOnOff", {onOff: 1}, {disableResponse: true});
7438
6470
  });
7439
6471
 
7440
6472
  it("Group command error", async () => {
@@ -7457,13 +6489,8 @@ describe("Controller", () => {
7457
6489
  const device = controller.getDeviceByIeeeAddr("0x129")!;
7458
6490
  const endpoint = device.getEndpoint(1)!;
7459
6491
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
7460
- let error;
7461
- try {
7462
- await endpoint.writeStructured("genPowerCfg", {});
7463
- } catch (e) {
7464
- error = e;
7465
- }
7466
- expect(error).toBeUndefined();
6492
+
6493
+ await endpoint.writeStructured("genPowerCfg", {});
7467
6494
  });
7468
6495
 
7469
6496
  it("Write structured with disable response", async () => {
@@ -7473,13 +6500,8 @@ describe("Controller", () => {
7473
6500
  const device = controller.getDeviceByIeeeAddr("0x129")!;
7474
6501
  const endpoint = device.getEndpoint(1)!;
7475
6502
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
7476
- let error;
7477
- try {
7478
- await endpoint.writeStructured("genPowerCfg", {}, {disableResponse: true});
7479
- } catch (e) {
7480
- error = e;
7481
- }
7482
- expect(error).toBeUndefined();
6503
+
6504
+ await endpoint.writeStructured("genPowerCfg", {}, {disableResponse: true});
7483
6505
  });
7484
6506
 
7485
6507
  it("Write structured error", async () => {
@@ -8246,7 +7268,6 @@ describe("Controller", () => {
8246
7268
  _gpSecurityKey: [0x21, 0x7f, 0x8c, 0xb2, 0x90, 0xd9, 0x90, 0x14, 0x15, 0xd0, 0x5c, 0xb1, 0x64, 0x7c, 0x44, 0x6c],
8247
7269
  },
8248
7270
  });
8249
- console.log(events.deviceInterview);
8250
7271
  expect(events.deviceInterview.length).toBe(3); // gpp[started] + gpp[successful] + gpd
8251
7272
  expect(deepClone(events.deviceInterview[2])).toStrictEqual({
8252
7273
  status: "successful",
@@ -8495,57 +7516,21 @@ describe("Controller", () => {
8495
7516
  expect(call[0]).toBe("0x129");
8496
7517
  expect(call[1]).toBe(129);
8497
7518
  expect(call[2]).toBe(1);
8498
- expect(deepClone(call[3])).toStrictEqual({
8499
- header: {
8500
- frameControl: {reservedBits: 0, frameType: 0, direction: 0, disableDefaultResponse: true, manufacturerSpecific: true},
8501
- transactionSequenceNumber: 11,
8502
- manufacturerCode: 4107,
8503
- commandIdentifier: 10,
8504
- },
8505
- payload: [{attrId: 49, attrData: 11, dataType: 25}],
8506
- cluster: {
8507
- ID: 0,
8508
- attributes: {
8509
- zclVersion: {ID: 0, type: 32, name: "zclVersion"},
8510
- appVersion: {ID: 1, type: 32, name: "appVersion"},
8511
- stackVersion: {ID: 2, type: 32, name: "stackVersion"},
8512
- hwVersion: {ID: 3, type: 32, name: "hwVersion"},
8513
- manufacturerName: {ID: 4, type: 66, name: "manufacturerName"},
8514
- modelId: {ID: 5, type: 66, name: "modelId"},
8515
- dateCode: {ID: 6, type: 66, name: "dateCode"},
8516
- powerSource: {ID: 7, type: 48, name: "powerSource"},
8517
- appProfileVersion: {ID: 8, type: 48, name: "appProfileVersion"},
8518
- genericDeviceType: {ID: 9, type: 48, name: "genericDeviceType"},
8519
- productCode: {ID: 10, type: 65, name: "productCode"},
8520
- productUrl: {ID: 11, type: 66, name: "productUrl"},
8521
- manufacturerVersionDetails: {ID: 12, type: 66, name: "manufacturerVersionDetails"},
8522
- serialNumber: {ID: 13, type: 66, name: "serialNumber"},
8523
- productLabel: {ID: 14, type: 66, name: "productLabel"},
8524
- locationDesc: {ID: 16, type: 66, name: "locationDesc"},
8525
- physicalEnv: {ID: 17, type: 48, name: "physicalEnv"},
8526
- deviceEnabled: {ID: 18, type: 16, name: "deviceEnabled"},
8527
- alarmMask: {ID: 19, type: 24, name: "alarmMask"},
8528
- disableLocalConfig: {ID: 20, type: 24, name: "disableLocalConfig"},
8529
- swBuildId: {ID: 16384, type: 66, name: "swBuildId"},
8530
- schneiderMeterRadioPower: {ID: 57856, manufacturerCode: 4190, name: "schneiderMeterRadioPower", type: 40},
8531
- },
8532
- name: "genBasic",
8533
- commands: {
8534
- resetFactDefault: {ID: 0, parameters: [], name: "resetFactDefault"},
8535
- tuyaSetup: {ID: 240, parameters: [], name: "tuyaSetup"},
8536
- },
8537
- commandsResponse: {},
8538
- },
8539
- command: {
8540
- ID: 10,
8541
- name: "report",
8542
- parameters: [
8543
- {name: "attrId", type: 33},
8544
- {name: "dataType", type: 32},
8545
- {name: "attrData", type: 1000},
8546
- ],
8547
- },
8548
- });
7519
+ expect(deepClone(call[3])).toStrictEqual(
7520
+ deepClone(
7521
+ Zcl.Frame.create(
7522
+ Zcl.FrameType.GLOBAL,
7523
+ Zcl.Direction.CLIENT_TO_SERVER,
7524
+ true,
7525
+ 4107,
7526
+ 11,
7527
+ "report",
7528
+ 0,
7529
+ [{attrId: 49, attrData: 11, dataType: 25}],
7530
+ {},
7531
+ ),
7532
+ ),
7533
+ );
8549
7534
  expect(call[4]).toBe(12);
8550
7535
  });
8551
7536
 
@@ -9396,13 +8381,20 @@ describe("Controller", () => {
9396
8381
  const device = controller.getDeviceByIeeeAddr("0x129")!;
9397
8382
  const endpoint = device.getEndpoint(1)!;
9398
8383
  mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
9399
- let error;
9400
- try {
9401
- await endpoint.zclCommand("genOnOff", "discover", {startAttrId: 1, maxAttrIds: 255});
9402
- } catch (e) {
9403
- error = e;
9404
- }
9405
- expect(error).toBeUndefined();
8384
+
8385
+ await endpoint.zclCommand("genOnOff", "discover", {startAttrId: 1, maxAttrIds: 255});
8386
+ });
8387
+
8388
+ it("zclCommand with cluster/command objects", async () => {
8389
+ await controller.start();
8390
+ await mockAdapterEvents.deviceJoined({networkAddress: 129, ieeeAddr: "0x129"});
8391
+ const cluster = Zcl.Utils.getCluster("genOnOff", undefined, {});
8392
+ const command = Zcl.Utils.getGlobalCommand("discover");
8393
+ const device = controller.getDeviceByIeeeAddr("0x129")!;
8394
+ const endpoint = device.getEndpoint(1)!;
8395
+ mocksendZclFrameToEndpoint.mockReturnValueOnce(null);
8396
+
8397
+ await endpoint.zclCommand(cluster, command, {startAttrId: 1, maxAttrIds: 255});
9406
8398
  });
9407
8399
 
9408
8400
  it("zclCommand with error", async () => {
@@ -10123,7 +9115,7 @@ describe("Controller", () => {
10123
9115
 
10124
9116
  device.addCustomCluster("manuSpecificInovelli", {
10125
9117
  ID: 64561,
10126
- manufacturerCode: 0x122f,
9118
+ manufacturerCode: Zcl.ManufacturerCode.V_MARK_ENTERPRISES_INC,
10127
9119
  // omitted for brevity (unused here)
10128
9120
  attributes: {},
10129
9121
  commands: {
@@ -10169,7 +9161,7 @@ describe("Controller", () => {
10169
9161
  Zcl.FrameType.SPECIFIC,
10170
9162
  Zcl.Direction.CLIENT_TO_SERVER,
10171
9163
  true,
10172
- undefined,
9164
+ Zcl.ManufacturerCode.V_MARK_ENTERPRISES_INC,
10173
9165
  14,
10174
9166
  "individualLedEffect",
10175
9167
  64561,
@@ -10189,7 +9181,7 @@ describe("Controller", () => {
10189
9181
  Zcl.FrameType.SPECIFIC,
10190
9182
  Zcl.Direction.SERVER_TO_CLIENT,
10191
9183
  true,
10192
- undefined,
9184
+ Zcl.ManufacturerCode.V_MARK_ENTERPRISES_INC,
10193
9185
  15,
10194
9186
  "bogus",
10195
9187
  64561,