zigbee-herdsman-converters 14.0.511 → 14.0.514
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 +86 -1
- package/converters/toZigbee.js +183 -75
- package/devices/easyaccess.js +1 -0
- package/devices/ikea.js +4 -1
- package/devices/inovelli.js +1225 -0
- package/devices/lellki.js +6 -25
- package/devices/mecrator.js +41 -0
- package/devices/moes.js +12 -1
- package/devices/namron.js +1 -1
- package/devices/onesti.js +1 -1
- package/devices/philips.js +9 -0
- package/devices/prolight.js +5 -2
- package/devices/tuya.js +22 -2
- package/devices/xiaomi.js +5 -3
- package/lib/ota/index.js +1 -0
- package/lib/ota/inovelli.js +72 -0
- package/lib/tuya.js +9 -0
- package/package.json +2 -2
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
|
}
|
|
@@ -1699,7 +1717,7 @@ const converters = {
|
|
|
1699
1717
|
result.hysterersis = precisionRound(data[0x100A], 2) / 10;
|
|
1700
1718
|
}
|
|
1701
1719
|
if (data.hasOwnProperty(0x100B)) { // DisplayAutoOffEnable
|
|
1702
|
-
const lookup = {0: '
|
|
1720
|
+
const lookup = {0: 'enabled', 1: 'disabled'};
|
|
1703
1721
|
result.display_auto_off_enabled = lookup[data[0x100B]];
|
|
1704
1722
|
}
|
|
1705
1723
|
if (data.hasOwnProperty(0x2001)) { // AlarmAirTempOverValue
|
|
@@ -8496,6 +8514,73 @@ const converters = {
|
|
|
8496
8514
|
return result;
|
|
8497
8515
|
},
|
|
8498
8516
|
},
|
|
8517
|
+
ZG204ZL_lms: {
|
|
8518
|
+
cluster: 'manuSpecificTuya',
|
|
8519
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
8520
|
+
convert: (model, msg, publish, options, meta) => {
|
|
8521
|
+
const result = {};
|
|
8522
|
+
for (const dpValue of msg.data.dpValues) {
|
|
8523
|
+
const dp = dpValue.dp;
|
|
8524
|
+
const value = tuya.getDataValue(dpValue);
|
|
8525
|
+
switch (dp) {
|
|
8526
|
+
case tuya.dataPoints.lmsState:
|
|
8527
|
+
result.occupancy = (value === 0);
|
|
8528
|
+
break;
|
|
8529
|
+
case tuya.dataPoints.lmsBattery:
|
|
8530
|
+
result.battery = value;
|
|
8531
|
+
break;
|
|
8532
|
+
case tuya.dataPoints.lmsSensitivity:
|
|
8533
|
+
result.sensitivity = {'0': 'low', '1': 'medium', '2': 'high'}[value];
|
|
8534
|
+
break;
|
|
8535
|
+
case tuya.dataPoints.lmsKeepTime:
|
|
8536
|
+
result.keep_time = {'0': '10', '1': '30', '2': '60', '3': '120'}[value];
|
|
8537
|
+
break;
|
|
8538
|
+
case tuya.dataPoints.lmsIlluminance:
|
|
8539
|
+
result.illuminance = value;
|
|
8540
|
+
break;
|
|
8541
|
+
default:
|
|
8542
|
+
meta.logger.warn(`zigbee-herdsman-converters:ZG204ZL_lms: NOT RECOGNIZED DP #${
|
|
8543
|
+
dp} with data ${JSON.stringify(dpValue)}`);
|
|
8544
|
+
}
|
|
8545
|
+
}
|
|
8546
|
+
return result;
|
|
8547
|
+
},
|
|
8548
|
+
},
|
|
8549
|
+
moes_cover: {
|
|
8550
|
+
cluster: 'manuSpecificTuya',
|
|
8551
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
8552
|
+
options: [exposes.options.invert_cover()],
|
|
8553
|
+
convert: (model, msg, publish, options, meta) => {
|
|
8554
|
+
const dpValue = tuya.firstDpValue(msg, meta, 'moes_cover');
|
|
8555
|
+
const dp = dpValue.dp;
|
|
8556
|
+
const value = tuya.getDataValue(dpValue);
|
|
8557
|
+
let result = null;
|
|
8558
|
+
switch (dp) {
|
|
8559
|
+
case tuya.dataPoints.coverPosition: {
|
|
8560
|
+
const invert = !tuya.isCoverInverted(meta.device.manufacturerName) ?
|
|
8561
|
+
!options.invert_cover : options.invert_cover;
|
|
8562
|
+
const position = invert ? 100 - value : value;
|
|
8563
|
+
result = {position: position};
|
|
8564
|
+
break;
|
|
8565
|
+
}
|
|
8566
|
+
case tuya.dataPoints.state:
|
|
8567
|
+
result = {state: {0: 'OPEN', 1: 'STOP', 2: 'CLOSE'}[value], running: {0: true, 1: false, 2: true}[value]};
|
|
8568
|
+
break;
|
|
8569
|
+
case tuya.dataPoints.moesCoverBacklight:
|
|
8570
|
+
result = {backlight: {false: 'OFF', true: 'ON'}[value]};
|
|
8571
|
+
break;
|
|
8572
|
+
case tuya.dataPoints.moesCoverCalibration:
|
|
8573
|
+
result = {calibration: {0: 'ON', 1: 'OFF'}[value]};
|
|
8574
|
+
break;
|
|
8575
|
+
case tuya.dataPoints.moesCoverMotorReversal:
|
|
8576
|
+
result = {motor_reversal: {0: 'OFF', 1: 'ON'}[value]};
|
|
8577
|
+
break;
|
|
8578
|
+
default:
|
|
8579
|
+
meta.logger.warn(`fromZigbee.moes_cover: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
|
|
8580
|
+
}
|
|
8581
|
+
return result;
|
|
8582
|
+
},
|
|
8583
|
+
},
|
|
8499
8584
|
// #endregion
|
|
8500
8585
|
|
|
8501
8586
|
// #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) {
|
|
@@ -798,7 +827,7 @@ const converters = {
|
|
|
798
827
|
const {message} = meta;
|
|
799
828
|
const transition = utils.getTransition(entity, 'brightness', meta);
|
|
800
829
|
const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false);
|
|
801
|
-
let state = message.hasOwnProperty('state') ? message.state.toLowerCase() : undefined;
|
|
830
|
+
let state = message.hasOwnProperty('state') ? (message.state === null ? null : message.state.toLowerCase()) : undefined;
|
|
802
831
|
let brightness = undefined;
|
|
803
832
|
if (message.hasOwnProperty('brightness')) {
|
|
804
833
|
brightness = Number(message.brightness);
|
|
@@ -806,91 +835,106 @@ const converters = {
|
|
|
806
835
|
brightness = utils.mapNumberRange(Number(message.brightness_percent), 0, 100, 0, 255);
|
|
807
836
|
}
|
|
808
837
|
|
|
809
|
-
if (brightness
|
|
810
|
-
// Allow 255
|
|
838
|
+
if (brightness === 255) {
|
|
839
|
+
// Allow 255 for backwards compatibility.
|
|
840
|
+
brightness = 254;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 254)) {
|
|
811
844
|
throw new Error(`Brightness value of message: '${JSON.stringify(message)}' invalid, must be a number >= 0 and =< 254`);
|
|
812
845
|
}
|
|
813
846
|
|
|
814
|
-
if (state !== undefined && ['on', 'off', 'toggle'].includes(state) === false) {
|
|
847
|
+
if (state !== undefined && state !== null && ['on', 'off', 'toggle'].includes(state) === false) {
|
|
815
848
|
throw new Error(`State value of message: '${JSON.stringify(message)}' invalid, must be 'ON', 'OFF' or 'TOGGLE'`);
|
|
816
849
|
}
|
|
817
850
|
|
|
818
|
-
if (state ===
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
//
|
|
860
|
-
//
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
globalStore.putValue(entity, 'turnedOffWithTransition', false);
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
const result = await converters.on_off.convertSet(entity, 'state', state, meta);
|
|
867
|
-
result.readAfterWriteTime = 0;
|
|
868
|
-
if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
|
|
869
|
-
result.state.brightness = 1;
|
|
851
|
+
if ((state === undefined || state === null) && brightness === undefined) {
|
|
852
|
+
throw new Error(`At least one of "brightness" or "state" must have a value: '${JSON.stringify(message)}'`);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Infer state from desired brightness if unset. Ideally we'd want to keep it as it is, but this code has always
|
|
856
|
+
// used 'MoveToLevelWithOnOff' so that'd break backwards compatibility. To keep the state, the user
|
|
857
|
+
// has to explicitly set it to null.
|
|
858
|
+
if (state === undefined) {
|
|
859
|
+
// Also write to `meta.message.state` in case we delegate to the `on_off` converter.
|
|
860
|
+
state = meta.message.state = brightness === 0 ? 'off' : 'on';
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const targetState = state === 'toggle' ? (meta.state.state === 'ON' ? 'off' : 'on') : state;
|
|
864
|
+
if (targetState === 'off') {
|
|
865
|
+
// Simulate 'Off' with transition via 'MoveToLevelWithOnOff', otherwise just use 'Off'.
|
|
866
|
+
// TODO: if this is a group where some members don't support Level Control, turning them off
|
|
867
|
+
// with transition may have no effect. (Some devices, such as Envilar ZG302-BOX-RELAY, handle
|
|
868
|
+
// 'MoveToLevelWithOnOff' despite not supporting the cluster; others, like the LEDVANCE SMART+
|
|
869
|
+
// plug, do not.)
|
|
870
|
+
brightness = transition.specified || brightness === 0 ? 0 : undefined;
|
|
871
|
+
if (meta.state.hasOwnProperty('brightness') && meta.state.state === 'ON') {
|
|
872
|
+
// The light's current level gets clobbered in two cases:
|
|
873
|
+
// 1. when 'Off' has a transition, in which case it is really 'MoveToLevelWithOnOff'
|
|
874
|
+
// https://github.com/Koenkk/zigbee-herdsman-converters/issues/1073
|
|
875
|
+
// 2. when 'OnLevel' is set: "If OnLevel is not defined, set the CurrentLevel to the stored level."
|
|
876
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
|
|
877
|
+
// We need to remember current brightness in case the next 'On' does not provide it. `meta` is not reliable
|
|
878
|
+
// here, as it will get clobbered too if reporting is configured.
|
|
879
|
+
globalStore.putValue(entity, 'brightness', meta.state.brightness);
|
|
880
|
+
globalStore.putValue(entity, 'turnedOffWithTransition', brightness !== undefined);
|
|
881
|
+
}
|
|
882
|
+
} else if (targetState === 'on' && brightness === undefined) {
|
|
883
|
+
// Simulate 'On' with transition via 'MoveToLevelWithOnOff', or restore the level from before
|
|
884
|
+
// it was clobbered by a previous transition to off; otherwise just use 'On'.
|
|
885
|
+
// TODO: same problem as above.
|
|
886
|
+
// TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
|
|
887
|
+
if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
|
|
888
|
+
const current = utils.getObjectProperty(meta.state, 'brightness', 254);
|
|
889
|
+
brightness = globalStore.getValue(entity, 'brightness', current);
|
|
890
|
+
try {
|
|
891
|
+
const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
|
|
892
|
+
// TODO: for groups, `read` does not wait for responses. If it did, we could still issue a single
|
|
893
|
+
// command if all values of `OnLevel` are equal, or split into one command per device if not.
|
|
894
|
+
if (attributeRead !== undefined && attributeRead['onLevel'] != 255) {
|
|
895
|
+
brightness = attributeRead['onLevel'];
|
|
870
896
|
}
|
|
871
|
-
|
|
872
|
-
|
|
897
|
+
} catch (e) {
|
|
898
|
+
// OnLevel not supported
|
|
873
899
|
}
|
|
874
900
|
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (brightness === undefined) {
|
|
904
|
+
const result = await converters.on_off.convertSet(entity, 'state', state, meta);
|
|
905
|
+
result.readAfterWriteTime = 0;
|
|
906
|
+
if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
|
|
907
|
+
result.state.brightness = 1;
|
|
879
908
|
}
|
|
909
|
+
return result;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (brightness === 0 && (targetState === 'on' || state === null)) {
|
|
913
|
+
brightness = 1;
|
|
914
|
+
}
|
|
915
|
+
if (brightness === 1 && turnsOffAtBrightness1) {
|
|
916
|
+
brightness = 2;
|
|
917
|
+
}
|
|
880
918
|
|
|
919
|
+
if (targetState !== 'off') {
|
|
881
920
|
globalStore.putValue(entity, 'brightness', brightness);
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
)
|
|
921
|
+
globalStore.clearValue(entity, 'turnedOffWithTransition');
|
|
922
|
+
}
|
|
923
|
+
await entity.command(
|
|
924
|
+
'genLevelCtrl',
|
|
925
|
+
state === null ? 'moveToLevel' : 'moveToLevelWithOnOff',
|
|
926
|
+
{level: Number(brightness), transtime: transition.time},
|
|
927
|
+
utils.getOptions(meta.mapped, entity),
|
|
928
|
+
);
|
|
888
929
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
};
|
|
930
|
+
const result = {state: {}, readAfterWriteTime: transition.time * 100};
|
|
931
|
+
if (brightness !== 0) {
|
|
932
|
+
result.state.brightness = Number(brightness);
|
|
893
933
|
}
|
|
934
|
+
if (state !== null) {
|
|
935
|
+
result.state.state = brightness === 0 ? 'OFF' : 'ON';
|
|
936
|
+
}
|
|
937
|
+
return result;
|
|
894
938
|
},
|
|
895
939
|
convertGet: async (entity, key, meta) => {
|
|
896
940
|
if (key === 'brightness') {
|
|
@@ -3077,10 +3121,10 @@ const converters = {
|
|
|
3077
3121
|
const payload = {0x1009: {value: value * 2, type: 0x20}};
|
|
3078
3122
|
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3079
3123
|
} else if (key==='hysterersis') {
|
|
3080
|
-
const payload = {0x100A: {value: value* 10, type: 0x20}};
|
|
3124
|
+
const payload = {0x100A: {value: value * 10, type: 0x20}};
|
|
3081
3125
|
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3082
3126
|
} else if (key==='display_auto_off_enabled') {
|
|
3083
|
-
const lookup = {'
|
|
3127
|
+
const lookup = {'enabled': 0, 'disabled': 1};
|
|
3084
3128
|
const payload = {0x100B: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3085
3129
|
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3086
3130
|
} else if (key==='alarm_airtemp_overvalue') {
|
|
@@ -7421,6 +7465,70 @@ const converters = {
|
|
|
7421
7465
|
}
|
|
7422
7466
|
},
|
|
7423
7467
|
},
|
|
7468
|
+
ZG204ZL_lms: {
|
|
7469
|
+
key: ['sensitivity', 'keep_time'],
|
|
7470
|
+
convertSet: async (entity, key, value, meta) => {
|
|
7471
|
+
switch (key) {
|
|
7472
|
+
case 'sensitivity':
|
|
7473
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsSensitivity, {'low': 0, 'medium': 1, 'high': 2}[value]);
|
|
7474
|
+
break;
|
|
7475
|
+
case 'keep_time':
|
|
7476
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsKeepTime, {'10': 0, '30': 1, '60': 2, '120': 3}[value]);
|
|
7477
|
+
break;
|
|
7478
|
+
default: // Unknown key
|
|
7479
|
+
meta.logger.warn(`tz.ZG204ZL_lms: Unhandled key ${key}`);
|
|
7480
|
+
}
|
|
7481
|
+
},
|
|
7482
|
+
convertGet: async (entity, key, meta) => {
|
|
7483
|
+
switch (key) {
|
|
7484
|
+
case 'sensitivity':
|
|
7485
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsSensitivity, 0, 'dataQuery' );
|
|
7486
|
+
break;
|
|
7487
|
+
case 'keep_time':
|
|
7488
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsKeepTime, 0, 'dataQuery' );
|
|
7489
|
+
break;
|
|
7490
|
+
default: // Unknown key
|
|
7491
|
+
meta.logger.warn(`Unhandled key toZigbee.ZG204ZL_lms.convertGet ${key}`);
|
|
7492
|
+
}
|
|
7493
|
+
},
|
|
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
|
+
},
|
|
7424
7532
|
// #endregion
|
|
7425
7533
|
|
|
7426
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/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
|
|