zigbee-herdsman-converters 14.0.513 → 14.0.516
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 +78 -1
- package/converters/toZigbee.js +67 -1
- package/devices/easyaccess.js +1 -0
- package/devices/ecodim.js +7 -0
- package/devices/ikea.js +4 -1
- package/devices/inovelli.js +1225 -0
- package/devices/moes.js +11 -0
- package/devices/onesti.js +1 -1
- package/devices/paulmann.js +10 -0
- package/devices/prolight.js +5 -2
- package/devices/tuya.js +11 -12
- package/devices/useelink.js +2 -0
- package/devices/xiaomi.js +16 -21
- package/lib/ota/index.js +1 -0
- package/lib/ota/inovelli.js +72 -0
- package/lib/tuya.js +3 -0
- package/lib/xiaomi.js +8 -4
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -532,6 +532,24 @@ const converters = {
|
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
+
// onLevel - range 0x00 to 0xff - optional
|
|
536
|
+
// Any value outside of MinLevel to MaxLevel, including 0xff and 0x00, is interpreted as "previous".
|
|
537
|
+
if (msg.data.hasOwnProperty('onLevel') && (msg.data['onLevel'] !== undefined)) {
|
|
538
|
+
result.level_config.on_level = Number(msg.data['onLevel']);
|
|
539
|
+
if (result.level_config.on_level === 255) {
|
|
540
|
+
result.level_config.on_level = 'previous';
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// options - 8-bit map
|
|
545
|
+
// bit 0: ExecuteIfOff - when 0, Move commands are ignored if the device is off;
|
|
546
|
+
// when 1, CurrentLevel can be changed while the device is off.
|
|
547
|
+
// bit 1: CoupleColorTempToLevel - when 1, changes to level also change color temperature.
|
|
548
|
+
// (What this means is not defined, but it's most likely to be "dim to warm".)
|
|
549
|
+
if (msg.data.hasOwnProperty('options') && msg.data['options'] !== undefined) {
|
|
550
|
+
result.level_config.execute_if_off = !!(Number(msg.data['options']) & 1);
|
|
551
|
+
}
|
|
552
|
+
|
|
535
553
|
if (Object.keys(result.level_config).length > 0) {
|
|
536
554
|
return result;
|
|
537
555
|
}
|
|
@@ -4341,7 +4359,8 @@ const converters = {
|
|
|
4341
4359
|
// DP2: Smart Air Box: co2, Smart Air Housekeeper: MP25
|
|
4342
4360
|
case tuya.dataPoints.tuyaSabCO2:
|
|
4343
4361
|
if (meta.device.manufacturerName === '_TZE200_dwcarsat') {
|
|
4344
|
-
|
|
4362
|
+
// Ignore: https://github.com/Koenkk/zigbee2mqtt/issues/11033#issuecomment-1109808552
|
|
4363
|
+
if (value === 0xaaac || value === 0xaaab) return;
|
|
4345
4364
|
return {pm25: calibrateAndPrecisionRoundOptions(value, options, 'pm25')};
|
|
4346
4365
|
} else if (meta.device.manufacturerName === '_TZE200_ryfmq5rl') {
|
|
4347
4366
|
return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd') / 100};
|
|
@@ -5909,6 +5928,29 @@ const converters = {
|
|
|
5909
5928
|
return result;
|
|
5910
5929
|
},
|
|
5911
5930
|
},
|
|
5931
|
+
xiaomi_curtain_hagl04_status: {
|
|
5932
|
+
cluster: 'genMultistateOutput',
|
|
5933
|
+
type: ['attributeReport'],
|
|
5934
|
+
convert: (model, msg, publish, options, meta) => {
|
|
5935
|
+
let running = false;
|
|
5936
|
+
const data = msg.data;
|
|
5937
|
+
const lookup = {
|
|
5938
|
+
0: 'closing',
|
|
5939
|
+
1: 'opening',
|
|
5940
|
+
2: 'stop',
|
|
5941
|
+
};
|
|
5942
|
+
if (data && data.hasOwnProperty('presentValue')) {
|
|
5943
|
+
const value = data['presentValue'];
|
|
5944
|
+
if (value < 2) {
|
|
5945
|
+
running = true;
|
|
5946
|
+
}
|
|
5947
|
+
return {
|
|
5948
|
+
motor_state: lookup[value],
|
|
5949
|
+
running: running,
|
|
5950
|
+
};
|
|
5951
|
+
}
|
|
5952
|
+
},
|
|
5953
|
+
},
|
|
5912
5954
|
xiaomi_curtain_acn002_status: {
|
|
5913
5955
|
cluster: 'genMultistateOutput',
|
|
5914
5956
|
type: ['attributeReport'],
|
|
@@ -8528,6 +8570,41 @@ const converters = {
|
|
|
8528
8570
|
return result;
|
|
8529
8571
|
},
|
|
8530
8572
|
},
|
|
8573
|
+
moes_cover: {
|
|
8574
|
+
cluster: 'manuSpecificTuya',
|
|
8575
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
8576
|
+
options: [exposes.options.invert_cover()],
|
|
8577
|
+
convert: (model, msg, publish, options, meta) => {
|
|
8578
|
+
const dpValue = tuya.firstDpValue(msg, meta, 'moes_cover');
|
|
8579
|
+
const dp = dpValue.dp;
|
|
8580
|
+
const value = tuya.getDataValue(dpValue);
|
|
8581
|
+
let result = null;
|
|
8582
|
+
switch (dp) {
|
|
8583
|
+
case tuya.dataPoints.coverPosition: {
|
|
8584
|
+
const invert = !tuya.isCoverInverted(meta.device.manufacturerName) ?
|
|
8585
|
+
!options.invert_cover : options.invert_cover;
|
|
8586
|
+
const position = invert ? 100 - value : value;
|
|
8587
|
+
result = {position: position};
|
|
8588
|
+
break;
|
|
8589
|
+
}
|
|
8590
|
+
case tuya.dataPoints.state:
|
|
8591
|
+
result = {state: {0: 'OPEN', 1: 'STOP', 2: 'CLOSE'}[value], running: {0: true, 1: false, 2: true}[value]};
|
|
8592
|
+
break;
|
|
8593
|
+
case tuya.dataPoints.moesCoverBacklight:
|
|
8594
|
+
result = {backlight: {false: 'OFF', true: 'ON'}[value]};
|
|
8595
|
+
break;
|
|
8596
|
+
case tuya.dataPoints.moesCoverCalibration:
|
|
8597
|
+
result = {calibration: {0: 'ON', 1: 'OFF'}[value]};
|
|
8598
|
+
break;
|
|
8599
|
+
case tuya.dataPoints.moesCoverMotorReversal:
|
|
8600
|
+
result = {motor_reversal: {0: 'OFF', 1: 'ON'}[value]};
|
|
8601
|
+
break;
|
|
8602
|
+
default:
|
|
8603
|
+
meta.logger.warn(`fromZigbee.moes_cover: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
|
|
8604
|
+
}
|
|
8605
|
+
return result;
|
|
8606
|
+
},
|
|
8607
|
+
},
|
|
8531
8608
|
// #endregion
|
|
8532
8609
|
|
|
8533
8610
|
// #region Ignore converters (these message dont need parsing).
|
package/converters/toZigbee.js
CHANGED
|
@@ -535,12 +535,41 @@ const converters = {
|
|
|
535
535
|
Object.assign(state, {current_level_startup: startUpCurrentLevelValue});
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
// onLevel - range 0x00 to 0xff - optional
|
|
539
|
+
// Any value outside of MinLevel to MaxLevel, including 0xff and 0x00, is interpreted as "previous".
|
|
540
|
+
if (value.hasOwnProperty('on_level')) {
|
|
541
|
+
let onLevel = value.on_level;
|
|
542
|
+
if (typeof onLevel === 'string' && onLevel.toLowerCase() == 'previous') {
|
|
543
|
+
onLevel = 255;
|
|
544
|
+
} else {
|
|
545
|
+
onLevel = Number(onLevel);
|
|
546
|
+
}
|
|
547
|
+
if (onLevel > 255) onLevel = 254;
|
|
548
|
+
if (onLevel < 1) onLevel = 1;
|
|
549
|
+
await entity.write('genLevelCtrl', {onLevel}, utils.getOptions(meta.mapped, entity));
|
|
550
|
+
Object.assign(state, {on_level: onLevel == 255 ? 'previous' : onLevel});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// options - 8-bit map
|
|
554
|
+
// bit 0: ExecuteIfOff - when 0, Move commands are ignored if the device is off;
|
|
555
|
+
// when 1, CurrentLevel can be changed while the device is off.
|
|
556
|
+
// bit 1: CoupleColorTempToLevel - when 1, changes to level also change color temperature.
|
|
557
|
+
// (What this means is not defined, but it's most likely to be "dim to warm".)
|
|
558
|
+
if (value.hasOwnProperty('execute_if_off')) {
|
|
559
|
+
const executeIfOffValue = !!value.execute_if_off;
|
|
560
|
+
await entity.write('genLevelCtrl', {options: executeIfOffValue ? 1 : 0}, utils.getOptions(meta.mapped, entity));
|
|
561
|
+
Object.assign(state, {execute_if_off: executeIfOffValue});
|
|
562
|
+
}
|
|
563
|
+
|
|
538
564
|
if (Object.keys(state).length > 0) {
|
|
539
565
|
return {state: {level_config: state}};
|
|
540
566
|
}
|
|
541
567
|
},
|
|
542
568
|
convertGet: async (entity, key, meta) => {
|
|
543
|
-
for (const attribute of [
|
|
569
|
+
for (const attribute of [
|
|
570
|
+
'onOffTransitionTime', 'onTransitionTime', 'offTransitionTime', 'startUpCurrentLevel',
|
|
571
|
+
'onLevel', 'options',
|
|
572
|
+
]) {
|
|
544
573
|
try {
|
|
545
574
|
await entity.read('genLevelCtrl', [attribute]);
|
|
546
575
|
} catch (ex) {
|
|
@@ -7463,6 +7492,43 @@ const converters = {
|
|
|
7463
7492
|
}
|
|
7464
7493
|
},
|
|
7465
7494
|
},
|
|
7495
|
+
moes_cover: {
|
|
7496
|
+
key: ['backlight', 'calibration', 'motor_reversal', 'state', 'position'],
|
|
7497
|
+
options: [exposes.options.invert_cover()],
|
|
7498
|
+
convertSet: async (entity, key, value, meta) => {
|
|
7499
|
+
switch (key) {
|
|
7500
|
+
case 'position':
|
|
7501
|
+
if (value >= 0 && value <= 100) {
|
|
7502
|
+
const invert = !tuya.isCoverInverted(meta.device.manufacturerName) ?
|
|
7503
|
+
!meta.options.invert_cover : meta.options.invert_cover;
|
|
7504
|
+
const position = invert ? 100 - value : value;
|
|
7505
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.coverPosition, position);
|
|
7506
|
+
return {position: value};
|
|
7507
|
+
}
|
|
7508
|
+
break;
|
|
7509
|
+
case 'state': {
|
|
7510
|
+
const state = {'OPEN': 0, 'STOP': 1, 'CLOSE': 2}[value.toUpperCase()];
|
|
7511
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.state, state);
|
|
7512
|
+
break;
|
|
7513
|
+
}
|
|
7514
|
+
case 'backlight': {
|
|
7515
|
+
const backlight = value.toUpperCase() === 'ON' ? true : false;
|
|
7516
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.moesCoverBacklight, backlight);
|
|
7517
|
+
return {backlight: value};
|
|
7518
|
+
}
|
|
7519
|
+
case 'calibration': {
|
|
7520
|
+
const calibration = value.toUpperCase() === 'ON' ? 0 : 1;
|
|
7521
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.moesCoverCalibration, calibration);
|
|
7522
|
+
break;
|
|
7523
|
+
}
|
|
7524
|
+
case 'motor_reversal': {
|
|
7525
|
+
const motorReversal = value.toUpperCase() === 'ON' ? 1 : 0;
|
|
7526
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.moesCoverMotorReversal, motorReversal);
|
|
7527
|
+
return {motor_reversal: value};
|
|
7528
|
+
}
|
|
7529
|
+
}
|
|
7530
|
+
},
|
|
7531
|
+
},
|
|
7466
7532
|
// #endregion
|
|
7467
7533
|
|
|
7468
7534
|
// #region Ignore converters
|
package/devices/easyaccess.js
CHANGED
|
@@ -22,5 +22,6 @@ module.exports = [
|
|
|
22
22
|
exposes: [e.lock(), e.battery(), e.sound_volume(),
|
|
23
23
|
e.action(['zigbee_unlock', 'lock', 'rfid_unlock', 'keypad_unlock']),
|
|
24
24
|
exposes.binary('auto_relock', ea.STATE_SET, true, false).withDescription('Auto relock after 7 seconds.')],
|
|
25
|
+
whiteLabel: [{vendor: 'Datek Wireless', model: 'EasyCode903G2.1'}],
|
|
25
26
|
},
|
|
26
27
|
];
|
package/devices/ecodim.js
CHANGED
|
@@ -126,4 +126,11 @@ module.exports = [
|
|
|
126
126
|
description: 'Zigbee LED filament light dimmable E27, globe G125, flame 2200K',
|
|
127
127
|
extend: extend.light_onoff_brightness(),
|
|
128
128
|
},
|
|
129
|
+
{
|
|
130
|
+
fingerprint: [{modelID: 'CCT Light', manufacturerName: 'ZigBee/CCT', manufacturerID: 4137}],
|
|
131
|
+
model: 'ED-10041',
|
|
132
|
+
vendor: 'EcoDim',
|
|
133
|
+
description: 'Zigbee LED filament light dimmable E27, edison ST64, flame 2200K',
|
|
134
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
135
|
+
},
|
|
129
136
|
];
|
package/devices/ikea.js
CHANGED
|
@@ -36,9 +36,12 @@ const bulbOnEvent = async (type, data, device, options, state) => {
|
|
|
36
36
|
|
|
37
37
|
// NOTE: execute_if_off default is false
|
|
38
38
|
// we only restore if true, to save unneeded network writes
|
|
39
|
-
if (state.color_options.execute_if_off === true) {
|
|
39
|
+
if (state.color_options !== undefined && state.color_options.execute_if_off === true) {
|
|
40
40
|
device.endpoints[0].write('lightingColorCtrl', {'options': 1});
|
|
41
41
|
}
|
|
42
|
+
if (state.level_config !== undefined && state.level_config.execute_if_off === true) {
|
|
43
|
+
device.endpoints[0].write('genLevelCtrl', {'options': 1});
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
};
|
|
44
47
|
|