zigbee-herdsman-converters 14.0.412 → 14.0.416
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 +120 -86
- package/converters/toZigbee.js +68 -16
- package/devices/adeo.js +7 -0
- 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/lixee.js +43 -32
- package/devices/moes.js +6 -6
- package/devices/philips.js +18 -0
- package/devices/prolight.js +12 -0
- package/devices/titan_products.js +2 -1
- package/devices/tuya.js +29 -12
- package/devices/xiaomi.js +34 -34
- 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 +20 -0
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -423,9 +423,12 @@ const converters = {
|
|
|
423
423
|
// This is for occupancy sensor that send motion start AND stop messages
|
|
424
424
|
cluster: 'msOccupancySensing',
|
|
425
425
|
type: ['attributeReport', 'readResponse'],
|
|
426
|
+
options: [exposes.options.no_occupancy_since()],
|
|
426
427
|
convert: (model, msg, publish, options, meta) => {
|
|
427
428
|
if (msg.data.hasOwnProperty('occupancy')) {
|
|
428
|
-
|
|
429
|
+
const payload = {occupancy: (msg.data.occupancy % 2) > 0};
|
|
430
|
+
utils.noOccupancySince(msg.endpoint, payload, options, publish);
|
|
431
|
+
return payload;
|
|
429
432
|
}
|
|
430
433
|
},
|
|
431
434
|
},
|
|
@@ -449,32 +452,19 @@ const converters = {
|
|
|
449
452
|
options.occupancy_timeout : 90;
|
|
450
453
|
|
|
451
454
|
// Stop existing timers because motion is detected and set a new one.
|
|
452
|
-
globalStore.getValue(msg.endpoint, '
|
|
453
|
-
globalStore.putValue(msg.endpoint, 'timers', []);
|
|
455
|
+
clearTimeout(globalStore.getValue(msg.endpoint, 'occupancy_timer', null));
|
|
454
456
|
|
|
455
457
|
if (timeout !== 0) {
|
|
456
458
|
const timer = setTimeout(() => {
|
|
457
459
|
publish({occupancy: false});
|
|
458
460
|
}, timeout * 1000);
|
|
459
461
|
|
|
460
|
-
globalStore.
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// No occupancy since
|
|
464
|
-
if (options && options.no_occupancy_since) {
|
|
465
|
-
options.no_occupancy_since.forEach((since) => {
|
|
466
|
-
const timer = setTimeout(() => {
|
|
467
|
-
publish({no_occupancy_since: since});
|
|
468
|
-
}, since * 1000);
|
|
469
|
-
globalStore.getValue(msg.endpoint, 'timers').push(timer);
|
|
470
|
-
});
|
|
462
|
+
globalStore.putValue(msg.endpoint, 'occupancy_timer', timer);
|
|
471
463
|
}
|
|
472
464
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return {occupancy: true};
|
|
477
|
-
}
|
|
465
|
+
const payload = {occupancy: true};
|
|
466
|
+
utils.noOccupancySince(msg.endpoint, payload, options, publish);
|
|
467
|
+
return payload;
|
|
478
468
|
},
|
|
479
469
|
},
|
|
480
470
|
occupancy_timeout: {
|
|
@@ -2420,6 +2410,12 @@ const converters = {
|
|
|
2420
2410
|
convert: (model, msg, publish, options, meta) => {
|
|
2421
2411
|
const dpValue = tuya.firstDpValue(msg, meta, 'moes_switch');
|
|
2422
2412
|
const dp = dpValue.dp;
|
|
2413
|
+
|
|
2414
|
+
// tuya_switch datapoints
|
|
2415
|
+
if (dp >= 1 && dp <= 4) {
|
|
2416
|
+
return null;
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2423
2419
|
const value = tuya.getDataValue(dpValue);
|
|
2424
2420
|
|
|
2425
2421
|
switch (dp) {
|
|
@@ -2637,6 +2633,31 @@ const converters = {
|
|
|
2637
2633
|
}
|
|
2638
2634
|
},
|
|
2639
2635
|
},
|
|
2636
|
+
ts011f_plug_indicator_mode: {
|
|
2637
|
+
cluster: 'genOnOff',
|
|
2638
|
+
type: ['attributeReport', 'readResponse'],
|
|
2639
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2640
|
+
const property = 'tuyaBacklightMode'; // 0x8001 or 32769
|
|
2641
|
+
if (msg.data.hasOwnProperty(property)) {
|
|
2642
|
+
const value = msg.data[property];
|
|
2643
|
+
const lookup = {0: 'off', 1: 'off/on', 2: 'on/off', 3: 'on'};
|
|
2644
|
+
if (lookup.hasOwnProperty(value)) {
|
|
2645
|
+
return {indicator_mode: lookup[value]};
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
},
|
|
2649
|
+
},
|
|
2650
|
+
ts011f_plug_child_mode: {
|
|
2651
|
+
cluster: 'genOnOff',
|
|
2652
|
+
type: ['attributeReport', 'readResponse'],
|
|
2653
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2654
|
+
const property = (0x8000).toString(); // 32768
|
|
2655
|
+
if (msg.data.hasOwnProperty(property)) {
|
|
2656
|
+
const value = msg.data[property];
|
|
2657
|
+
return {child_lock: value ? 'LOCK' : 'UNLOCK'};
|
|
2658
|
+
}
|
|
2659
|
+
},
|
|
2660
|
+
},
|
|
2640
2661
|
WSZ01_on_off_action: {
|
|
2641
2662
|
cluster: 65029,
|
|
2642
2663
|
type: 'raw',
|
|
@@ -5330,8 +5351,11 @@ const converters = {
|
|
|
5330
5351
|
if (index == 1) {
|
|
5331
5352
|
payload.voltage = value;
|
|
5332
5353
|
payload.battery = batteryVoltageToPercentage(value, '3V_2100');
|
|
5333
|
-
} else if (index === 3)
|
|
5334
|
-
|
|
5354
|
+
} else if (index === 3) {
|
|
5355
|
+
if (!['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5356
|
+
payload.temperature = calibrateAndPrecisionRoundOptions(value, options, 'temperature'); // 0x03
|
|
5357
|
+
}
|
|
5358
|
+
} else if (index === 5) {
|
|
5335
5359
|
if (['JT-BZ-01AQ/A', 'RTCZCGQ11LM'].includes(model.model)) payload.power_outage_count = value;
|
|
5336
5360
|
} else if (index === 100) {
|
|
5337
5361
|
if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
@@ -5339,7 +5363,7 @@ const converters = {
|
|
|
5339
5363
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5340
5364
|
} else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
|
|
5341
5365
|
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
5342
|
-
} else if (['WXCJKG11LM
|
|
5366
|
+
} else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
|
|
5343
5367
|
// We don't know what the value means for these devices.
|
|
5344
5368
|
// https://github.com/Koenkk/zigbee2mqtt/issues/11126
|
|
5345
5369
|
} else {
|
|
@@ -8301,79 +8325,89 @@ const converters = {
|
|
|
8301
8325
|
return {action};
|
|
8302
8326
|
},
|
|
8303
8327
|
},
|
|
8304
|
-
|
|
8328
|
+
ZMAM02_cover: {
|
|
8305
8329
|
cluster: 'manuSpecificTuya',
|
|
8306
|
-
type: ['
|
|
8330
|
+
type: ['commandDataReport', 'commandDataResponse'],
|
|
8331
|
+
options: [exposes.options.invert_cover()],
|
|
8307
8332
|
convert: (model, msg, publish, options, meta) => {
|
|
8308
|
-
const
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8333
|
+
const dpValue = tuya.firstDpValue(msg, meta, 'ZMAM02_cover');
|
|
8334
|
+
const dp = dpValue.dp;
|
|
8335
|
+
const value = tuya.getDataValue(dpValue);
|
|
8336
|
+
switch (dp) {
|
|
8337
|
+
case tuya.dataPoints.coverPosition: // Started moving to position (triggered from Zigbee)
|
|
8338
|
+
case tuya.dataPoints.coverArrived: { // Arrived at position
|
|
8339
|
+
const running = dp === tuya.dataPoints.coverArrived ? false : true;
|
|
8340
|
+
const invert = tuya.isCoverInverted(meta.device.manufacturerName) ? !options.invert_cover : options.invert_cover;
|
|
8341
|
+
const position = invert ? 100 - (value & 0xFF) : (value & 0xFF);
|
|
8342
|
+
if (position > 0 && position <= 100) {
|
|
8343
|
+
return {running, position, state: 'OPEN'};
|
|
8344
|
+
} else if (position == 0) { // Report fully closed
|
|
8345
|
+
return {running, position, state: 'CLOSE'};
|
|
8346
|
+
} else {
|
|
8347
|
+
return {running}; // Not calibrated yet, no position is available
|
|
8348
|
+
}
|
|
8349
|
+
}
|
|
8350
|
+
case tuya.dataPoints.coverSpeed: // Cover is reporting its current speed setting
|
|
8351
|
+
return {motor_speed: value};
|
|
8352
|
+
case tuya.dataPoints.state: // Ignore the cover state, it's not reliable between different covers!
|
|
8353
|
+
case tuya.dataPoints.coverChange: // Ignore manual cover change, it's not reliable between different covers!
|
|
8354
|
+
break;
|
|
8355
|
+
case tuya.dataPoints.config: // Returned by configuration set; ignore
|
|
8356
|
+
break;
|
|
8357
|
+
case tuya.dataPoints.AM02MotorWorkingMode:
|
|
8358
|
+
switch (value) {
|
|
8359
|
+
case 0: // continuous 1
|
|
8360
|
+
return {motor_working_mode: 'continuous'};
|
|
8361
|
+
case 1: // intermittently
|
|
8362
|
+
return {motor_working_mode: 'intermittently'};
|
|
8363
|
+
default:
|
|
8364
|
+
meta.logger.warn('ZMAM02: ' +
|
|
8365
|
+
`Mode ${value} is not recognized.`);
|
|
8319
8366
|
break;
|
|
8320
|
-
|
|
8321
|
-
|
|
8367
|
+
}
|
|
8368
|
+
break;
|
|
8369
|
+
case tuya.dataPoints.AM02Border:
|
|
8370
|
+
switch (value) {
|
|
8371
|
+
case 0: // up
|
|
8372
|
+
return {border: 'up'};
|
|
8373
|
+
case 1: // down
|
|
8374
|
+
return {border: 'down'};
|
|
8375
|
+
case 2: // down_delete
|
|
8376
|
+
return {border: 'down_delete'};
|
|
8377
|
+
default:
|
|
8378
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8379
|
+
`Mode ${value} is not recognized.`);
|
|
8322
8380
|
break;
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
break;
|
|
8335
|
-
}
|
|
8381
|
+
}
|
|
8382
|
+
break;
|
|
8383
|
+
case tuya.dataPoints.AM02Direction:
|
|
8384
|
+
switch (value) {
|
|
8385
|
+
case 0:
|
|
8386
|
+
return {motor_direction: 'forward'};
|
|
8387
|
+
case 1:
|
|
8388
|
+
return {motor_direction: 'back'};
|
|
8389
|
+
default:
|
|
8390
|
+
meta.logger.warn('ZMAM02: ' +
|
|
8391
|
+
`Mode ${value} is not recognized.`);
|
|
8336
8392
|
break;
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
break;
|
|
8348
|
-
default:
|
|
8349
|
-
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8393
|
+
}
|
|
8394
|
+
break;
|
|
8395
|
+
case tuya.dataPoints.AM02Mode:
|
|
8396
|
+
switch (value) {
|
|
8397
|
+
case 0: // morning
|
|
8398
|
+
return {mode: 'morning'};
|
|
8399
|
+
case 1: // night
|
|
8400
|
+
return {mode: 'night'};
|
|
8401
|
+
default:
|
|
8402
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8350
8403
|
`Mode ${value} is not recognized.`);
|
|
8351
|
-
break;
|
|
8352
|
-
}
|
|
8353
|
-
break;
|
|
8354
|
-
case tuya.dataPoints.AM02PercentState:
|
|
8355
|
-
result.percent_state = value;
|
|
8356
8404
|
break;
|
|
8357
|
-
case tuya.dataPoints.AM02Mode:
|
|
8358
|
-
switch (value) {
|
|
8359
|
-
case 0: // morning
|
|
8360
|
-
result.mode = 'morning';
|
|
8361
|
-
break;
|
|
8362
|
-
case 1: // night
|
|
8363
|
-
result.mode = 'night';
|
|
8364
|
-
break;
|
|
8365
|
-
default:
|
|
8366
|
-
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8367
|
-
`Mode ${value} is not recognized.`);
|
|
8368
|
-
break;
|
|
8369
|
-
}
|
|
8370
|
-
break;
|
|
8371
|
-
default:
|
|
8372
|
-
meta.logger.warn(`fromZigbee.Zemismart Shader Konverter (Zm_AM02): NOT RECOGNIZED ` +
|
|
8373
|
-
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
8374
8405
|
}
|
|
8406
|
+
break;
|
|
8407
|
+
default: // Unknown code
|
|
8408
|
+
meta.logger.warn(`ZMAM02_cover: Unhandled DP #${dp} for ${meta.device.manufacturerName}:
|
|
8409
|
+
${JSON.stringify(dpValue)}`);
|
|
8375
8410
|
}
|
|
8376
|
-
return result;
|
|
8377
8411
|
},
|
|
8378
8412
|
},
|
|
8379
8413
|
// #endregion
|
package/converters/toZigbee.js
CHANGED
|
@@ -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),
|
|
@@ -5994,6 +5994,32 @@ const converters = {
|
|
|
5994
5994
|
await entity.read('genOnOff', ['tuyaBacklightMode']);
|
|
5995
5995
|
},
|
|
5996
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
|
+
},
|
|
5997
6023
|
hy_thermostat: {
|
|
5998
6024
|
key: [
|
|
5999
6025
|
'child_lock', 'current_heating_setpoint', 'local_temperature_calibration',
|
|
@@ -6898,30 +6924,56 @@ const converters = {
|
|
|
6898
6924
|
}
|
|
6899
6925
|
},
|
|
6900
6926
|
},
|
|
6901
|
-
|
|
6902
|
-
key: ['
|
|
6927
|
+
ZMAM02_cover: {
|
|
6928
|
+
key: ['state', 'position', 'mode', 'motor_direction', 'border', 'motor_working_mode'],
|
|
6929
|
+
options: [exposes.options.invert_cover()],
|
|
6903
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
|
+
}
|
|
6904
6960
|
switch (key) {
|
|
6905
|
-
case 'control':
|
|
6906
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, utils.getKey(tuya.ZMAM02.AM02Control, value));
|
|
6907
|
-
break;
|
|
6908
|
-
case 'percent_control':
|
|
6909
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.AM02PercentState, value);
|
|
6910
|
-
break;
|
|
6911
6961
|
case 'mode':
|
|
6912
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.
|
|
6962
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.ZMLookups.AM02Mode, value));
|
|
6913
6963
|
break;
|
|
6914
|
-
case '
|
|
6915
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.
|
|
6964
|
+
case 'motor_direction':
|
|
6965
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Direction, utils.getKey(tuya.ZMLookups.AM02Direction, value));
|
|
6916
6966
|
break;
|
|
6917
6967
|
case 'border':
|
|
6918
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.
|
|
6968
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.ZMLookups.AM02Border, value));
|
|
6919
6969
|
break;
|
|
6920
6970
|
case 'motor_working_mode':
|
|
6921
|
-
await tuya.sendDataPointEnum(
|
|
6971
|
+
await tuya.sendDataPointEnum(
|
|
6972
|
+
entity,
|
|
6973
|
+
tuya.dataPoints.AM02MotorWorkingMode,
|
|
6974
|
+
utils.getKey(tuya.ZMLookups.AM02MotorWorkingMode,
|
|
6975
|
+
value));
|
|
6922
6976
|
break;
|
|
6923
|
-
default: // Unknown Key
|
|
6924
|
-
meta.logger.warn(`toZigbee.ZMAM02: Unhandled Key ${key}`);
|
|
6925
6977
|
}
|
|
6926
6978
|
},
|
|
6927
6979
|
},
|
package/devices/adeo.js
CHANGED
|
@@ -6,6 +6,13 @@ const tz = require('../converters/toZigbee');
|
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
|
|
8
8
|
module.exports = [
|
|
9
|
+
{
|
|
10
|
+
zigbeeModel: ['ZBEK-12'],
|
|
11
|
+
model: 'IA-CDZFB2AA007NA-MZN-01',
|
|
12
|
+
vendor: 'ADEO',
|
|
13
|
+
description: 'ENKI LEXMAN E27 LED white',
|
|
14
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
15
|
+
},
|
|
9
16
|
{
|
|
10
17
|
zigbeeModel: ['LDSENK01F'],
|
|
11
18
|
model: 'LDSENK01F',
|
|
@@ -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',
|