zigbee-herdsman-converters 14.0.590 → 14.0.593
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/gewiss.js +2 -2
- package/devices/giex.js +4 -1
- package/devices/gledopto.js +7 -0
- package/devices/ikea.js +7 -0
- package/devices/lidl.js +8 -0
- package/devices/osram.js +2 -1
- package/devices/philips.js +1 -1
- package/devices/rtx.js +61 -9
- package/devices/skydance.js +9 -0
- package/devices/tuya.js +5 -2
- package/devices/xiaomi.js +20 -0
- package/lib/tuya.js +114 -0
- package/lib/utils.js +4 -1
- package/lib/xiaomi.js +3 -2
- 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 ? 'OPEN' : 'CLOSE') : (value === 0 ? 'OPEN' : 'CLOSE');
|
|
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/gewiss.js
CHANGED
|
@@ -39,8 +39,8 @@ module.exports = [
|
|
|
39
39
|
toZigbee: [tz.cover_state, tz.cover_position_tilt],
|
|
40
40
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
41
41
|
const endpoint = device.getEndpoint(1);
|
|
42
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['
|
|
43
|
-
await reporting.
|
|
42
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['closuresWindowCovering']);
|
|
43
|
+
await reporting.currentPositionLiftPercentage(endpoint);
|
|
44
44
|
},
|
|
45
45
|
exposes: [e.cover_position()],
|
|
46
46
|
},
|
package/devices/giex.js
CHANGED
|
@@ -104,7 +104,10 @@ const tzLocal = {
|
|
|
104
104
|
|
|
105
105
|
module.exports = [
|
|
106
106
|
{
|
|
107
|
-
fingerprint: [
|
|
107
|
+
fingerprint: [
|
|
108
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_sh1btabb'},
|
|
109
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_a7sghmms'},
|
|
110
|
+
],
|
|
108
111
|
model: 'QT06',
|
|
109
112
|
vendor: 'GiEX',
|
|
110
113
|
description: 'Water irrigation valve',
|
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/lidl.js
CHANGED
|
@@ -561,6 +561,14 @@ module.exports = [
|
|
|
561
561
|
device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
|
|
562
562
|
},
|
|
563
563
|
},
|
|
564
|
+
{
|
|
565
|
+
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_zbabx9wh'}],
|
|
566
|
+
model: 'HG08007',
|
|
567
|
+
vendor: 'TuYa',
|
|
568
|
+
description: 'Livarno Home outdoor LED band',
|
|
569
|
+
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500], disableColorTempStartup: true}),
|
|
570
|
+
meta: {applyRedFix: true, enhancedHue: false},
|
|
571
|
+
},
|
|
564
572
|
{
|
|
565
573
|
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_z1vlyufu'}],
|
|
566
574
|
model: '14158704L',
|
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/philips.js
CHANGED
|
@@ -1325,7 +1325,7 @@ module.exports = [
|
|
|
1325
1325
|
extend: hueExtend.light_onoff_brightness_colortemp(),
|
|
1326
1326
|
},
|
|
1327
1327
|
{
|
|
1328
|
-
zigbeeModel: ['LTP002'],
|
|
1328
|
+
zigbeeModel: ['LTP002', '929003054901'],
|
|
1329
1329
|
model: '4023330P7',
|
|
1330
1330
|
vendor: 'Philips',
|
|
1331
1331
|
description: 'Hue white ambiance suspension Amaze',
|
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/skydance.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const exposes = require('../lib/exposes');
|
|
2
2
|
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
3
|
const tz = require('../converters/toZigbee');
|
|
4
|
+
const extend = require('../lib/extend');
|
|
4
5
|
const ea = exposes.access;
|
|
5
6
|
|
|
6
7
|
module.exports = [
|
|
@@ -49,6 +50,14 @@ module.exports = [
|
|
|
49
50
|
ea.STATE_SET).withColor(['hs']),
|
|
50
51
|
],
|
|
51
52
|
},
|
|
53
|
+
{
|
|
54
|
+
fingerprint: [{modelID: 'TS0503B', manufacturerName: '_TZB210_zdvrsts8'}],
|
|
55
|
+
model: 'WZ5_rgb_1',
|
|
56
|
+
vendor: 'TuYa',
|
|
57
|
+
description: 'Zigbee & RF 5 in 1 LED controller (RGB mode)',
|
|
58
|
+
extend: extend.light_onoff_brightness_color({supportsHS: true, preferHS: true, disableEffect: true}),
|
|
59
|
+
meta: {applyRedFix: true, enhancedHue: false},
|
|
60
|
+
},
|
|
52
61
|
{
|
|
53
62
|
fingerprint: [
|
|
54
63
|
{modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'},
|
package/devices/tuya.js
CHANGED
|
@@ -19,7 +19,8 @@ const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak',
|
|
|
19
19
|
'_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
|
|
20
20
|
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo', '_TZ3000_ksw8qtmt',
|
|
21
21
|
'_TZ3000_1h2x4akh', '_TZ3000_9vo5icau', '_TZ3000_cehuw1lw', '_TZ3000_ko6v90pg', '_TZ3000_f1bapcit', '_TZ3000_cjrngdr3',
|
|
22
|
-
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx'
|
|
22
|
+
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx',
|
|
23
|
+
'_TZ3000_ss98ec5d', '_TZ3000_gznh2xla'];
|
|
23
24
|
|
|
24
25
|
const tzLocal = {
|
|
25
26
|
TS0504B_color: {
|
|
@@ -796,7 +797,8 @@ module.exports = [
|
|
|
796
797
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_trm3l2aw'},
|
|
797
798
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_95txyzbx'},
|
|
798
799
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_odlghna1'},
|
|
799
|
-
{modelID: 'TS0503B', manufacturerName: '_TZ3220_wp1k8xws'}
|
|
800
|
+
{modelID: 'TS0503B', manufacturerName: '_TZ3220_wp1k8xws'},
|
|
801
|
+
{modelID: 'TS0503B', manufacturerName: '_TZ3210_wp1k8xws'}],
|
|
800
802
|
model: 'TS0503B',
|
|
801
803
|
vendor: 'TuYa',
|
|
802
804
|
description: 'Zigbee RGB light',
|
|
@@ -914,6 +916,7 @@ module.exports = [
|
|
|
914
916
|
{
|
|
915
917
|
fingerprint: [{modelID: 'TS0207', manufacturerName: '_TZ3000_m0vaazab'},
|
|
916
918
|
{modelID: 'TS0207', manufacturerName: '_TZ3000_ufttklsz'},
|
|
919
|
+
{modelID: 'TS0207', manufacturerName: '_TZ3000_nkkl7uzv'},
|
|
917
920
|
{modelID: 'TS0207', manufacturerName: '_TZ3000_5k5vh43t'}],
|
|
918
921
|
model: 'TS0207_repeater',
|
|
919
922
|
vendor: 'TuYa',
|
package/devices/xiaomi.js
CHANGED
|
@@ -1007,6 +1007,26 @@ module.exports = [
|
|
|
1007
1007
|
},
|
|
1008
1008
|
ota: ota.zigbeeOTA,
|
|
1009
1009
|
},
|
|
1010
|
+
{
|
|
1011
|
+
zigbeeModel: ['lumi.motion.acn001'],
|
|
1012
|
+
model: 'RTCGQ15LM',
|
|
1013
|
+
vendor: 'Xiaomi',
|
|
1014
|
+
description: 'Aqara E1 human body movement and illuminance sensor',
|
|
1015
|
+
fromZigbee: [fz.aqara_occupancy_illuminance, fz.aqara_opple, fz.battery],
|
|
1016
|
+
toZigbee: [tz.aqara_detection_interval],
|
|
1017
|
+
exposes: [e.occupancy(), e.illuminance_lux().withProperty('illuminance'),
|
|
1018
|
+
e.illuminance().withUnit('lx').withDescription('Measured illuminance in lux'),
|
|
1019
|
+
exposes.numeric('detection_interval', ea.ALL).withValueMin(2).withValueMax(65535).withUnit('s')
|
|
1020
|
+
.withDescription('Time interval for detecting actions'),
|
|
1021
|
+
e.device_temperature(), e.battery(), e.battery_voltage(), e.power_outage_count(false)],
|
|
1022
|
+
meta: {battery: {voltageToPercentage: '3V_2850_3200'}},
|
|
1023
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1024
|
+
const endpoint = device.getEndpoint(1);
|
|
1025
|
+
await endpoint.read('genPowerCfg', ['batteryVoltage']);
|
|
1026
|
+
await endpoint.read('aqaraOpple', [0x0102], {manufacturerCode: 0x115f});
|
|
1027
|
+
},
|
|
1028
|
+
ota: ota.zigbeeOTA,
|
|
1029
|
+
},
|
|
1010
1030
|
{
|
|
1011
1031
|
zigbeeModel: ['lumi.motion.ac01'],
|
|
1012
1032
|
model: 'RTCZCGQ11LM',
|
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,
|
package/lib/utils.js
CHANGED
|
@@ -114,7 +114,10 @@ function addActionGroup(payload, msg, definition) {
|
|
|
114
114
|
|
|
115
115
|
function postfixWithEndpointName(value, msg, definition, meta) {
|
|
116
116
|
// Prevent breaking change https://github.com/Koenkk/zigbee2mqtt/issues/13451
|
|
117
|
-
if (!meta)
|
|
117
|
+
if (!meta) {
|
|
118
|
+
meta.logger.warn(`No meta passed to postfixWithEndpointName, update your external converter!`);
|
|
119
|
+
meta = {device: null};
|
|
120
|
+
}
|
|
118
121
|
if (definition.meta && definition.meta.multiEndpoint) {
|
|
119
122
|
const endpointName = definition.hasOwnProperty('endpoint') ?
|
|
120
123
|
getKey(definition.endpoint(meta.device), msg.endpoint.ID) : msg.endpoint.ID;
|
package/lib/xiaomi.js
CHANGED
|
@@ -219,7 +219,8 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
219
219
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
220
220
|
} else if (['WXKG14LM', 'WXKG16LM', 'WXKG17LM'].includes(model.model)) {
|
|
221
221
|
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
222
|
-
} else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM', 'ZNMS12LM', '
|
|
222
|
+
} else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM', 'ZNMS12LM', 'ZNCLBL01LM', 'RTCGQ12LM', 'RTCGQ13LM', 'RTCGQ14LM',
|
|
223
|
+
'RTCGQ15LM'].includes(model.model)) {
|
|
223
224
|
// We don't know what the value means for these devices.
|
|
224
225
|
// https://github.com/Koenkk/zigbee2mqtt/issues/11126
|
|
225
226
|
// https://github.com/Koenkk/zigbee2mqtt/issues/12279
|
|
@@ -268,7 +269,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
268
269
|
mapping = 'right';
|
|
269
270
|
}
|
|
270
271
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
271
|
-
} else if (['RTCGQ12LM', 'RTCGQ14LM'].includes(model.model)) {
|
|
272
|
+
} else if (['RTCGQ12LM', 'RTCGQ14LM', 'RTCGQ15LM'].includes(model.model)) {
|
|
272
273
|
// Sometimes RTCGQ14LM reports high illuminance values in the dark
|
|
273
274
|
// https://github.com/Koenkk/zigbee2mqtt/issues/12596
|
|
274
275
|
const illuminance = value > 65000 ? 0 : value;
|