zigbee-herdsman-converters 14.0.442 → 14.0.445
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/converters/fromZigbee.js +56 -259
- package/converters/toZigbee.js +26 -0
- package/devices/aurora_lighting.js +1 -1
- package/devices/hive.js +3 -3
- package/devices/livolo.js +22 -5
- package/devices/sengled.js +40 -5
- package/devices/smartthings.js +4 -1
- package/devices/smartwings.js +24 -0
- package/devices/tuya.js +8 -5
- package/devices/woox.js +2 -2
- package/devices/xiaomi.js +2 -2
- package/devices/yale.js +7 -0
- package/lib/exposes.js +2 -1
- package/lib/ota/zigbeeOTA.js +4 -2
- package/lib/utils.js +16 -12
- package/lib/xiaomi.js +384 -0
- package/npm-shrinkwrap.json +33 -33
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -20,6 +20,7 @@ const constants = require('../lib/constants');
|
|
|
20
20
|
const libColor = require('../lib/color');
|
|
21
21
|
const utils = require('../lib/utils');
|
|
22
22
|
const exposes = require('../lib/exposes');
|
|
23
|
+
const xiaomi = require('../lib/xiaomi');
|
|
23
24
|
|
|
24
25
|
const converters = {
|
|
25
26
|
// #region Generic/recommended converters
|
|
@@ -423,11 +424,11 @@ const converters = {
|
|
|
423
424
|
// This is for occupancy sensor that send motion start AND stop messages
|
|
424
425
|
cluster: 'msOccupancySensing',
|
|
425
426
|
type: ['attributeReport', 'readResponse'],
|
|
426
|
-
options: [exposes.options.
|
|
427
|
+
options: [exposes.options.no_occupancy_since_false()],
|
|
427
428
|
convert: (model, msg, publish, options, meta) => {
|
|
428
429
|
if (msg.data.hasOwnProperty('occupancy')) {
|
|
429
430
|
const payload = {occupancy: (msg.data.occupancy % 2) > 0};
|
|
430
|
-
utils.noOccupancySince(msg.endpoint,
|
|
431
|
+
utils.noOccupancySince(msg.endpoint, options, publish, payload.occupancy ? 'stop' : 'start');
|
|
431
432
|
return payload;
|
|
432
433
|
}
|
|
433
434
|
},
|
|
@@ -438,7 +439,7 @@ const converters = {
|
|
|
438
439
|
// Therefore we need to publish the no_motion detected by ourselves.
|
|
439
440
|
cluster: 'msOccupancySensing',
|
|
440
441
|
type: ['attributeReport', 'readResponse'],
|
|
441
|
-
options: [exposes.options.occupancy_timeout(), exposes.options.
|
|
442
|
+
options: [exposes.options.occupancy_timeout(), exposes.options.no_occupancy_since_true()],
|
|
442
443
|
convert: (model, msg, publish, options, meta) => {
|
|
443
444
|
if (msg.data.occupancy !== 1) {
|
|
444
445
|
// In case of 0 no occupancy is reported.
|
|
@@ -463,7 +464,7 @@ const converters = {
|
|
|
463
464
|
}
|
|
464
465
|
|
|
465
466
|
const payload = {occupancy: true};
|
|
466
|
-
utils.noOccupancySince(msg.endpoint,
|
|
467
|
+
utils.noOccupancySince(msg.endpoint, options, publish, 'start');
|
|
467
468
|
return payload;
|
|
468
469
|
},
|
|
469
470
|
},
|
|
@@ -2789,6 +2790,33 @@ const converters = {
|
|
|
2789
2790
|
}
|
|
2790
2791
|
},
|
|
2791
2792
|
},
|
|
2793
|
+
livolo_new_switch_state_4gang: {
|
|
2794
|
+
cluster: 'genPowerCfg',
|
|
2795
|
+
type: ['raw'],
|
|
2796
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2797
|
+
const stateHeader = Buffer.from([122, 209]);
|
|
2798
|
+
if (msg.data.indexOf(stateHeader) === 0) {
|
|
2799
|
+
if (msg.data[10] === 7) {
|
|
2800
|
+
const status = msg.data[14];
|
|
2801
|
+
return {
|
|
2802
|
+
state_left: status & 1 ? 'ON' : 'OFF',
|
|
2803
|
+
state_right: status & 2 ? 'ON' : 'OFF',
|
|
2804
|
+
state_bottom_left: status & 4 ? 'ON' : 'OFF',
|
|
2805
|
+
state_bottom_right: status & 8 ? 'ON' : 'OFF',
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
if (msg.data[10] === 13) {
|
|
2809
|
+
const status = msg.data[13];
|
|
2810
|
+
return {
|
|
2811
|
+
state_left: status & 1 ? 'ON' : 'OFF',
|
|
2812
|
+
state_right: status & 2 ? 'ON' : 'OFF',
|
|
2813
|
+
state_bottom_left: status & 4 ? 'ON' : 'OFF',
|
|
2814
|
+
state_bottom_right: status & 8 ? 'ON' : 'OFF',
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
},
|
|
2819
|
+
},
|
|
2792
2820
|
livolo_curtain_switch_state: {
|
|
2793
2821
|
cluster: 'genPowerCfg',
|
|
2794
2822
|
type: ['raw'],
|
|
@@ -2948,7 +2976,8 @@ const converters = {
|
|
|
2948
2976
|
meta.device.modelID = 'TI0001-socket';
|
|
2949
2977
|
meta.device.save();
|
|
2950
2978
|
}
|
|
2951
|
-
|
|
2979
|
+
// No need to detect this switches, will be done by universal procedure
|
|
2980
|
+
/* if (msg.data.includes(Buffer.from([19, 1, 0]), 13)) {
|
|
2952
2981
|
// new switch, hack
|
|
2953
2982
|
meta.device.modelID = 'TI0001-switch';
|
|
2954
2983
|
meta.device.save();
|
|
@@ -2957,7 +2986,7 @@ const converters = {
|
|
|
2957
2986
|
// new switch, hack
|
|
2958
2987
|
meta.device.modelID = 'TI0001-switch-2gang';
|
|
2959
2988
|
meta.device.save();
|
|
2960
|
-
}
|
|
2989
|
+
}*/
|
|
2961
2990
|
if (msg.data.includes(Buffer.from([19, 5, 0]), 13)) {
|
|
2962
2991
|
if (meta.logger) meta.logger.debug('Detected Livolo Curtain Switch');
|
|
2963
2992
|
// curtain switch, hack
|
|
@@ -5230,40 +5259,27 @@ const converters = {
|
|
|
5230
5259
|
type: ['attributeReport', 'readResponse'],
|
|
5231
5260
|
options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
|
|
5232
5261
|
convert: (model, msg, publish, options, meta) => {
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
// Consumption is deprecated
|
|
5253
|
-
payload.consumption = precisionRound(data['149'], 2);
|
|
5254
|
-
payload.energy = precisionRound(data['149'], 2);
|
|
5255
|
-
}
|
|
5256
|
-
|
|
5257
|
-
if (data.hasOwnProperty('3')) {
|
|
5258
|
-
payload.temperature = calibrateAndPrecisionRoundOptions(data['3'], options, 'temperature');
|
|
5259
|
-
}
|
|
5260
|
-
|
|
5261
|
-
if (data.hasOwnProperty('150')) {
|
|
5262
|
-
payload.voltage = precisionRound(data['150'] * 0.1, 1);
|
|
5263
|
-
}
|
|
5264
|
-
|
|
5265
|
-
return payload;
|
|
5262
|
+
const payload = xiaomi.numericAttributes2Payload(msg, meta, model, options, msg.data);
|
|
5263
|
+
return payload;
|
|
5264
|
+
},
|
|
5265
|
+
},
|
|
5266
|
+
xiaomi_basic_raw: {
|
|
5267
|
+
cluster: 'genBasic',
|
|
5268
|
+
type: ['raw'],
|
|
5269
|
+
options: (definition) => {
|
|
5270
|
+
const result = [];
|
|
5271
|
+
if (definition.exposes.find((e) => e.name === 'temperature')) {
|
|
5272
|
+
result.push(exposes.options.precision('temperature'), exposes.options.calibration('temperature'));
|
|
5273
|
+
}
|
|
5274
|
+
return result;
|
|
5275
|
+
},
|
|
5276
|
+
convert: (model, msg, publish, options, meta) => {
|
|
5277
|
+
let payload = {};
|
|
5278
|
+
if (Buffer.isBuffer(msg.data)) {
|
|
5279
|
+
const dataObject = xiaomi.buffer2DataObject(meta, model, msg.data);
|
|
5280
|
+
payload = xiaomi.numericAttributes2Payload(msg, meta, model, options, dataObject);
|
|
5266
5281
|
}
|
|
5282
|
+
return payload;
|
|
5267
5283
|
},
|
|
5268
5284
|
},
|
|
5269
5285
|
aqara_opple: {
|
|
@@ -5280,226 +5296,7 @@ const converters = {
|
|
|
5280
5296
|
return result;
|
|
5281
5297
|
},
|
|
5282
5298
|
convert: (model, msg, publish, options, meta) => {
|
|
5283
|
-
const payload =
|
|
5284
|
-
if (msg.data.hasOwnProperty('247')) {
|
|
5285
|
-
const data = msg.data['247'];
|
|
5286
|
-
// Xiaomi struct parsing
|
|
5287
|
-
const length = data.length;
|
|
5288
|
-
for (let i=0; i < length; i++) {
|
|
5289
|
-
const index = data[i];
|
|
5290
|
-
let value = null;
|
|
5291
|
-
switch (data[i+1]) {
|
|
5292
|
-
case 16:
|
|
5293
|
-
// 0x10 ZclBoolean
|
|
5294
|
-
value = data.readUInt8(i+2);
|
|
5295
|
-
i += 2;
|
|
5296
|
-
break;
|
|
5297
|
-
case 32:
|
|
5298
|
-
// 0x20 Zcl8BitUint
|
|
5299
|
-
value = data.readUInt8(i+2);
|
|
5300
|
-
i += 2;
|
|
5301
|
-
break;
|
|
5302
|
-
case 33:
|
|
5303
|
-
// 0x21 Zcl16BitUint
|
|
5304
|
-
value = data.readUInt16LE(i+2);
|
|
5305
|
-
i += 3;
|
|
5306
|
-
break;
|
|
5307
|
-
case 34:
|
|
5308
|
-
// 0x22 Zcl24BitUint
|
|
5309
|
-
value = data.readUIntLE(i+2, 3);
|
|
5310
|
-
i += 4;
|
|
5311
|
-
break;
|
|
5312
|
-
case 35:
|
|
5313
|
-
// 0x23 Zcl32BitUint
|
|
5314
|
-
value = data.readUInt32LE(i+2);
|
|
5315
|
-
i += 5;
|
|
5316
|
-
break;
|
|
5317
|
-
case 36:
|
|
5318
|
-
// 0x24 Zcl40BitUint
|
|
5319
|
-
value = data.readUIntLE(i+2, 5);
|
|
5320
|
-
i += 6;
|
|
5321
|
-
break;
|
|
5322
|
-
case 37:
|
|
5323
|
-
// 0x25 Zcl48BitUint
|
|
5324
|
-
value = data.readUIntLE(i+2, 6);
|
|
5325
|
-
i += 7;
|
|
5326
|
-
break;
|
|
5327
|
-
case 38:
|
|
5328
|
-
// 0x26 Zcl56BitUint
|
|
5329
|
-
value = data.readUIntLE(i+2, 7);
|
|
5330
|
-
i += 8;
|
|
5331
|
-
break;
|
|
5332
|
-
case 39:
|
|
5333
|
-
// 0x27 Zcl64BitUint
|
|
5334
|
-
value = data.readBigUInt64BE(i+2);
|
|
5335
|
-
i += 9;
|
|
5336
|
-
break;
|
|
5337
|
-
case 40:
|
|
5338
|
-
// 0x28 Zcl8BitInt
|
|
5339
|
-
value = data.readInt8(i+2);
|
|
5340
|
-
i += 2;
|
|
5341
|
-
break;
|
|
5342
|
-
case 41:
|
|
5343
|
-
// 0x29 Zcl16BitInt
|
|
5344
|
-
value = data.readInt16LE(i+2);
|
|
5345
|
-
i += 3;
|
|
5346
|
-
break;
|
|
5347
|
-
case 42:
|
|
5348
|
-
// 0x2A Zcl24BitInt
|
|
5349
|
-
value = data.readIntLE(i+2, 3);
|
|
5350
|
-
i += 4;
|
|
5351
|
-
break;
|
|
5352
|
-
case 43:
|
|
5353
|
-
// 0x2B Zcl32BitInt
|
|
5354
|
-
value = data.readInt32LE(i+2);
|
|
5355
|
-
i += 5;
|
|
5356
|
-
break;
|
|
5357
|
-
case 44:
|
|
5358
|
-
// 0x2C Zcl40BitInt
|
|
5359
|
-
value = data.readIntLE(i+2, 5);
|
|
5360
|
-
i += 6;
|
|
5361
|
-
break;
|
|
5362
|
-
case 45:
|
|
5363
|
-
// 0x2D Zcl48BitInt
|
|
5364
|
-
value = data.readIntLE(i+2, 6);
|
|
5365
|
-
i += 7;
|
|
5366
|
-
break;
|
|
5367
|
-
case 46:
|
|
5368
|
-
// 0x2E Zcl56BitInt
|
|
5369
|
-
value = data.readIntLE(i+2, 7);
|
|
5370
|
-
i += 8;
|
|
5371
|
-
break;
|
|
5372
|
-
case 47:
|
|
5373
|
-
// 0x2F Zcl64BitInt
|
|
5374
|
-
value = data.readBigInt64BE(i+2);
|
|
5375
|
-
i += 9;
|
|
5376
|
-
break;
|
|
5377
|
-
case 57:
|
|
5378
|
-
// 0x39 ZclSingleFloat
|
|
5379
|
-
value = data.readFloatLE(i+2);
|
|
5380
|
-
i += 5;
|
|
5381
|
-
break;
|
|
5382
|
-
case 58:
|
|
5383
|
-
// 0x3a ZclDoubleFloat
|
|
5384
|
-
value = data.readDoubleLE(i+2);
|
|
5385
|
-
i += 5;
|
|
5386
|
-
break;
|
|
5387
|
-
default:
|
|
5388
|
-
if (meta.logger) meta.logger.debug(`${model.zigbeeModel}: unknown vtype=${data[i+1]}, pos=${i+1}`);
|
|
5389
|
-
}
|
|
5390
|
-
|
|
5391
|
-
if (index == 1) {
|
|
5392
|
-
payload.voltage = value;
|
|
5393
|
-
payload.battery = batteryVoltageToPercentage(value, '3V_2100');
|
|
5394
|
-
} else if (index === 3) {
|
|
5395
|
-
if (!['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5396
|
-
payload.temperature = calibrateAndPrecisionRoundOptions(value, options, 'temperature'); // 0x03
|
|
5397
|
-
}
|
|
5398
|
-
} else if (index === 5) {
|
|
5399
|
-
if (['JT-BZ-01AQ/A', 'RTCZCGQ11LM'].includes(model.model)) payload.power_outage_count = value;
|
|
5400
|
-
} else if (index === 100) {
|
|
5401
|
-
if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5402
|
-
const mapping = model.model === 'QBCZ15LM' ? 'relay' : 'left';
|
|
5403
|
-
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5404
|
-
} else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
|
|
5405
|
-
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
5406
|
-
} else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5407
|
-
// We don't know what the value means for these devices.
|
|
5408
|
-
// https://github.com/Koenkk/zigbee2mqtt/issues/11126
|
|
5409
|
-
} else {
|
|
5410
|
-
payload.state = value === 1 ? 'ON' : 'OFF';
|
|
5411
|
-
}
|
|
5412
|
-
} else if (index === 101) {
|
|
5413
|
-
if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5414
|
-
const mapping = model.model === 'QBCZ15LM' ? 'usb' : 'right';
|
|
5415
|
-
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5416
|
-
} else if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
|
|
5417
|
-
payload.state_center = value === 1 ? 'ON' : 'OFF';
|
|
5418
|
-
} else if (['RTCGQ12LM'].includes(model.model)) {
|
|
5419
|
-
payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
|
|
5420
|
-
} else if (['ZNJLBL01LM'].includes(model.model)) {
|
|
5421
|
-
payload.battery = value;
|
|
5422
|
-
}
|
|
5423
|
-
} else if (index ===102 ) {
|
|
5424
|
-
if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
|
|
5425
|
-
payload.state_right = value === 1 ? 'ON' : 'OFF';
|
|
5426
|
-
} else if (['RTCZCGQ11LM'].includes(model.model)) {
|
|
5427
|
-
payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
|
|
5428
|
-
5: 'left_leave', 6: 'approach', 7: 'away', 255: null}[value];
|
|
5429
|
-
}
|
|
5430
|
-
} else if (index === 103) {
|
|
5431
|
-
if (['RTCZCGQ11LM'].includes(model.model)) payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected';
|
|
5432
|
-
} else if (index === 105) {
|
|
5433
|
-
if (['RTCGQ13LM'].includes(model.model)) {
|
|
5434
|
-
payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value];
|
|
5435
|
-
} else if (['RTCZCGQ11LM'].includes(model.model)) {
|
|
5436
|
-
payload.approach_distance = {0: 'far', 1: 'medium', 2: 'near'}[value];
|
|
5437
|
-
}
|
|
5438
|
-
} else if (index === 149) {
|
|
5439
|
-
payload.energy = precisionRound(value, 2); // 0x95
|
|
5440
|
-
// Consumption is deprecated
|
|
5441
|
-
payload.consumption = payload.energy;
|
|
5442
|
-
} else if (index === 150) payload.voltage = precisionRound(value * 0.1, 1); // 0x96
|
|
5443
|
-
else if (index === 151) payload.current = precisionRound(value * 0.001, 4); // 0x97
|
|
5444
|
-
else if (index === 152) payload.power = precisionRound(value, 2); // 0x98
|
|
5445
|
-
else if (index === 159) payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value]; // JT-BZ-01AQ/A
|
|
5446
|
-
else if (index === 160) payload.gas = value === 1; // JT-BZ-01AQ/A
|
|
5447
|
-
else if (index === 161) payload.gas_density = value; // JT-BZ-01AQ/A
|
|
5448
|
-
else if (index === 162) payload.test = value === 1; // JT-BZ-01AQ/A
|
|
5449
|
-
else if (index === 163) payload.mute = value === 1; // JT-BZ-01AQ/A
|
|
5450
|
-
else if (index === 164) payload.state = value === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
|
|
5451
|
-
else if (index === 166) payload.linkage_alarm = value === 1; // JT-BZ-01AQ/A
|
|
5452
|
-
else if (meta.logger) meta.logger.debug(`${model.zigbeeModel}: unknown index ${index} with value ${value}`);
|
|
5453
|
-
}
|
|
5454
|
-
}
|
|
5455
|
-
|
|
5456
|
-
if (msg.data.hasOwnProperty('0')) payload.detection_period = msg.data['0'];
|
|
5457
|
-
if (msg.data.hasOwnProperty('2')) {
|
|
5458
|
-
if (['JT-BZ-01AQ/A'].includes(model.model)) payload.power_outage_count = msg.data['2'];
|
|
5459
|
-
}
|
|
5460
|
-
if (msg.data.hasOwnProperty('4')) payload.mode_switch = {4: 'anti_flicker_mode', 1: 'quick_mode'}[msg.data['4']];
|
|
5461
|
-
if (msg.data.hasOwnProperty('10')) payload.switch_type = {1: 'toggle', 2: 'momentary'}[msg.data['10']];
|
|
5462
|
-
if (msg.data.hasOwnProperty('240')) payload.flip_indicator_light = msg.data['240'] === 1 ? 'ON' : 'OFF';
|
|
5463
|
-
if (msg.data.hasOwnProperty('258')) payload.detection_interval = msg.data['258'];
|
|
5464
|
-
if (msg.data.hasOwnProperty('268')) {
|
|
5465
|
-
if (['RTCGQ13LM'].includes(model.model)) {
|
|
5466
|
-
payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[msg.data['268']];
|
|
5467
|
-
} else if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
5468
|
-
payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[msg.data['268']];
|
|
5469
|
-
}
|
|
5470
|
-
}
|
|
5471
|
-
if (msg.data.hasOwnProperty('293')) payload.click_mode = {1: 'fast', 2: 'multi'}[msg.data['293']];
|
|
5472
|
-
if (msg.data.hasOwnProperty('294')) payload.mute = msg.data['294'] === 1; // JT-BZ-01AQ/A
|
|
5473
|
-
if (msg.data.hasOwnProperty('295')) payload.test = msg.data['295'] === 1; // JT-BZ-01AQ/A
|
|
5474
|
-
if (msg.data.hasOwnProperty('313')) payload.state = msg.data['313'] === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
|
|
5475
|
-
if (msg.data.hasOwnProperty('314')) payload.gas = msg.data['314'] === 1; // JT-BZ-01AQ/A
|
|
5476
|
-
if (msg.data.hasOwnProperty('315')) payload.gas_density = msg.data['315']; // JT-BZ-01AQ/A
|
|
5477
|
-
if (msg.data.hasOwnProperty('322')) payload.presence = msg.data['322'] === 1; // RTCZCGQ11LM
|
|
5478
|
-
if (msg.data.hasOwnProperty('323')) {
|
|
5479
|
-
payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
|
|
5480
|
-
5: 'left_leave', 6: 'approach', 7: 'away'}[msg.data['323']]; // RTCZCGQ11LM
|
|
5481
|
-
}
|
|
5482
|
-
// RTCZCGQ11LM
|
|
5483
|
-
if (msg.data.hasOwnProperty('324')) payload.monitoring_mode = msg.data['324'] === 1 ? 'left_right' : 'undirected';
|
|
5484
|
-
// RTCZCGQ11LM
|
|
5485
|
-
if (msg.data.hasOwnProperty('326')) payload.approach_distance = {0: 'far', 1: 'medium', 2: 'near'}[msg.data['326']];
|
|
5486
|
-
if (msg.data.hasOwnProperty('331')) payload.linkage_alarm = msg.data['331'] === 1; // JT-BZ-01AQ/A
|
|
5487
|
-
if (msg.data.hasOwnProperty('512')) {
|
|
5488
|
-
if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5489
|
-
payload.button_lock = msg.data['512'] === 1 ? 'OFF' : 'ON';
|
|
5490
|
-
} else {
|
|
5491
|
-
const mode = {0x01: 'control_relay', 0x00: 'decoupled'}[msg.data['512']];
|
|
5492
|
-
payload[postfixWithEndpointName('operation_mode', msg, model)] = mode;
|
|
5493
|
-
}
|
|
5494
|
-
}
|
|
5495
|
-
if (msg.data.hasOwnProperty('513')) payload.power_outage_memory = msg.data['513'] === 1;
|
|
5496
|
-
if (msg.data.hasOwnProperty('514')) payload.auto_off = msg.data['514'] === 1;
|
|
5497
|
-
if (msg.data.hasOwnProperty('515')) payload.led_disabled_night = msg.data['515'] === 1;
|
|
5498
|
-
if (msg.data.hasOwnProperty('519')) payload.consumer_connected = msg.data['519'] === 1;
|
|
5499
|
-
if (msg.data.hasOwnProperty('523')) payload.overload_protection = precisionRound(msg.data['523'], 2);
|
|
5500
|
-
if (msg.data.hasOwnProperty('550')) payload.button_switch_mode = msg.data['550'] === 1 ? 'relay_and_usb' : 'relay';
|
|
5501
|
-
if (msg.data['mode'] !== undefined) payload.operation_mode = ['command', 'event'][msg.data['mode']];
|
|
5502
|
-
if (msg.data.hasOwnProperty('1289')) payload.dimmer_mode = {3: 'rgbw', 1: 'dual_ct'}[msg.data['1289']];
|
|
5299
|
+
const payload = xiaomi.numericAttributes2Payload(msg, meta, model, options, msg.data);
|
|
5503
5300
|
return payload;
|
|
5504
5301
|
},
|
|
5505
5302
|
},
|
package/converters/toZigbee.js
CHANGED
|
@@ -1599,13 +1599,23 @@ const converters = {
|
|
|
1599
1599
|
}
|
|
1600
1600
|
|
|
1601
1601
|
const state = value.toLowerCase();
|
|
1602
|
+
let oldstate = 1;
|
|
1603
|
+
if (state === 'on') {
|
|
1604
|
+
oldstate = 108;
|
|
1605
|
+
}
|
|
1606
|
+
let channel = 1.0;
|
|
1602
1607
|
const postfix = meta.endpoint_name || 'left';
|
|
1603
1608
|
await entity.command('genOnOff', 'toggle', {}, {transactionSequenceNumber: 0});
|
|
1604
1609
|
const payloadOn = {0x0001: {value: Buffer.from([1, 0, 0, 0, 0, 0, 0, 0]), type: 1}};
|
|
1605
1610
|
const payloadOff = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 1}};
|
|
1606
1611
|
const payloadOnRight = {0x0001: {value: Buffer.from([2, 0, 0, 0, 0, 0, 0, 0]), type: 2}};
|
|
1607
1612
|
const payloadOffRight = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 2}};
|
|
1613
|
+
const payloadOnBottomLeft = {0x0001: {value: Buffer.from([4, 0, 0, 0, 0, 0, 0, 0]), type: 4}};
|
|
1614
|
+
const payloadOffBottomLeft = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 4}};
|
|
1615
|
+
const payloadOnBottomRight = {0x0001: {value: Buffer.from([8, 0, 0, 0, 0, 0, 0, 0]), type: 136}};
|
|
1616
|
+
const payloadOffBottomRight = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 136}};
|
|
1608
1617
|
if (postfix === 'left') {
|
|
1618
|
+
await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', {level: oldstate, transtime: channel});
|
|
1609
1619
|
await entity.write('genPowerCfg', (state === 'on') ? payloadOn : payloadOff,
|
|
1610
1620
|
{
|
|
1611
1621
|
manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
|
|
@@ -1613,12 +1623,28 @@ const converters = {
|
|
|
1613
1623
|
});
|
|
1614
1624
|
return {state: {state_left: value.toUpperCase()}, readAfterWriteTime: 250};
|
|
1615
1625
|
} else if (postfix === 'right') {
|
|
1626
|
+
channel = 2.0;
|
|
1627
|
+
await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', {level: oldstate, transtime: channel});
|
|
1616
1628
|
await entity.write('genPowerCfg', (state === 'on') ? payloadOnRight : payloadOffRight,
|
|
1617
1629
|
{
|
|
1618
1630
|
manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
|
|
1619
1631
|
reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
|
|
1620
1632
|
});
|
|
1621
1633
|
return {state: {state_right: value.toUpperCase()}, readAfterWriteTime: 250};
|
|
1634
|
+
} else if (postfix === 'bottom_right') {
|
|
1635
|
+
await entity.write('genPowerCfg', (state === 'on') ? payloadOnBottomRight : payloadOffBottomRight,
|
|
1636
|
+
{
|
|
1637
|
+
manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
|
|
1638
|
+
reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
|
|
1639
|
+
});
|
|
1640
|
+
return {state: {state_bottom_right: value.toUpperCase()}, readAfterWriteTime: 250};
|
|
1641
|
+
} else if (postfix === 'bottom_left') {
|
|
1642
|
+
await entity.write('genPowerCfg', (state === 'on') ? payloadOnBottomLeft : payloadOffBottomLeft,
|
|
1643
|
+
{
|
|
1644
|
+
manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
|
|
1645
|
+
reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
|
|
1646
|
+
});
|
|
1647
|
+
return {state: {state_bottom_left: value.toUpperCase()}, readAfterWriteTime: 250};
|
|
1622
1648
|
}
|
|
1623
1649
|
return {state: {state: value.toUpperCase()}, readAfterWriteTime: 250};
|
|
1624
1650
|
},
|
|
@@ -13,7 +13,7 @@ const tzLocal = {
|
|
|
13
13
|
convertSet: async (entity, key, value, meta) => {
|
|
14
14
|
const state = value.toLowerCase();
|
|
15
15
|
utils.validateValue(state, ['toggle', 'off', 'on']);
|
|
16
|
-
const endpoint = meta.device.getEndpoint(3);
|
|
16
|
+
const endpoint = meta.mapped.model === 'AU-A1ZBDSS' ? meta.device.getEndpoint(3) : meta.device.getEndpoint(2);
|
|
17
17
|
await endpoint.command('genOnOff', state, {});
|
|
18
18
|
return {state: {backlight_led: state.toUpperCase()}};
|
|
19
19
|
},
|
package/devices/hive.js
CHANGED
|
@@ -291,7 +291,7 @@ module.exports = [
|
|
|
291
291
|
.withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
|
|
292
292
|
' used. 0 to 360 to match the remote display').withEndpoint('heat'),
|
|
293
293
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 22, 22, 1).withLocalTemperature()
|
|
294
|
-
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
294
|
+
.withSystemMode(['off', 'auto', 'heat', 'emergency_heating']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
295
295
|
exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
|
|
296
296
|
.withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
|
|
297
297
|
' Must be set to `false` when system_mode = off or `true` for heat').withEndpoint('water'),
|
|
@@ -342,7 +342,7 @@ module.exports = [
|
|
|
342
342
|
.withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
|
|
343
343
|
' used. 0 to 360 to match the remote display').withEndpoint('heat'),
|
|
344
344
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 22, 22, 1).withLocalTemperature()
|
|
345
|
-
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
345
|
+
.withSystemMode(['off', 'auto', 'heat', 'emergency_heating']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
346
346
|
exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
|
|
347
347
|
.withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
|
|
348
348
|
' Must be set to `false` when system_mode = off or `true` for heat').withEndpoint('water'),
|
|
@@ -393,7 +393,7 @@ module.exports = [
|
|
|
393
393
|
.withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
|
|
394
394
|
' used. 0 to 360 to match the remote display').withEndpoint('heat'),
|
|
395
395
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 22, 22, 1).withLocalTemperature()
|
|
396
|
-
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
396
|
+
.withSystemMode(['off', 'auto', 'heat', 'emergency_heating']).withRunningState(['idle', 'heat']).withEndpoint('water'),
|
|
397
397
|
exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
|
|
398
398
|
.withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
|
|
399
399
|
' Must be set to `false` when system_mode = off or `true` for heat').withEndpoint('water'),
|
package/devices/livolo.js
CHANGED
|
@@ -20,13 +20,18 @@ module.exports = [
|
|
|
20
20
|
{
|
|
21
21
|
zigbeeModel: ['TI0001 '],
|
|
22
22
|
model: 'TI0001',
|
|
23
|
-
description: 'Zigbee switch (1
|
|
23
|
+
description: 'Zigbee switch (1, 2, 3, 4 gang)',
|
|
24
24
|
vendor: 'Livolo',
|
|
25
|
-
exposes: [
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
exposes: [
|
|
26
|
+
e.switch().withEndpoint('left'),
|
|
27
|
+
e.switch().withEndpoint('right'),
|
|
28
|
+
e.switch().withEndpoint('bottom_left'),
|
|
29
|
+
e.switch().withEndpoint('bottom_right'),
|
|
30
|
+
],
|
|
31
|
+
fromZigbee: [fz.livolo_switch_state, fz.livolo_switch_state_raw, fz.livolo_new_switch_state_4gang],
|
|
32
|
+
toZigbee: [tz.livolo_socket_switch_on_off],
|
|
28
33
|
endpoint: (device) => {
|
|
29
|
-
return {'left': 6, 'right': 6};
|
|
34
|
+
return {'left': 6, 'right': 6, 'bottom_left': 6, 'bottom_right': 6};
|
|
30
35
|
},
|
|
31
36
|
configure: poll,
|
|
32
37
|
onEvent: async (type, data, device) => {
|
|
@@ -41,6 +46,18 @@ module.exports = [
|
|
|
41
46
|
globalStore.putValue(device, 'interval', interval);
|
|
42
47
|
}
|
|
43
48
|
}
|
|
49
|
+
if (data.cluster === 'genPowerCfg' && data.type === 'raw') {
|
|
50
|
+
const dp = data.data[10];
|
|
51
|
+
if (data.data[0] === 0x7a && data.data[1] === 0xd1) {
|
|
52
|
+
const endpoint = device.getEndpoint(6);
|
|
53
|
+
if (dp === 0x01) {
|
|
54
|
+
const options = {manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
|
|
55
|
+
reservedBits: 3, direction: 1, writeUndiv: true};
|
|
56
|
+
const payload = {0x2002: {value: [0, 0, 0, 0, 0, 0, 0], type: 0x0e}};
|
|
57
|
+
await endpoint.readResponse('genPowerCfg', 0xe9, payload, options);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
},
|
|
45
62
|
},
|
|
46
63
|
{
|
package/devices/sengled.js
CHANGED
|
@@ -14,7 +14,8 @@ module.exports = [
|
|
|
14
14
|
description: 'Flood light with motion sensor light outdoor',
|
|
15
15
|
fromZigbee: extend.light_onoff_brightness().fromZigbee.concat([fz.ias_occupancy_alarm_1]),
|
|
16
16
|
toZigbee: extend.light_onoff_brightness().toZigbee,
|
|
17
|
-
exposes:
|
|
17
|
+
exposes: extend.light_onoff_brightness().exposes.concat([e.occupancy()]),
|
|
18
|
+
ota: ota.zigbeeOTA,
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
21
|
zigbeeModel: ['E21-N13A'],
|
|
@@ -29,7 +30,22 @@ module.exports = [
|
|
|
29
30
|
model: 'E21-N1EA',
|
|
30
31
|
vendor: 'Sengled',
|
|
31
32
|
description: 'Smart LED multicolor A19 bulb',
|
|
32
|
-
|
|
33
|
+
fromZigbee: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).fromZigbee.concat([fz.metering]),
|
|
34
|
+
toZigbee: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).toZigbee,
|
|
35
|
+
exposes: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).exposes.concat([e.power(), e.energy()]),
|
|
36
|
+
ota: ota.zigbeeOTA,
|
|
37
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
38
|
+
await extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]})
|
|
39
|
+
.configure(device, coordinatorEndpoint, logger);
|
|
40
|
+
device.powerSource = 'Mains (single phase)';
|
|
41
|
+
device.save();
|
|
42
|
+
|
|
43
|
+
const endpoint = device.getEndpoint(1);
|
|
44
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
45
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
46
|
+
await reporting.currentSummDelivered(endpoint);
|
|
47
|
+
await reporting.instantaneousDemand(endpoint);
|
|
48
|
+
},
|
|
33
49
|
},
|
|
34
50
|
{
|
|
35
51
|
zigbeeModel: ['E12-N1E'],
|
|
@@ -62,6 +78,7 @@ module.exports = [
|
|
|
62
78
|
description: 'Element classic (A19)',
|
|
63
79
|
fromZigbee: extend.light_onoff_brightness().fromZigbee.concat([fz.metering]),
|
|
64
80
|
toZigbee: extend.light_onoff_brightness().toZigbee,
|
|
81
|
+
ota: ota.zigbeeOTA,
|
|
65
82
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
66
83
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
67
84
|
device.powerSource = 'Mains (single phase)';
|
|
@@ -73,7 +90,7 @@ module.exports = [
|
|
|
73
90
|
await reporting.currentSummDelivered(endpoint);
|
|
74
91
|
await reporting.instantaneousDemand(endpoint);
|
|
75
92
|
},
|
|
76
|
-
exposes: [e.power(), e.energy()
|
|
93
|
+
exposes: extend.light_onoff_brightness().exposes.concat([e.power(), e.energy()]),
|
|
77
94
|
},
|
|
78
95
|
{
|
|
79
96
|
zigbeeModel: ['E11-G23', 'E11-G33'],
|
|
@@ -149,8 +166,22 @@ module.exports = [
|
|
|
149
166
|
model: 'E1F-N5E',
|
|
150
167
|
vendor: 'Sengled',
|
|
151
168
|
description: 'Element color plus E12',
|
|
152
|
-
|
|
169
|
+
fromZigbee: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).fromZigbee.concat([fz.metering]),
|
|
170
|
+
toZigbee: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).toZigbee,
|
|
171
|
+
exposes: extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]}).exposes.concat([e.power(), e.energy()]),
|
|
153
172
|
ota: ota.zigbeeOTA,
|
|
173
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
174
|
+
await extend.light_onoff_brightness_colortemp_color({colorTempRange: [154, 500]})
|
|
175
|
+
.configure(device, coordinatorEndpoint, logger);
|
|
176
|
+
device.powerSource = 'Mains (single phase)';
|
|
177
|
+
device.save();
|
|
178
|
+
|
|
179
|
+
const endpoint = device.getEndpoint(1);
|
|
180
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
181
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
182
|
+
await reporting.currentSummDelivered(endpoint);
|
|
183
|
+
await reporting.instantaneousDemand(endpoint);
|
|
184
|
+
},
|
|
154
185
|
},
|
|
155
186
|
{
|
|
156
187
|
zigbeeModel: ['E12-N14'],
|
|
@@ -206,15 +237,17 @@ module.exports = [
|
|
|
206
237
|
await reporting.instantaneousDemand(endpoint);
|
|
207
238
|
},
|
|
208
239
|
exposes: [e.switch(), e.power(), e.energy()],
|
|
240
|
+
ota: ota.zigbeeOTA,
|
|
209
241
|
},
|
|
210
242
|
{
|
|
211
243
|
zigbeeModel: ['E1E-G7F'],
|
|
212
244
|
model: 'E1E-G7F',
|
|
213
245
|
vendor: 'Sengled',
|
|
214
|
-
description: 'Smart switch
|
|
246
|
+
description: 'Smart switch',
|
|
215
247
|
fromZigbee: [fz.E1E_G7F_action],
|
|
216
248
|
exposes: [e.action(['on', 'up', 'down', 'off', 'on_double', 'on_long', 'off_double', 'off_long'])],
|
|
217
249
|
toZigbee: [],
|
|
250
|
+
ota: ota.zigbeeOTA,
|
|
218
251
|
},
|
|
219
252
|
{
|
|
220
253
|
zigbeeModel: ['E11-N1G'],
|
|
@@ -222,6 +255,7 @@ module.exports = [
|
|
|
222
255
|
vendor: 'Sengled',
|
|
223
256
|
description: 'Vintage LED edison bulb (ST19)',
|
|
224
257
|
extend: extend.light_onoff_brightness(),
|
|
258
|
+
ota: ota.zigbeeOTA,
|
|
225
259
|
},
|
|
226
260
|
{
|
|
227
261
|
zigbeeModel: ['E1F-N9G'],
|
|
@@ -229,5 +263,6 @@ module.exports = [
|
|
|
229
263
|
vendor: 'Sengled',
|
|
230
264
|
description: 'Smart LED filament candle (E12)',
|
|
231
265
|
extend: extend.light_onoff_brightness(),
|
|
266
|
+
ota: ota.zigbeeOTA,
|
|
232
267
|
},
|
|
233
268
|
];
|
package/devices/smartthings.js
CHANGED
|
@@ -157,7 +157,10 @@ module.exports = [
|
|
|
157
157
|
const endpoint = device.getEndpoint(1);
|
|
158
158
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
|
|
159
159
|
await reporting.onOff(endpoint);
|
|
160
|
-
|
|
160
|
+
try {
|
|
161
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/11706
|
|
162
|
+
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
163
|
+
} catch (error) {/* Fails for some*/}
|
|
161
164
|
await reporting.activePower(endpoint);
|
|
162
165
|
await reporting.rmsCurrent(endpoint);
|
|
163
166
|
await reporting.rmsVoltage(endpoint, {change: 10});
|