zigbee-herdsman-converters 14.0.411 → 14.0.415
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 +128 -83
- package/converters/toZigbee.js +77 -26
- package/devices/bticino.js +10 -10
- package/devices/custom_devices_diy.js +40 -0
- package/devices/develco.js +3 -1
- package/devices/frankever.js +2 -1
- package/devices/gledopto.js +20 -7
- package/devices/heiman.js +1 -1
- package/devices/jasco.js +18 -0
- package/devices/legrand.js +33 -12
- package/devices/moes.js +6 -6
- package/devices/philips.js +9 -0
- package/devices/prolight.js +12 -0
- package/devices/titan_products.js +2 -1
- package/devices/tuya.js +29 -12
- package/devices/xiaomi.js +35 -35
- package/devices/zemismart.js +13 -8
- package/lib/exposes.js +2 -1
- package/lib/reporting.js +6 -1
- package/lib/tuya.js +5 -4
- package/lib/utils.js +2 -0
- package/npm-shrinkwrap.json +426 -401
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -2420,6 +2420,12 @@ const converters = {
|
|
|
2420
2420
|
convert: (model, msg, publish, options, meta) => {
|
|
2421
2421
|
const dpValue = tuya.firstDpValue(msg, meta, 'moes_switch');
|
|
2422
2422
|
const dp = dpValue.dp;
|
|
2423
|
+
|
|
2424
|
+
// tuya_switch datapoints
|
|
2425
|
+
if (dp >= 1 && dp <= 4) {
|
|
2426
|
+
return null;
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2423
2429
|
const value = tuya.getDataValue(dpValue);
|
|
2424
2430
|
|
|
2425
2431
|
switch (dp) {
|
|
@@ -2637,6 +2643,31 @@ const converters = {
|
|
|
2637
2643
|
}
|
|
2638
2644
|
},
|
|
2639
2645
|
},
|
|
2646
|
+
ts011f_plug_indicator_mode: {
|
|
2647
|
+
cluster: 'genOnOff',
|
|
2648
|
+
type: ['attributeReport', 'readResponse'],
|
|
2649
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2650
|
+
const property = 'tuyaBacklightMode'; // 0x8001 or 32769
|
|
2651
|
+
if (msg.data.hasOwnProperty(property)) {
|
|
2652
|
+
const value = msg.data[property];
|
|
2653
|
+
const lookup = {0: 'off', 1: 'off/on', 2: 'on/off', 3: 'on'};
|
|
2654
|
+
if (lookup.hasOwnProperty(value)) {
|
|
2655
|
+
return {indicator_mode: lookup[value]};
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
},
|
|
2659
|
+
},
|
|
2660
|
+
ts011f_plug_child_mode: {
|
|
2661
|
+
cluster: 'genOnOff',
|
|
2662
|
+
type: ['attributeReport', 'readResponse'],
|
|
2663
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2664
|
+
const property = (0x8000).toString(); // 32768
|
|
2665
|
+
if (msg.data.hasOwnProperty(property)) {
|
|
2666
|
+
const value = msg.data[property];
|
|
2667
|
+
return {child_lock: value ? 'LOCK' : 'UNLOCK'};
|
|
2668
|
+
}
|
|
2669
|
+
},
|
|
2670
|
+
},
|
|
2640
2671
|
WSZ01_on_off_action: {
|
|
2641
2672
|
cluster: 65029,
|
|
2642
2673
|
type: 'raw',
|
|
@@ -5059,27 +5090,28 @@ const converters = {
|
|
|
5059
5090
|
}
|
|
5060
5091
|
},
|
|
5061
5092
|
},
|
|
5062
|
-
|
|
5093
|
+
legrand_cluster_fc01: {
|
|
5063
5094
|
cluster: 'manuSpecificLegrandDevices',
|
|
5064
5095
|
type: ['readResponse'],
|
|
5065
5096
|
convert: (model, msg, publish, options, meta) => {
|
|
5066
5097
|
const payload = {};
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
payload.device_mode = 'unknown';
|
|
5098
|
+
|
|
5099
|
+
if (msg.data.hasOwnProperty('0')) {
|
|
5100
|
+
const option0 = msg.data['0'];
|
|
5101
|
+
|
|
5102
|
+
if (option0 === 0x0001) payload.device_mode = 'pilot_off';
|
|
5103
|
+
else if (option0 === 0x0002) payload.device_mode = 'pilot_on';
|
|
5104
|
+
else if (option0 === 0x0003) payload.device_mode = 'switch';
|
|
5105
|
+
else if (option0 === 0x0004) payload.device_mode = 'auto';
|
|
5106
|
+
else if (option0 === 0x0100) payload.device_mode = 'dimmer_off';
|
|
5107
|
+
else if (option0 === 0x0101) payload.device_mode = 'dimmer_on';
|
|
5108
|
+
else {
|
|
5109
|
+
meta.logger.warn(`device_mode ${option0} not recognized, please fix me`);
|
|
5110
|
+
payload.device_mode = 'unknown';
|
|
5111
|
+
}
|
|
5082
5112
|
}
|
|
5113
|
+
if (msg.data.hasOwnProperty('1')) payload.permanent_led = msg.data['1'] === 0x00 ? 'OFF' : 'ON';
|
|
5114
|
+
if (msg.data.hasOwnProperty('2')) payload.led_when_on = msg.data['2'] === 0x00 ? 'OFF' : 'ON';
|
|
5083
5115
|
return payload;
|
|
5084
5116
|
},
|
|
5085
5117
|
},
|
|
@@ -5329,8 +5361,11 @@ const converters = {
|
|
|
5329
5361
|
if (index == 1) {
|
|
5330
5362
|
payload.voltage = value;
|
|
5331
5363
|
payload.battery = batteryVoltageToPercentage(value, '3V_2100');
|
|
5332
|
-
} else if (index === 3)
|
|
5333
|
-
|
|
5364
|
+
} else if (index === 3) {
|
|
5365
|
+
if (!['WXCJKG11LM ', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5366
|
+
payload.temperature = calibrateAndPrecisionRoundOptions(value, options, 'temperature'); // 0x03
|
|
5367
|
+
}
|
|
5368
|
+
} else if (index === 5) {
|
|
5334
5369
|
if (['JT-BZ-01AQ/A', 'RTCZCGQ11LM'].includes(model.model)) payload.power_outage_count = value;
|
|
5335
5370
|
} else if (index === 100) {
|
|
5336
5371
|
if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
@@ -5338,7 +5373,7 @@ const converters = {
|
|
|
5338
5373
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5339
5374
|
} else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
|
|
5340
5375
|
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
5341
|
-
} else if (['WXCJKG11LM
|
|
5376
|
+
} else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5342
5377
|
// We don't know what the value means for these devices.
|
|
5343
5378
|
// https://github.com/Koenkk/zigbee2mqtt/issues/11126
|
|
5344
5379
|
} else {
|
|
@@ -8300,79 +8335,89 @@ const converters = {
|
|
|
8300
8335
|
return {action};
|
|
8301
8336
|
},
|
|
8302
8337
|
},
|
|
8303
|
-
|
|
8338
|
+
ZMAM02_cover: {
|
|
8304
8339
|
cluster: 'manuSpecificTuya',
|
|
8305
|
-
type: ['
|
|
8340
|
+
type: ['commandDataReport', 'commandDataResponse'],
|
|
8341
|
+
options: [exposes.options.invert_cover()],
|
|
8306
8342
|
convert: (model, msg, publish, options, meta) => {
|
|
8307
|
-
const
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8343
|
+
const dpValue = tuya.firstDpValue(msg, meta, 'ZMAM02_cover');
|
|
8344
|
+
const dp = dpValue.dp;
|
|
8345
|
+
const value = tuya.getDataValue(dpValue);
|
|
8346
|
+
switch (dp) {
|
|
8347
|
+
case tuya.dataPoints.coverPosition: // Started moving to position (triggered from Zigbee)
|
|
8348
|
+
case tuya.dataPoints.coverArrived: { // Arrived at position
|
|
8349
|
+
const running = dp === tuya.dataPoints.coverArrived ? false : true;
|
|
8350
|
+
const invert = tuya.isCoverInverted(meta.device.manufacturerName) ? !options.invert_cover : options.invert_cover;
|
|
8351
|
+
const position = invert ? 100 - (value & 0xFF) : (value & 0xFF);
|
|
8352
|
+
if (position > 0 && position <= 100) {
|
|
8353
|
+
return {running, position, state: 'OPEN'};
|
|
8354
|
+
} else if (position == 0) { // Report fully closed
|
|
8355
|
+
return {running, position, state: 'CLOSE'};
|
|
8356
|
+
} else {
|
|
8357
|
+
return {running}; // Not calibrated yet, no position is available
|
|
8358
|
+
}
|
|
8359
|
+
}
|
|
8360
|
+
case tuya.dataPoints.coverSpeed: // Cover is reporting its current speed setting
|
|
8361
|
+
return {motor_speed: value};
|
|
8362
|
+
case tuya.dataPoints.state: // Ignore the cover state, it's not reliable between different covers!
|
|
8363
|
+
case tuya.dataPoints.coverChange: // Ignore manual cover change, it's not reliable between different covers!
|
|
8364
|
+
break;
|
|
8365
|
+
case tuya.dataPoints.config: // Returned by configuration set; ignore
|
|
8366
|
+
break;
|
|
8367
|
+
case tuya.dataPoints.AM02MotorWorkingMode:
|
|
8368
|
+
switch (value) {
|
|
8369
|
+
case 0: // continuous 1
|
|
8370
|
+
return {motor_working_mode: 'continuous'};
|
|
8371
|
+
case 1: // intermittently
|
|
8372
|
+
return {motor_working_mode: 'intermittently'};
|
|
8373
|
+
default:
|
|
8374
|
+
meta.logger.warn('ZMAM02: ' +
|
|
8375
|
+
`Mode ${value} is not recognized.`);
|
|
8318
8376
|
break;
|
|
8319
|
-
|
|
8320
|
-
|
|
8377
|
+
}
|
|
8378
|
+
break;
|
|
8379
|
+
case tuya.dataPoints.AM02Border:
|
|
8380
|
+
switch (value) {
|
|
8381
|
+
case 0: // up
|
|
8382
|
+
return {border: 'up'};
|
|
8383
|
+
case 1: // down
|
|
8384
|
+
return {border: 'down'};
|
|
8385
|
+
case 2: // down_delete
|
|
8386
|
+
return {border: 'down_delete'};
|
|
8387
|
+
default:
|
|
8388
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8389
|
+
`Mode ${value} is not recognized.`);
|
|
8321
8390
|
break;
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
break;
|
|
8334
|
-
}
|
|
8391
|
+
}
|
|
8392
|
+
break;
|
|
8393
|
+
case tuya.dataPoints.AM02Direction:
|
|
8394
|
+
switch (value) {
|
|
8395
|
+
case 0:
|
|
8396
|
+
return {motor_direction: 'forward'};
|
|
8397
|
+
case 1:
|
|
8398
|
+
return {motor_direction: 'back'};
|
|
8399
|
+
default:
|
|
8400
|
+
meta.logger.warn('ZMAM02: ' +
|
|
8401
|
+
`Mode ${value} is not recognized.`);
|
|
8335
8402
|
break;
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
break;
|
|
8347
|
-
default:
|
|
8348
|
-
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8403
|
+
}
|
|
8404
|
+
break;
|
|
8405
|
+
case tuya.dataPoints.AM02Mode:
|
|
8406
|
+
switch (value) {
|
|
8407
|
+
case 0: // morning
|
|
8408
|
+
return {mode: 'morning'};
|
|
8409
|
+
case 1: // night
|
|
8410
|
+
return {mode: 'night'};
|
|
8411
|
+
default:
|
|
8412
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8349
8413
|
`Mode ${value} is not recognized.`);
|
|
8350
|
-
break;
|
|
8351
|
-
}
|
|
8352
|
-
break;
|
|
8353
|
-
case tuya.dataPoints.AM02PercentState:
|
|
8354
|
-
result.percent_state = value;
|
|
8355
|
-
break;
|
|
8356
|
-
case tuya.dataPoints.AM02Mode:
|
|
8357
|
-
switch (value) {
|
|
8358
|
-
case 0: // morning
|
|
8359
|
-
result.mode = 'morning';
|
|
8360
|
-
break;
|
|
8361
|
-
case 1: // night
|
|
8362
|
-
result.mode = 'night';
|
|
8363
|
-
break;
|
|
8364
|
-
default:
|
|
8365
|
-
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8366
|
-
`Mode ${value} is not recognized.`);
|
|
8367
|
-
break;
|
|
8368
|
-
}
|
|
8369
8414
|
break;
|
|
8370
|
-
default:
|
|
8371
|
-
meta.logger.warn(`fromZigbee.Zemismart Shader Konverter (Zm_AM02): NOT RECOGNIZED ` +
|
|
8372
|
-
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
8373
8415
|
}
|
|
8416
|
+
break;
|
|
8417
|
+
default: // Unknown code
|
|
8418
|
+
meta.logger.warn(`ZMAM02_cover: Unhandled DP #${dp} for ${meta.device.manufacturerName}:
|
|
8419
|
+
${JSON.stringify(dpValue)}`);
|
|
8374
8420
|
}
|
|
8375
|
-
return result;
|
|
8376
8421
|
},
|
|
8377
8422
|
},
|
|
8378
8423
|
// #endregion
|
package/converters/toZigbee.js
CHANGED
|
@@ -2211,7 +2211,7 @@ const converters = {
|
|
|
2211
2211
|
key: ['led_disabled_night'],
|
|
2212
2212
|
convertSet: async (entity, key, value, meta) => {
|
|
2213
2213
|
if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
|
|
2214
|
-
'QBKG31LM', 'QBKG34LM', 'DLKZMK11LM'].includes(meta.mapped.model)) {
|
|
2214
|
+
'QBKG31LM', 'QBKG34LM', 'DLKZMK11LM', 'SSM-U01'].includes(meta.mapped.model)) {
|
|
2215
2215
|
await entity.write('aqaraOpple', {0x0203: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
|
|
2216
2216
|
} else if (['ZNCZ11LM'].includes(meta.mapped.model)) {
|
|
2217
2217
|
const payload = value ?
|
|
@@ -2226,7 +2226,7 @@ const converters = {
|
|
|
2226
2226
|
},
|
|
2227
2227
|
convertGet: async (entity, key, meta) => {
|
|
2228
2228
|
if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
|
|
2229
|
-
'QBKG31LM', 'QBKG34LM', 'DLKZMK11LM'].includes(meta.mapped.model)) {
|
|
2229
|
+
'QBKG31LM', 'QBKG34LM', 'DLKZMK11LM', 'SSM-U01'].includes(meta.mapped.model)) {
|
|
2230
2230
|
await entity.read('aqaraOpple', [0x0203], manufacturerOptions.xiaomi);
|
|
2231
2231
|
} else {
|
|
2232
2232
|
throw new Error('Not supported');
|
|
@@ -3218,7 +3218,7 @@ const converters = {
|
|
|
3218
3218
|
);
|
|
3219
3219
|
break;
|
|
3220
3220
|
case 'indicate_light':
|
|
3221
|
-
await tuya.
|
|
3221
|
+
await tuya.sendDataPointEnum(
|
|
3222
3222
|
entity,
|
|
3223
3223
|
tuya.dataPoints.moesSwitchIndicateLight,
|
|
3224
3224
|
utils.getKey(tuya.moesSwitch.indicateLight, value),
|
|
@@ -4523,6 +4523,10 @@ const converters = {
|
|
|
4523
4523
|
const enableLedIfOn = value === 'ON' || (value === 'OFF' ? false : !!value);
|
|
4524
4524
|
const payload = {1: {value: enableLedIfOn, type: 16}};
|
|
4525
4525
|
await entity.write('manuSpecificLegrandDevices', payload, manufacturerOptions.legrand);
|
|
4526
|
+
return {state: {'permanent_led': value}};
|
|
4527
|
+
},
|
|
4528
|
+
convertGet: async (entity, key, meta) => {
|
|
4529
|
+
await entity.read('manuSpecificLegrandDevices', [0x0001], manufacturerOptions.legrand);
|
|
4526
4530
|
},
|
|
4527
4531
|
},
|
|
4528
4532
|
legrand_settingEnableLedIfOn: {
|
|
@@ -4534,15 +4538,10 @@ const converters = {
|
|
|
4534
4538
|
const enableLedIfOn = value === 'ON' || (value === 'OFF' ? false : !!value);
|
|
4535
4539
|
const payload = {2: {value: enableLedIfOn, type: 16}};
|
|
4536
4540
|
await entity.write('manuSpecificLegrandDevices', payload, manufacturerOptions.legrand);
|
|
4541
|
+
return {state: {'led_when_on': value}};
|
|
4537
4542
|
},
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
key: ['dimmer_enabled'],
|
|
4541
|
-
convertSet: async (entity, key, value, meta) => {
|
|
4542
|
-
// enable the dimmer, requires a recent firmware on the device
|
|
4543
|
-
const enableDimmer = value === 'ON' || (value === 'OFF' ? false : !!value);
|
|
4544
|
-
const payload = {0: {value: enableDimmer ? 0x0101 : 0x0100, type: 9}};
|
|
4545
|
-
await entity.write('manuSpecificLegrandDevices', payload, manufacturerOptions.legrand);
|
|
4543
|
+
convertGet: async (entity, key, meta) => {
|
|
4544
|
+
await entity.read('manuSpecificLegrandDevices', [0x0002], manufacturerOptions.legrand);
|
|
4546
4545
|
},
|
|
4547
4546
|
},
|
|
4548
4547
|
legrand_deviceMode: {
|
|
@@ -5995,6 +5994,32 @@ const converters = {
|
|
|
5995
5994
|
await entity.read('genOnOff', ['tuyaBacklightMode']);
|
|
5996
5995
|
},
|
|
5997
5996
|
},
|
|
5997
|
+
ts011f_plug_indicator_mode: {
|
|
5998
|
+
key: ['indicator_mode'],
|
|
5999
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6000
|
+
if (typeof value === 'string') {
|
|
6001
|
+
value = value.toLowerCase();
|
|
6002
|
+
const lookup = {'off': 0, 'off/on': 1, 'on/off': 2, 'on': 3};
|
|
6003
|
+
utils.validateValue(value, Object.keys(lookup));
|
|
6004
|
+
value = lookup[value];
|
|
6005
|
+
}
|
|
6006
|
+
|
|
6007
|
+
if (typeof value === 'number' && value >= 0 && value <= 3) {
|
|
6008
|
+
await entity.write('genOnOff', {tuyaBacklightMode: value});
|
|
6009
|
+
} else {
|
|
6010
|
+
meta.logger.warn(`toZigbee.ts011f_plug_indicator_mode: Unsupported value ${value}`);
|
|
6011
|
+
}
|
|
6012
|
+
},
|
|
6013
|
+
convertGet: async (entity, key, meta) => {
|
|
6014
|
+
await entity.read('genOnOff', ['tuyaBacklightMode']);
|
|
6015
|
+
},
|
|
6016
|
+
},
|
|
6017
|
+
ts011f_plug_child_mode: {
|
|
6018
|
+
key: ['child_lock'],
|
|
6019
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6020
|
+
await entity.write('genOnOff', {0x8000: {value: value === 'LOCK', type: 0x10}});
|
|
6021
|
+
},
|
|
6022
|
+
},
|
|
5998
6023
|
hy_thermostat: {
|
|
5999
6024
|
key: [
|
|
6000
6025
|
'child_lock', 'current_heating_setpoint', 'local_temperature_calibration',
|
|
@@ -6899,30 +6924,56 @@ const converters = {
|
|
|
6899
6924
|
}
|
|
6900
6925
|
},
|
|
6901
6926
|
},
|
|
6902
|
-
|
|
6903
|
-
key: ['
|
|
6927
|
+
ZMAM02_cover: {
|
|
6928
|
+
key: ['state', 'position', 'mode', 'motor_direction', 'border', 'motor_working_mode'],
|
|
6929
|
+
options: [exposes.options.invert_cover()],
|
|
6904
6930
|
convertSet: async (entity, key, value, meta) => {
|
|
6931
|
+
if (key === 'position') {
|
|
6932
|
+
if (value >= 0 && value <= 100) {
|
|
6933
|
+
const invert = tuya.isCoverInverted(meta.device.manufacturerName) ?
|
|
6934
|
+
!meta.options.invert_cover : meta.options.invert_cover;
|
|
6935
|
+
|
|
6936
|
+
value = invert ? 100 - value : value;
|
|
6937
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.coverPosition, value);
|
|
6938
|
+
} else {
|
|
6939
|
+
throw new Error('TuYa_cover_control: Curtain motor position is out of range');
|
|
6940
|
+
}
|
|
6941
|
+
} else if (key === 'state') {
|
|
6942
|
+
const stateEnums = tuya.getCoverStateEnums(meta.device.manufacturerName);
|
|
6943
|
+
meta.logger.debug(`ZMAM02: Using state enums for ${meta.device.manufacturerName}:
|
|
6944
|
+
${JSON.stringify(stateEnums)}`);
|
|
6945
|
+
value = value.toLowerCase();
|
|
6946
|
+
switch (value) {
|
|
6947
|
+
case 'close':
|
|
6948
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, stateEnums.close);
|
|
6949
|
+
break;
|
|
6950
|
+
case 'open':
|
|
6951
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, stateEnums.open);
|
|
6952
|
+
break;
|
|
6953
|
+
case 'stop':
|
|
6954
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, stateEnums.stop);
|
|
6955
|
+
break;
|
|
6956
|
+
default:
|
|
6957
|
+
throw new Error('ZMAM02: Invalid command received');
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6905
6960
|
switch (key) {
|
|
6906
|
-
case 'control':
|
|
6907
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, utils.getKey(tuya.ZMAM02.AM02Control, value));
|
|
6908
|
-
break;
|
|
6909
|
-
case 'percent_control':
|
|
6910
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.AM02PercentState, value);
|
|
6911
|
-
break;
|
|
6912
6961
|
case 'mode':
|
|
6913
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.
|
|
6962
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.ZMLookups.AM02Mode, value));
|
|
6914
6963
|
break;
|
|
6915
|
-
case '
|
|
6916
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.
|
|
6964
|
+
case 'motor_direction':
|
|
6965
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Direction, utils.getKey(tuya.ZMLookups.AM02Direction, value));
|
|
6917
6966
|
break;
|
|
6918
6967
|
case 'border':
|
|
6919
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.
|
|
6968
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.ZMLookups.AM02Border, value));
|
|
6920
6969
|
break;
|
|
6921
6970
|
case 'motor_working_mode':
|
|
6922
|
-
await tuya.sendDataPointEnum(
|
|
6971
|
+
await tuya.sendDataPointEnum(
|
|
6972
|
+
entity,
|
|
6973
|
+
tuya.dataPoints.AM02MotorWorkingMode,
|
|
6974
|
+
utils.getKey(tuya.ZMLookups.AM02MotorWorkingMode,
|
|
6975
|
+
value));
|
|
6923
6976
|
break;
|
|
6924
|
-
default: // Unknown Key
|
|
6925
|
-
meta.logger.warn(`toZigbee.ZMAM02: Unhandled Key ${key}`);
|
|
6926
6977
|
}
|
|
6927
6978
|
},
|
|
6928
6979
|
},
|
package/devices/bticino.js
CHANGED
|
@@ -12,12 +12,12 @@ module.exports = [
|
|
|
12
12
|
model: 'K4003C/L4003C/N4003C/NT4003C',
|
|
13
13
|
vendor: 'BTicino',
|
|
14
14
|
description: 'Light switch with neutral',
|
|
15
|
-
fromZigbee: [fz.identify, fz.on_off, fz.K4003C_binary_input],
|
|
15
|
+
fromZigbee: [fz.identify, fz.on_off, fz.K4003C_binary_input, fz.legrand_cluster_fc01],
|
|
16
16
|
toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn, tz.legrand_identify],
|
|
17
17
|
exposes: [
|
|
18
18
|
e.switch(), e.action(['identify', 'on', 'off']),
|
|
19
|
-
exposes.binary('permanent_led', ea.
|
|
20
|
-
exposes.binary('led_when_on', ea.
|
|
19
|
+
exposes.binary('permanent_led', ea.ALL, 'ON', 'OFF').withDescription('Enable or disable the permanent blue LED'),
|
|
20
|
+
exposes.binary('led_when_on', ea.ALL, 'ON', 'OFF').withDescription('Enables the LED when the light is on'),
|
|
21
21
|
],
|
|
22
22
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
23
23
|
const endpoint = device.getEndpoint(1);
|
|
@@ -30,17 +30,17 @@ module.exports = [
|
|
|
30
30
|
vendor: 'BTicino',
|
|
31
31
|
description: 'Dimmer switch with neutral',
|
|
32
32
|
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
33
|
-
fromZigbee: [fz.brightness, fz.identify, fz.on_off, fz.lighting_ballast_configuration],
|
|
33
|
+
fromZigbee: [fz.brightness, fz.identify, fz.on_off, fz.lighting_ballast_configuration, fz.legrand_cluster_fc01],
|
|
34
34
|
toZigbee: [tz.light_onoff_brightness, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn,
|
|
35
|
-
tz.
|
|
35
|
+
tz.legrand_deviceMode, tz.legrand_identify, tz.ballast_config],
|
|
36
36
|
exposes: [e.light_brightness(),
|
|
37
37
|
exposes.numeric('ballast_minimum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
38
38
|
.withDescription('Specifies the minimum brightness value'),
|
|
39
39
|
exposes.numeric('ballast_maximum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
40
40
|
.withDescription('Specifies the maximum brightness value'),
|
|
41
|
-
exposes.binary('
|
|
42
|
-
exposes.binary('permanent_led', ea.
|
|
43
|
-
exposes.binary('led_when_on', ea.
|
|
41
|
+
exposes.binary('device_mode', ea.ALL, 'dimmer_on', 'dimmer_off').withDescription('Allow the device to change brightness'),
|
|
42
|
+
exposes.binary('permanent_led', ea.ALL, 'ON', 'OFF').withDescription('Enable or disable the permanent blue LED'),
|
|
43
|
+
exposes.binary('led_when_on', ea.ALL, 'ON', 'OFF').withDescription('Enables the LED when the light is on')],
|
|
44
44
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
45
45
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
46
46
|
const endpoint = device.getEndpoint(1);
|
|
@@ -76,10 +76,10 @@ module.exports = [
|
|
|
76
76
|
description: 'DIN power consumption module (same as Legrand 412015)',
|
|
77
77
|
vendor: 'BTicino',
|
|
78
78
|
extend: extend.switch(),
|
|
79
|
-
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.
|
|
79
|
+
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.legrand_cluster_fc01, fz.ignore_basic_report, fz.ignore_genOta],
|
|
80
80
|
toZigbee: [tz.legrand_deviceMode, tz.on_off, tz.legrand_identify, tz.electrical_measurement_power],
|
|
81
81
|
exposes: [exposes.switch().withState('state', true, 'On/off (works only if device is in "switch" mode)'),
|
|
82
|
-
e.power().withAccess(ea.STATE_GET), exposes.enum(
|
|
82
|
+
e.power().withAccess(ea.STATE_GET), exposes.enum('device_mode', ea.ALL, ['switch', 'auto'])
|
|
83
83
|
.withDescription('switch: allow on/off, auto will use wired action via C1/C2 on contactor for example with HC/HP')],
|
|
84
84
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
85
85
|
const endpoint = device.getEndpoint(1);
|
|
@@ -375,4 +375,44 @@ module.exports = [
|
|
|
375
375
|
},
|
|
376
376
|
exposes: [e.battery(), e.illuminance(), e.temperature(), e.humidity(), e.pressure()],
|
|
377
377
|
},
|
|
378
|
+
{
|
|
379
|
+
zigbeeModel: ['EFEKTA_eFlower_Pro'],
|
|
380
|
+
model: 'EFEKTA_eFlower_Pro',
|
|
381
|
+
vendor: 'Custom devices (DiY)',
|
|
382
|
+
description: '[Plant Wattering Sensor with e-ink display 2.13](https://efektalab.com/eFlowerPro)',
|
|
383
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.illuminance, fz.soil_moisture, fz.battery],
|
|
384
|
+
toZigbee: [tz.factory_reset],
|
|
385
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
386
|
+
const firstEndpoint = device.getEndpoint(1);
|
|
387
|
+
await reporting.bind(firstEndpoint, coordinatorEndpoint, [
|
|
388
|
+
'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity', 'msIlluminanceMeasurement', 'msSoilMoisture']);
|
|
389
|
+
const overides = {min: 0, max: 21600, change: 0};
|
|
390
|
+
await reporting.batteryVoltage(firstEndpoint, overides);
|
|
391
|
+
await reporting.batteryPercentageRemaining(firstEndpoint, overides);
|
|
392
|
+
await reporting.temperature(firstEndpoint, overides);
|
|
393
|
+
await reporting.humidity(firstEndpoint, overides);
|
|
394
|
+
await reporting.illuminance(firstEndpoint, overides);
|
|
395
|
+
await reporting.soil_moisture(firstEndpoint, overides);
|
|
396
|
+
},
|
|
397
|
+
exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
zigbeeModel: ['EFEKTA_eTH102'],
|
|
401
|
+
model: 'EFEKTA_eTH102',
|
|
402
|
+
vendor: 'Custom devices (DiY)',
|
|
403
|
+
description: '[Mini digital thermometer & hygrometer with e-ink1.02](http://efektalab.com/eTH102)',
|
|
404
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.battery],
|
|
405
|
+
toZigbee: [tz.factory_reset],
|
|
406
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
407
|
+
const endpoint = device.getEndpoint(1);
|
|
408
|
+
await reporting.bind(endpoint, coordinatorEndpoint, [
|
|
409
|
+
'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity']);
|
|
410
|
+
const overides = {min: 0, max: 21600, change: 0};
|
|
411
|
+
await reporting.batteryVoltage(endpoint, overides);
|
|
412
|
+
await reporting.batteryPercentageRemaining(endpoint, overides);
|
|
413
|
+
await reporting.temperature(endpoint, overides);
|
|
414
|
+
await reporting.humidity(endpoint, overides);
|
|
415
|
+
},
|
|
416
|
+
exposes: [e.battery(), e.temperature(), e.humidity()],
|
|
417
|
+
},
|
|
378
418
|
];
|
package/devices/develco.js
CHANGED
|
@@ -39,7 +39,8 @@ module.exports = [
|
|
|
39
39
|
description: 'Power plug',
|
|
40
40
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.device_temperature],
|
|
41
41
|
toZigbee: [tz.on_off],
|
|
42
|
-
exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.device_temperature()],
|
|
42
|
+
exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.device_temperature(), e.ac_frequency()],
|
|
43
|
+
options: [exposes.options.precision(`ac_frequency`)],
|
|
43
44
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
44
45
|
const endpoint = device.getEndpoint(2);
|
|
45
46
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering', 'genDeviceTempCfg']);
|
|
@@ -52,6 +53,7 @@ module.exports = [
|
|
|
52
53
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
53
54
|
await reporting.currentSummDelivered(endpoint, {change: [0, 20]}); // Limit reports to once every 5m, or 0.02kWh
|
|
54
55
|
await reporting.instantaneousDemand(endpoint, {min: constants.repInterval.MINUTES_5, change: 10});
|
|
56
|
+
await reporting.acFrequency(endpoint);
|
|
55
57
|
},
|
|
56
58
|
endpoint: (device) => {
|
|
57
59
|
return {default: 2};
|
package/devices/frankever.js
CHANGED
|
@@ -6,7 +6,8 @@ const ea = exposes.access;
|
|
|
6
6
|
|
|
7
7
|
module.exports = [
|
|
8
8
|
{
|
|
9
|
-
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_wt9agwf3'}
|
|
9
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_wt9agwf3'},
|
|
10
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_5uodvhgc'}],
|
|
10
11
|
model: 'FK_V02',
|
|
11
12
|
vendor: 'FrankEver',
|
|
12
13
|
description: 'Zigbee smart water valve',
|
package/devices/gledopto.js
CHANGED
|
@@ -62,10 +62,14 @@ const gledoptoExtend = {
|
|
|
62
62
|
}),
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
const configureReadModelID = async (device) => {
|
|
65
|
+
const configureReadModelID = async (device, coordinatorEndpoint, logger) => {
|
|
66
66
|
// https://github.com/Koenkk/zigbee-herdsman-converters/issues/3016#issuecomment-1027726604
|
|
67
67
|
const endpoint = device.endpoints[0];
|
|
68
|
-
|
|
68
|
+
const oldModel = device.modelID;
|
|
69
|
+
const newModel = (await endpoint.read('genBasic', ['modelId'])).modelId;
|
|
70
|
+
if (oldModel != newModel) {
|
|
71
|
+
logger.info(`Detected Gledopto device mode change, from '${oldModel}' to '${newModel}'`);
|
|
72
|
+
}
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
module.exports = [
|
|
@@ -125,7 +129,7 @@ module.exports = [
|
|
|
125
129
|
extend: gledoptoExtend.light_onoff_brightness_colortemp({noConfigure: true}),
|
|
126
130
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
127
131
|
await extend.light_onoff_brightness_colortemp().configure(device, coordinatorEndpoint, logger);
|
|
128
|
-
await configureReadModelID(device);
|
|
132
|
+
await configureReadModelID(device, coordinatorEndpoint, logger);
|
|
129
133
|
},
|
|
130
134
|
},
|
|
131
135
|
{
|
|
@@ -192,7 +196,7 @@ module.exports = [
|
|
|
192
196
|
extend: gledoptoExtend.light_onoff_brightness_colortemp_color({noConfigure: true}),
|
|
193
197
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
194
198
|
await extend.light_onoff_brightness_colortemp_color().configure(device, coordinatorEndpoint, logger);
|
|
195
|
-
await configureReadModelID(device);
|
|
199
|
+
await configureReadModelID(device, coordinatorEndpoint, logger);
|
|
196
200
|
},
|
|
197
201
|
},
|
|
198
202
|
{
|
|
@@ -254,7 +258,7 @@ module.exports = [
|
|
|
254
258
|
extend: gledoptoExtend.light_onoff_brightness_color({noConfigure: true}),
|
|
255
259
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
256
260
|
await extend.light_onoff_brightness_color().configure(device, coordinatorEndpoint, logger);
|
|
257
|
-
await configureReadModelID(device);
|
|
261
|
+
await configureReadModelID(device, coordinatorEndpoint, logger);
|
|
258
262
|
},
|
|
259
263
|
},
|
|
260
264
|
{
|
|
@@ -263,11 +267,12 @@ module.exports = [
|
|
|
263
267
|
vendor: 'Gledopto',
|
|
264
268
|
ota: ota.zigbeeOTA,
|
|
265
269
|
description: 'Zigbee LED Controller RGB+CCT (pro)',
|
|
270
|
+
whiteLabel: [{vendor: 'Gledopto', model: 'GL-C-001P'}],
|
|
266
271
|
extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495], noConfigure: true}),
|
|
267
272
|
meta: {disableDefaultResponse: true},
|
|
268
273
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
269
274
|
await extend.light_onoff_brightness_colortemp_color().configure(device, coordinatorEndpoint, logger);
|
|
270
|
-
await configureReadModelID(device);
|
|
275
|
+
await configureReadModelID(device, coordinatorEndpoint, logger);
|
|
271
276
|
},
|
|
272
277
|
},
|
|
273
278
|
{
|
|
@@ -292,7 +297,7 @@ module.exports = [
|
|
|
292
297
|
extend: gledoptoExtend.light_onoff_brightness({noConfigure: true}),
|
|
293
298
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
294
299
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
295
|
-
await configureReadModelID(device);
|
|
300
|
+
await configureReadModelID(device, coordinatorEndpoint, logger);
|
|
296
301
|
},
|
|
297
302
|
},
|
|
298
303
|
{
|
|
@@ -564,6 +569,14 @@ module.exports = [
|
|
|
564
569
|
description: 'Zigbee 10W Floodlight RGB+CCT (pro)',
|
|
565
570
|
extend: gledoptoExtend.light_onoff_brightness_colortemp_color(),
|
|
566
571
|
},
|
|
572
|
+
{
|
|
573
|
+
zigbeeModel: ['GL-FL-001P'],
|
|
574
|
+
model: 'GL-FL-001P',
|
|
575
|
+
vendor: 'Gledopto',
|
|
576
|
+
ota: ota.zigbeeOTA,
|
|
577
|
+
description: 'Zigbee 10W Floodlight RGB+CCT 12V Low Voltage (pro)',
|
|
578
|
+
extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495]}),
|
|
579
|
+
},
|
|
567
580
|
{
|
|
568
581
|
zigbeeModel: ['GL-FL-005TZ'],
|
|
569
582
|
model: 'GL-FL-005TZ',
|
package/devices/heiman.js
CHANGED
|
@@ -398,7 +398,7 @@ module.exports = [
|
|
|
398
398
|
exposes: [e.temperature(), e.humidity(), e.battery()],
|
|
399
399
|
},
|
|
400
400
|
{
|
|
401
|
-
fingerprint: [{modelID: 'SOS-EM', manufacturerName: 'HEIMAN'}],
|
|
401
|
+
fingerprint: [{modelID: 'SOS-EM', manufacturerName: 'HEIMAN'}, {modelID: 'SOS-EF-3.0', manufacturerName: 'HEIMAN'}],
|
|
402
402
|
model: 'HS1EB/HS1EB-E',
|
|
403
403
|
vendor: 'HEIMAN',
|
|
404
404
|
description: 'Smart emergency button',
|