zigbee-herdsman-converters 14.0.590 → 14.0.591
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/README.md +1 -0
- package/converters/fromZigbee.js +57 -2
- package/converters/toZigbee.js +126 -8
- package/devices/current_products_corp.js +1 -0
- package/devices/gledopto.js +7 -0
- package/devices/ikea.js +7 -0
- package/devices/osram.js +2 -1
- package/devices/rtx.js +61 -9
- package/devices/tuya.js +1 -0
- package/lib/tuya.js +114 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ If any of those commands finish with an error your PR won't pass the tests and w
|
|
|
23
23
|
- `supportsHueAndSaturation`: see toZigbee.light_color (default: false)
|
|
24
24
|
- `timeout`: timeout for commands to this device used in toZigbee. (default: 10000)
|
|
25
25
|
- `coverInverted`: Set to true for cover controls that report position=100 as open (default: false)
|
|
26
|
+
- `coverStateFromTilt`: Set cover state based on tilt
|
|
26
27
|
- `turnsOffAtBrightness1`: Indicates light turns off when brightness 1 is set (default: false)
|
|
27
28
|
- `pinCodeCount`: Amount of pincodes the lock can handle
|
|
28
29
|
- `disableActionGroup`: Prevents some converters adding the action_group to the payload (default: false)
|
package/converters/fromZigbee.js
CHANGED
|
@@ -1542,15 +1542,22 @@ const converters = {
|
|
|
1542
1542
|
// For zigbee-herdsman-converters: open = 100, close = 0
|
|
1543
1543
|
// ubisys J1 will report 255 if lift or tilt positions are not known, so skip that.
|
|
1544
1544
|
const invert = model.meta && model.meta.coverInverted ? !options.invert_cover : options.invert_cover;
|
|
1545
|
+
const coverStateFromTilt = model.meta && model.meta.coverStateFromTilt;
|
|
1545
1546
|
if (msg.data.hasOwnProperty('currentPositionLiftPercentage') && msg.data['currentPositionLiftPercentage'] <= 100) {
|
|
1546
1547
|
const value = msg.data['currentPositionLiftPercentage'];
|
|
1547
1548
|
result[postfixWithEndpointName('position', msg, model, meta)] = invert ? value : 100 - value;
|
|
1548
|
-
|
|
1549
|
-
|
|
1549
|
+
if (!coverStateFromTilt) {
|
|
1550
|
+
result[postfixWithEndpointName('state', msg, model, meta)] =
|
|
1551
|
+
invert ? (value === 100 ? 'CLOSE' : 'OPEN') : (value === 0 ? 'CLOSE' : 'OPEN');
|
|
1552
|
+
}
|
|
1550
1553
|
}
|
|
1551
1554
|
if (msg.data.hasOwnProperty('currentPositionTiltPercentage') && msg.data['currentPositionTiltPercentage'] <= 100) {
|
|
1552
1555
|
const value = msg.data['currentPositionTiltPercentage'];
|
|
1553
1556
|
result[postfixWithEndpointName('tilt', msg, model, meta)] = invert ? value : 100 - value;
|
|
1557
|
+
if (coverStateFromTilt) {
|
|
1558
|
+
result[postfixWithEndpointName('state', msg, model, meta)] =
|
|
1559
|
+
invert ? (value === 100 ? 'CLOSE' : 'OPEN') : (value === 0 ? 'CLOSE' : 'OPEN');
|
|
1560
|
+
}
|
|
1554
1561
|
}
|
|
1555
1562
|
return result;
|
|
1556
1563
|
},
|
|
@@ -6820,6 +6827,17 @@ const converters = {
|
|
|
6820
6827
|
case 7: {
|
|
6821
6828
|
return {battery: value};
|
|
6822
6829
|
}
|
|
6830
|
+
case 10: {
|
|
6831
|
+
let data = 'disabled';
|
|
6832
|
+
if (value == 1) {
|
|
6833
|
+
data = '24h';
|
|
6834
|
+
} else if (value == 2) {
|
|
6835
|
+
data = '48h';
|
|
6836
|
+
} else if (value == 3) {
|
|
6837
|
+
data = '72h';
|
|
6838
|
+
}
|
|
6839
|
+
return {weather_delay: data};
|
|
6840
|
+
}
|
|
6823
6841
|
case 11: {
|
|
6824
6842
|
// value reported in seconds
|
|
6825
6843
|
return {timer_time_left: value / 60};
|
|
@@ -6833,6 +6851,43 @@ const converters = {
|
|
|
6833
6851
|
// value reported in seconds
|
|
6834
6852
|
return {last_valve_open_duration: value / 60};
|
|
6835
6853
|
}
|
|
6854
|
+
case 16: {
|
|
6855
|
+
const tresult = {
|
|
6856
|
+
cycle_timer_1: '',
|
|
6857
|
+
cycle_timer_2: '',
|
|
6858
|
+
cycle_timer_3: '',
|
|
6859
|
+
cycle_timer_4: '',
|
|
6860
|
+
};
|
|
6861
|
+
for (let index = 0; index < 40; index += 12) {
|
|
6862
|
+
const timer = tuya.convertRawToCycleTimer(value.slice(index));
|
|
6863
|
+
if (timer.irrigationDuration > 0) {
|
|
6864
|
+
tresult['cycle_timer_' + (index / 13 + 1)] = timer.starttime +
|
|
6865
|
+
' / ' + timer.endtime + ' / ' +
|
|
6866
|
+
timer.irrigationDuration + ' / ' +
|
|
6867
|
+
timer.pauseDuration + ' / ' +
|
|
6868
|
+
timer.weekdays + ' / ' + timer.active;
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
return tresult;
|
|
6872
|
+
}
|
|
6873
|
+
case 17: {
|
|
6874
|
+
const tresult = {
|
|
6875
|
+
normal_schedule_timer_1: '',
|
|
6876
|
+
normal_schedule_timer_2: '',
|
|
6877
|
+
normal_schedule_timer_3: '',
|
|
6878
|
+
normal_schedule_timer_4: '',
|
|
6879
|
+
};
|
|
6880
|
+
for (let index = 0; index < 40; index += 13) {
|
|
6881
|
+
const timer = tuya.convertRawToTimer(value.slice(index));
|
|
6882
|
+
if (timer.duration > 0) {
|
|
6883
|
+
tresult['normal_schedule_timer_' + (index / 13 + 1)] = timer.time +
|
|
6884
|
+
' / ' + timer.duration +
|
|
6885
|
+
' / ' + timer.weekdays +
|
|
6886
|
+
' / ' + timer.active;
|
|
6887
|
+
}
|
|
6888
|
+
}
|
|
6889
|
+
return tresult;
|
|
6890
|
+
}
|
|
6836
6891
|
default: {
|
|
6837
6892
|
meta.logger.warn(`zigbee-herdsman-converters:RTXZVG1Valve: NOT RECOGNIZED DP ` +
|
|
6838
6893
|
`#${dp} with data ${JSON.stringify(dpValue)}`);
|
package/converters/toZigbee.js
CHANGED
|
@@ -3992,14 +3992,132 @@ const converters = {
|
|
|
3992
3992
|
return {state: {timer: value}};
|
|
3993
3993
|
},
|
|
3994
3994
|
},
|
|
3995
|
-
|
|
3996
|
-
key: ['
|
|
3997
|
-
convertSet: async (entity, key, value, meta) => {
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
3995
|
+
ZVG1_weather_delay: {
|
|
3996
|
+
key: ['weather_delay'],
|
|
3997
|
+
convertSet: async (entity, key, value, meta) => {
|
|
3998
|
+
const lookup = {'disabled': 0, '24h': 1, '48h': 2, '72h': 3};
|
|
3999
|
+
await tuya.sendDataPointEnum(entity, 10, lookup[value]);
|
|
4000
|
+
},
|
|
4001
|
+
},
|
|
4002
|
+
ZVG1_cycle_timer: {
|
|
4003
|
+
key: ['cycle_timer_1', 'cycle_timer_2', 'cycle_timer_3', 'cycle_timer_4'],
|
|
4004
|
+
convertSet: async (entity, key, value, meta) => {
|
|
4005
|
+
let data = [0];
|
|
4006
|
+
const footer = [0x64];
|
|
4007
|
+
if (value == '') {
|
|
4008
|
+
// delete
|
|
4009
|
+
data.push(0x04);
|
|
4010
|
+
data.push(parseInt(key.substr(-1)));
|
|
4011
|
+
await tuya.sendDataPointRaw(entity, 16, data);
|
|
4012
|
+
const ret = {state: {}};
|
|
4013
|
+
ret['state'][key] = value;
|
|
4014
|
+
return ret;
|
|
4015
|
+
} else {
|
|
4016
|
+
if ((meta.state.hasOwnProperty(key) && meta.state[key] == '') ||
|
|
4017
|
+
!meta.state.hasOwnProperty(key)) {
|
|
4018
|
+
data.push(0x03);
|
|
4019
|
+
} else {
|
|
4020
|
+
data.push(0x02);
|
|
4021
|
+
data.push(parseInt(key.substr(-1)));
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
const tarray = value.replace(/ /g, '').split('/');
|
|
4026
|
+
if (tarray.length < 4) {
|
|
4027
|
+
throw new Error('Please check the format of the timer string');
|
|
4028
|
+
}
|
|
4029
|
+
if (tarray.length < 5) {
|
|
4030
|
+
tarray.push('MoTuWeThFrSaSu');
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
if (tarray.length < 6) {
|
|
4034
|
+
tarray.push('1');
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
const starttime = tarray[0];
|
|
4038
|
+
const endtime = tarray[1];
|
|
4039
|
+
const irrigationDuration = tarray[2];
|
|
4040
|
+
const pauseDuration = tarray[3];
|
|
4041
|
+
const weekdays = tarray[4];
|
|
4042
|
+
const active = parseInt(tarray[5]);
|
|
4043
|
+
|
|
4044
|
+
if (!(active == 0 || active == 1)) {
|
|
4045
|
+
throw new Error('Active value only 0 or 1 allowed');
|
|
4046
|
+
}
|
|
4047
|
+
data.push(active);
|
|
4048
|
+
|
|
4049
|
+
const weekdaysPart = tuya.convertWeekdaysTo1ByteHexArray(weekdays);
|
|
4050
|
+
data = data.concat(weekdaysPart);
|
|
4051
|
+
|
|
4052
|
+
data = data.concat(tuya.convertTimeTo2ByteHexArray(starttime));
|
|
4053
|
+
data = data.concat(tuya.convertTimeTo2ByteHexArray(endtime));
|
|
4054
|
+
|
|
4055
|
+
data = data.concat(tuya.convertDecimalValueTo2ByteHexArray(irrigationDuration));
|
|
4056
|
+
data = data.concat(tuya.convertDecimalValueTo2ByteHexArray(pauseDuration));
|
|
4057
|
+
|
|
4058
|
+
data = data.concat(footer);
|
|
4059
|
+
await tuya.sendDataPointRaw(entity, 16, data);
|
|
4060
|
+
const ret = {state: {}};
|
|
4061
|
+
ret['state'][key] = value;
|
|
4062
|
+
return ret;
|
|
4063
|
+
},
|
|
4064
|
+
},
|
|
4065
|
+
ZVG1_normal_schedule_timer: {
|
|
4066
|
+
key: ['normal_schedule_timer_1', 'normal_schedule_timer_2', 'normal_schedule_timer_3', 'normal_schedule_timer_4'],
|
|
4067
|
+
convertSet: async (entity, key, value, meta) => {
|
|
4068
|
+
let data = [0];
|
|
4069
|
+
const footer = [0x07, 0xe6, 0x08, 0x01, 0x01];
|
|
4070
|
+
if (value == '') {
|
|
4071
|
+
// delete
|
|
4072
|
+
data.push(0x04);
|
|
4073
|
+
data.push(parseInt(key.substr(-1)));
|
|
4074
|
+
await tuya.sendDataPointRaw(entity, 17, data);
|
|
4075
|
+
const ret = {state: {}};
|
|
4076
|
+
ret['state'][key] = value;
|
|
4077
|
+
return ret;
|
|
4078
|
+
} else {
|
|
4079
|
+
if ((meta.state.hasOwnProperty(key) && meta.state[key] == '') || !meta.state.hasOwnProperty(key)) {
|
|
4080
|
+
data.push(0x03);
|
|
4081
|
+
} else {
|
|
4082
|
+
data.push(0x02);
|
|
4083
|
+
data.push(parseInt(key.substr(-1)));
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4087
|
+
const tarray = value.replace(/ /g, '').split('/');
|
|
4088
|
+
if (tarray.length < 2) {
|
|
4089
|
+
throw new Error('Please check the format of the timer string');
|
|
4090
|
+
}
|
|
4091
|
+
if (tarray.length < 3) {
|
|
4092
|
+
tarray.push('MoTuWeThFrSaSu');
|
|
4093
|
+
}
|
|
4094
|
+
|
|
4095
|
+
if (tarray.length < 4) {
|
|
4096
|
+
tarray.push('1');
|
|
4097
|
+
}
|
|
4098
|
+
|
|
4099
|
+
const time = tarray[0];
|
|
4100
|
+
const duration = tarray[1];
|
|
4101
|
+
const weekdays = tarray[2];
|
|
4102
|
+
const active = parseInt(tarray[3]);
|
|
4103
|
+
|
|
4104
|
+
if (!(active == 0 || active == 1)) {
|
|
4105
|
+
throw new Error('Active value only 0 or 1 allowed');
|
|
4106
|
+
}
|
|
4107
|
+
|
|
4108
|
+
data = data.concat(tuya.convertTimeTo2ByteHexArray(time));
|
|
4109
|
+
|
|
4110
|
+
const durationPart = tuya.convertDecimalValueTo2ByteHexArray(duration);
|
|
4111
|
+
data = data.concat(durationPart);
|
|
4112
|
+
|
|
4113
|
+
const weekdaysPart = tuya.convertWeekdaysTo1ByteHexArray(weekdays);
|
|
4114
|
+
data = data.concat(weekdaysPart);
|
|
4115
|
+
data = data.concat([64, active]);
|
|
4116
|
+
data = data.concat(footer);
|
|
4117
|
+
await tuya.sendDataPointRaw(entity, 17, data);
|
|
4118
|
+
const ret = {state: {}};
|
|
4119
|
+
ret['state'][key] = value;
|
|
4120
|
+
return ret;
|
|
4003
4121
|
},
|
|
4004
4122
|
},
|
|
4005
4123
|
EMIZB_132_mode: {
|
|
@@ -12,6 +12,7 @@ module.exports = [
|
|
|
12
12
|
description: 'Gen. 2 hybrid E-Wand',
|
|
13
13
|
fromZigbee: [fz.cover_position_tilt, fz.battery],
|
|
14
14
|
toZigbee: [tz.cover_state, tz.cover_position_tilt],
|
|
15
|
+
meta: {coverStateFromTilt: true},
|
|
15
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
16
17
|
const endpoint = device.getEndpoint(1);
|
|
17
18
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'closuresWindowCovering']);
|
package/devices/gledopto.js
CHANGED
|
@@ -330,6 +330,13 @@ module.exports = [
|
|
|
330
330
|
description: 'Zigbee smart filament LED bulb',
|
|
331
331
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495]}),
|
|
332
332
|
},
|
|
333
|
+
{
|
|
334
|
+
zigbeeModel: ['GL-S-006P'],
|
|
335
|
+
model: 'GL-S-006P',
|
|
336
|
+
vendor: 'Gledopto',
|
|
337
|
+
description: 'Zigbee GU10 LED lamp',
|
|
338
|
+
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495]}),
|
|
339
|
+
},
|
|
333
340
|
{
|
|
334
341
|
zigbeeModel: ['GL-MC-001P'],
|
|
335
342
|
model: 'GL-MC-001P',
|
package/devices/ikea.js
CHANGED
|
@@ -319,6 +319,13 @@ module.exports = [
|
|
|
319
319
|
description: 'TRADFRI LED bulb E27 1000 lumen, dimmable, opal white',
|
|
320
320
|
extend: tradfriExtend.light_onoff_brightness(),
|
|
321
321
|
},
|
|
322
|
+
{
|
|
323
|
+
zigbeeModel: ['TRADFRIbulbE26WWglobeclear250lm'],
|
|
324
|
+
model: 'LED2008G3',
|
|
325
|
+
vendor: 'IKEA',
|
|
326
|
+
description: 'TRADFRI LED bulb E26 250 lumen, wireless dimmable warm white/globe clear',
|
|
327
|
+
extend: tradfriExtend.light_onoff_brightness(),
|
|
328
|
+
},
|
|
322
329
|
{
|
|
323
330
|
zigbeeModel: ['TRADFRIbulbG125E27WSopal470lm', 'TRADFRIbulbG125E26WSopal450lm'],
|
|
324
331
|
model: 'LED1936G5',
|
package/devices/osram.js
CHANGED
|
@@ -331,7 +331,8 @@ module.exports = [
|
|
|
331
331
|
fz.legacy.osram_lightify_switch_cmdOff, fz.legacy.osram_lightify_switch_cmdMove, fz.battery,
|
|
332
332
|
fz.legacy.osram_lightify_switch_cmdMoveToLevelWithOnOff],
|
|
333
333
|
exposes: [e.battery(), e.action([
|
|
334
|
-
'
|
|
334
|
+
'on', 'brightness_move_up', 'brightness_move_down', 'brightness_stop', 'color_temperature_move', 'hue_move', 'hue_stop',
|
|
335
|
+
'move_to_saturation', 'off', 'brightness_move_to_level'])],
|
|
335
336
|
toZigbee: [],
|
|
336
337
|
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
337
338
|
ota: ota.ledvance,
|
package/devices/rtx.js
CHANGED
|
@@ -6,22 +6,74 @@ const ea = exposes.access;
|
|
|
6
6
|
|
|
7
7
|
module.exports = [
|
|
8
8
|
{
|
|
9
|
-
fingerprint: [
|
|
10
|
-
{modelID: 'TS0601', manufacturerName: '
|
|
9
|
+
fingerprint: [
|
|
10
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_akjefhj5'},
|
|
11
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_2wg5qrjy'},
|
|
12
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_81isopgh'},
|
|
13
|
+
],
|
|
11
14
|
model: 'ZVG1',
|
|
12
15
|
vendor: 'RTX',
|
|
13
16
|
description: 'Zigbee smart water valve',
|
|
14
17
|
fromZigbee: [fz.ZVG1, fz.ignore_tuya_set_time, fz.ignore_basic_report],
|
|
15
|
-
toZigbee: [tz.tuya_switch_state, tz.ZVG1_timer, tz.
|
|
18
|
+
toZigbee: [tz.tuya_switch_state, tz.ZVG1_weather_delay, tz.ZVG1_timer, tz.ZVG1_cycle_timer, tz.ZVG1_normal_schedule_timer],
|
|
16
19
|
exposes: [e.switch().setAccess('state', ea.STATE_SET), e.battery(),
|
|
17
|
-
exposes.enum('
|
|
18
|
-
exposes.
|
|
20
|
+
exposes.enum('weather_delay', ea.STATE_SET, ['disabled', '24h', '48h', '72h']),
|
|
21
|
+
exposes.enum('timer_state', ea.STATE, ['disabled', 'active', 'enabled']),
|
|
22
|
+
exposes.numeric('timer', ea.STATE_SET).withValueMin(0).withValueMax(60).withUnit('min')
|
|
19
23
|
.withDescription('Auto off after specific time'),
|
|
20
|
-
exposes.numeric('timer_time_left',
|
|
24
|
+
exposes.numeric('timer_time_left', ea.STATE).withUnit('min')
|
|
21
25
|
.withDescription('Auto off timer time left'),
|
|
22
|
-
exposes.numeric('last_valve_open_duration',
|
|
26
|
+
exposes.numeric('last_valve_open_duration', ea.STATE).withUnit('min')
|
|
23
27
|
.withDescription('Time the valve was open when state on'),
|
|
24
|
-
exposes.numeric('water_consumed',
|
|
25
|
-
.withDescription('Liters of water consumed')
|
|
28
|
+
exposes.numeric('water_consumed', ea.STATE).withUnit('l')
|
|
29
|
+
.withDescription('Liters of water consumed'),
|
|
30
|
+
exposes.text('cycle_timer_1', ea.STATE_SET).withDescription('Format 08:00 / 20:00 / 15 / 60 / MoTuWeThFrSaSu / 1 (' +
|
|
31
|
+
'08:00 = start time ' +
|
|
32
|
+
'20:00 = end time ' +
|
|
33
|
+
'15 = irrigation duration in minutes ' +
|
|
34
|
+
'60 = pause duration in minutes ' +
|
|
35
|
+
'MoTu..= active weekdays ' +
|
|
36
|
+
'1 = deactivate timer with 0)'),
|
|
37
|
+
exposes.text('cycle_timer_2', ea.STATE_SET).withDescription('Format 08:00 / 20:00 / 15 / 60 / MoTuWeThFrSaSu / 1 (' +
|
|
38
|
+
'08:00 = start time ' +
|
|
39
|
+
'20:00 = end time ' +
|
|
40
|
+
'15 = irrigation duration in minutes ' +
|
|
41
|
+
'60 = pause duration in minutes ' +
|
|
42
|
+
'MoTu..= active weekdays ' +
|
|
43
|
+
'1 = deactivate timer with 0)'),
|
|
44
|
+
exposes.text('cycle_timer_3', ea.STATE_SET).withDescription('Format 08:00 / 20:00 / 15 / 60 / MoTuWeThFrSaSu / 1 (' +
|
|
45
|
+
'08:00 = start time ' +
|
|
46
|
+
'20:00 = end time ' +
|
|
47
|
+
'15 = irrigation duration in minutes ' +
|
|
48
|
+
'60 = pause duration in minutes ' +
|
|
49
|
+
'MoTu..= active weekdays ' +
|
|
50
|
+
'1 = deactivate timer with 0)'),
|
|
51
|
+
exposes.text('cycle_timer_4', ea.STATE_SET).withDescription('Format 08:00 / 20:00 / 15 / 60 / MoTuWeThFrSaSu / 1 (' +
|
|
52
|
+
'08:00 = start time ' +
|
|
53
|
+
'20:00 = end time ' +
|
|
54
|
+
'15 = irrigation duration in minutes ' +
|
|
55
|
+
'60 = pause duration in minutes ' +
|
|
56
|
+
'MoTu..= active weekdays ' +
|
|
57
|
+
'1 = deactivate timer with 0)'),
|
|
58
|
+
exposes.text('normal_schedule_timer_1', ea.STATE_SET).withDescription('Format 08:00 / 15 / MoTuWeThFrSaSu / 1 (' +
|
|
59
|
+
'08:00 = start time ' +
|
|
60
|
+
'15 = duration in minutes ' +
|
|
61
|
+
'MoTu..= active weekdays ' +
|
|
62
|
+
'1 = deactivate timer with 0)'),
|
|
63
|
+
exposes.text('normal_schedule_timer_2', ea.STATE_SET).withDescription('Format 08:00 / 15 / MoTuWeThFrSaSu / 1 (' +
|
|
64
|
+
'08:00 = start time ' +
|
|
65
|
+
'15 = duration in minutes ' +
|
|
66
|
+
'MoTu..= active weekdays ' +
|
|
67
|
+
'1 = deactivate timer with 0)'),
|
|
68
|
+
exposes.text('normal_schedule_timer_3', ea.STATE_SET).withDescription('Format 08:00 / 15 / MoTuWeThFrSaSu / 1 (' +
|
|
69
|
+
'08:00 = start time ' +
|
|
70
|
+
'15 = duration in minutes ' +
|
|
71
|
+
'MoTu..= active weekdays ' +
|
|
72
|
+
'1 = deactivate timer with 0)'),
|
|
73
|
+
exposes.text('normal_schedule_timer_4', ea.STATE_SET).withDescription('Format 08:00 / 15 / MoTuWeThFrSaSu / 1 (' +
|
|
74
|
+
'08:00 = start time ' +
|
|
75
|
+
'15 = duration in minutes ' +
|
|
76
|
+
'MoTu..= active weekdays ' +
|
|
77
|
+
'1 = deactivate timer with 0)')],
|
|
26
78
|
},
|
|
27
79
|
];
|
package/devices/tuya.js
CHANGED
|
@@ -914,6 +914,7 @@ module.exports = [
|
|
|
914
914
|
{
|
|
915
915
|
fingerprint: [{modelID: 'TS0207', manufacturerName: '_TZ3000_m0vaazab'},
|
|
916
916
|
{modelID: 'TS0207', manufacturerName: '_TZ3000_ufttklsz'},
|
|
917
|
+
{modelID: 'TS0207', manufacturerName: '_TZ3000_nkkl7uzv'},
|
|
917
918
|
{modelID: 'TS0207', manufacturerName: '_TZ3000_5k5vh43t'}],
|
|
918
919
|
model: 'TS0207_repeater',
|
|
919
920
|
vendor: 'TuYa',
|
package/lib/tuya.js
CHANGED
|
@@ -113,6 +113,116 @@ function logUnexpectedDataValue(where, msg, dpValue, meta, valueKind, expectedMi
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
function convertRawToCycleTimer(value) {
|
|
117
|
+
let timernr = 0;
|
|
118
|
+
let starttime = '00:00';
|
|
119
|
+
let endtime = '00:00';
|
|
120
|
+
let irrigationDuration = 0;
|
|
121
|
+
let pauseDuration = 0;
|
|
122
|
+
let weekdays = 'once';
|
|
123
|
+
let timeractive = 0;
|
|
124
|
+
if (value.length > 11) {
|
|
125
|
+
timernr = value[1];
|
|
126
|
+
timeractive = value[2];
|
|
127
|
+
if (value[3] > 0) {
|
|
128
|
+
weekdays = (value[3] & 0x40 ? 'Mo' : '') +
|
|
129
|
+
(value[3] & 0x20 ? 'Tu' : '') +
|
|
130
|
+
(value[3] & 0x10 ? 'We' : '') +
|
|
131
|
+
(value[3] & 0x08 ? 'Th' : '') +
|
|
132
|
+
(value[3] & 0x04 ? 'Fr' : '') +
|
|
133
|
+
(value[3] & 0x02 ? 'Sa' : '') +
|
|
134
|
+
(value[3] & 0x01 ? 'Su' : '');
|
|
135
|
+
} else {
|
|
136
|
+
weekdays = 'once';
|
|
137
|
+
}
|
|
138
|
+
let minsincemidnight = value[4] * 256 + value[5];
|
|
139
|
+
starttime = String(parseInt(minsincemidnight / 60)).padStart(2, '0') + ':' + String(minsincemidnight % 60).padStart(2, '0');
|
|
140
|
+
minsincemidnight = value[6] * 256 + value[7];
|
|
141
|
+
endtime = String(parseInt(minsincemidnight / 60)).padStart(2, '0') + ':' + String(minsincemidnight % 60).padStart(2, '0');
|
|
142
|
+
irrigationDuration = value[8] * 256 + value[9];
|
|
143
|
+
pauseDuration = value[10] * 256 + value[11];
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
timernr: timernr,
|
|
147
|
+
starttime: starttime,
|
|
148
|
+
endtime: endtime,
|
|
149
|
+
irrigationDuration: irrigationDuration,
|
|
150
|
+
pauseDuration: pauseDuration,
|
|
151
|
+
weekdays: weekdays,
|
|
152
|
+
active: timeractive,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function convertRawToTimer(value) {
|
|
157
|
+
let timernr = 0;
|
|
158
|
+
let starttime = '00:00';
|
|
159
|
+
let duration = 0;
|
|
160
|
+
let weekdays = 'once';
|
|
161
|
+
let timeractive = '';
|
|
162
|
+
if (value.length > 12) {
|
|
163
|
+
timernr = value[1];
|
|
164
|
+
const minsincemidnight = value[2] * 256 + value[3];
|
|
165
|
+
starttime = String(parseInt(minsincemidnight / 60)).padStart(2, '0') + ':' + String(minsincemidnight % 60).padStart(2, '0');
|
|
166
|
+
duration = value[4] * 256 + value[5];
|
|
167
|
+
if (value[6] > 0) {
|
|
168
|
+
weekdays = (value[6] & 0x40 ? 'Mo' : '') +
|
|
169
|
+
(value[6] & 0x20 ? 'Tu' : '') +
|
|
170
|
+
(value[6] & 0x10 ? 'We' : '') +
|
|
171
|
+
(value[6] & 0x08 ? 'Th' : '') +
|
|
172
|
+
(value[6] & 0x04 ? 'Fr' : '') +
|
|
173
|
+
(value[6] & 0x02 ? 'Sa' : '') +
|
|
174
|
+
(value[6] & 0x01 ? 'Su' : '');
|
|
175
|
+
} else {
|
|
176
|
+
weekdays = 'once';
|
|
177
|
+
}
|
|
178
|
+
timeractive = value[8];
|
|
179
|
+
}
|
|
180
|
+
return {timernr: timernr, time: starttime, duration: duration, weekdays: weekdays, active: timeractive};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function convertTimeTo2ByteHexArray(time) {
|
|
184
|
+
const timeArray = time.split(':');
|
|
185
|
+
if (timeArray.length != 2) {
|
|
186
|
+
throw new Error('Time format incorrect');
|
|
187
|
+
}
|
|
188
|
+
const timeHour = parseInt(timeArray[0]);
|
|
189
|
+
const timeMinute = parseInt(timeArray[1]);
|
|
190
|
+
|
|
191
|
+
if (timeHour > 23 || timeMinute > 59) {
|
|
192
|
+
throw new Error('Time incorrect');
|
|
193
|
+
}
|
|
194
|
+
return convertDecimalValueTo2ByteHexArray(timeHour * 60 + timeMinute);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function convertWeekdaysTo1ByteHexArray(weekdays) {
|
|
198
|
+
let nr = 0;
|
|
199
|
+
if (weekdays == 'once') {
|
|
200
|
+
return nr;
|
|
201
|
+
}
|
|
202
|
+
if (weekdays.includes('Mo')) {
|
|
203
|
+
nr |= 0x40;
|
|
204
|
+
}
|
|
205
|
+
if (weekdays.includes('Tu')) {
|
|
206
|
+
nr |= 0x20;
|
|
207
|
+
}
|
|
208
|
+
if (weekdays.includes('We')) {
|
|
209
|
+
nr |= 0x10;
|
|
210
|
+
}
|
|
211
|
+
if (weekdays.includes('Th')) {
|
|
212
|
+
nr |= 0x08;
|
|
213
|
+
}
|
|
214
|
+
if (weekdays.includes('Fr')) {
|
|
215
|
+
nr |= 0x04;
|
|
216
|
+
}
|
|
217
|
+
if (weekdays.includes('Sa')) {
|
|
218
|
+
nr |= 0x02;
|
|
219
|
+
}
|
|
220
|
+
if (weekdays.includes('Su')) {
|
|
221
|
+
nr |= 0x01;
|
|
222
|
+
}
|
|
223
|
+
return [nr];
|
|
224
|
+
}
|
|
225
|
+
|
|
116
226
|
function convertDecimalValueTo4ByteHexArray(value) {
|
|
117
227
|
const hexValue = Number(value).toString(16).padStart(8, '0');
|
|
118
228
|
const chunk1 = hexValue.substr(0, 2);
|
|
@@ -1039,6 +1149,10 @@ module.exports = {
|
|
|
1039
1149
|
dpValueFromStringBuffer,
|
|
1040
1150
|
dpValueFromRaw,
|
|
1041
1151
|
dpValueFromBitmap,
|
|
1152
|
+
convertRawToCycleTimer,
|
|
1153
|
+
convertRawToTimer,
|
|
1154
|
+
convertTimeTo2ByteHexArray,
|
|
1155
|
+
convertWeekdaysTo1ByteHexArray,
|
|
1042
1156
|
convertDecimalValueTo4ByteHexArray,
|
|
1043
1157
|
convertDecimalValueTo2ByteHexArray,
|
|
1044
1158
|
onEventSetTime,
|