zigbee-herdsman-converters 14.0.588 → 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 +2 -0
- package/converters/fromZigbee.js +59 -20
- package/converters/toZigbee.js +126 -8
- package/devices/current_products_corp.js +1 -0
- package/devices/danfoss.js +2 -1
- package/devices/gledopto.js +7 -0
- package/devices/ikea.js +7 -0
- package/devices/makegood.js +51 -0
- package/devices/osram.js +2 -1
- package/devices/rtx.js +61 -9
- package/devices/sinope.js +8 -4
- package/devices/tuya.js +2 -1
- package/devices/ubisys.js +1 -0
- package/lib/legacy.js +1 -1
- package/lib/tuya.js +114 -0
- package/lib/utils.js +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,11 +23,13 @@ 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)
|
|
29
30
|
- `tuyaThermostatSystemMode`/`tuyaThermostatPreset`: TuYa specific thermostat options
|
|
30
31
|
- `thermostat`: see e.g. HT-08 definition
|
|
32
|
+
- `{dontMapPIHeatingDemand: true}`: do not map piHeatingDemand from 0-255 -> 0-100, see fromZigbee.thermostat (default: false)
|
|
31
33
|
- `battery`:
|
|
32
34
|
- `{dontDividePercentage: true}`: prevents batteryPercentageRemainig from being divided (ZCL 200=100%, but some report 100=100%) (default: false)
|
|
33
35
|
- `{voltageToPercentage: '3V_2100'}`: convert voltage to percentage using specified option. See utils.batteryVoltageToPercentage() (default: null, no voltage to percentage conversion)
|
package/converters/fromZigbee.js
CHANGED
|
@@ -37,6 +37,7 @@ const converters = {
|
|
|
37
37
|
type: ['attributeReport', 'readResponse'],
|
|
38
38
|
convert: (model, msg, publish, options, meta) => {
|
|
39
39
|
const result = {};
|
|
40
|
+
const dontMapPIHeatingDemand = model.meta && model.meta.thermostat && model.meta.thermostat.dontMapPIHeatingDemand;
|
|
40
41
|
if (msg.data.hasOwnProperty('localTemp')) {
|
|
41
42
|
result[postfixWithEndpointName('local_temperature', msg, model, meta)] = precisionRound(msg.data['localTemp'], 2) / 100;
|
|
42
43
|
}
|
|
@@ -110,7 +111,7 @@ const converters = {
|
|
|
110
111
|
}
|
|
111
112
|
if (msg.data.hasOwnProperty('pIHeatingDemand')) {
|
|
112
113
|
result[postfixWithEndpointName('pi_heating_demand', msg, model, meta)] =
|
|
113
|
-
mapNumberRange(msg.data['pIHeatingDemand'], 0, 255, 0, 100);
|
|
114
|
+
mapNumberRange(msg.data['pIHeatingDemand'], 0, (dontMapPIHeatingDemand ? 100: 255), 0, 100);
|
|
114
115
|
}
|
|
115
116
|
if (msg.data.hasOwnProperty('tempSetpointHold')) {
|
|
116
117
|
result[postfixWithEndpointName('temperature_setpoint_hold', msg, model, meta)] = msg.data['tempSetpointHold'] == 1;
|
|
@@ -1541,15 +1542,22 @@ const converters = {
|
|
|
1541
1542
|
// For zigbee-herdsman-converters: open = 100, close = 0
|
|
1542
1543
|
// ubisys J1 will report 255 if lift or tilt positions are not known, so skip that.
|
|
1543
1544
|
const invert = model.meta && model.meta.coverInverted ? !options.invert_cover : options.invert_cover;
|
|
1545
|
+
const coverStateFromTilt = model.meta && model.meta.coverStateFromTilt;
|
|
1544
1546
|
if (msg.data.hasOwnProperty('currentPositionLiftPercentage') && msg.data['currentPositionLiftPercentage'] <= 100) {
|
|
1545
1547
|
const value = msg.data['currentPositionLiftPercentage'];
|
|
1546
1548
|
result[postfixWithEndpointName('position', msg, model, meta)] = invert ? value : 100 - value;
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
+
if (!coverStateFromTilt) {
|
|
1550
|
+
result[postfixWithEndpointName('state', msg, model, meta)] =
|
|
1551
|
+
invert ? (value === 100 ? 'CLOSE' : 'OPEN') : (value === 0 ? 'CLOSE' : 'OPEN');
|
|
1552
|
+
}
|
|
1549
1553
|
}
|
|
1550
1554
|
if (msg.data.hasOwnProperty('currentPositionTiltPercentage') && msg.data['currentPositionTiltPercentage'] <= 100) {
|
|
1551
1555
|
const value = msg.data['currentPositionTiltPercentage'];
|
|
1552
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
|
+
}
|
|
1553
1561
|
}
|
|
1554
1562
|
return result;
|
|
1555
1563
|
},
|
|
@@ -2488,18 +2496,6 @@ const converters = {
|
|
|
2488
2496
|
}
|
|
2489
2497
|
},
|
|
2490
2498
|
},
|
|
2491
|
-
sinope_thermostat: {
|
|
2492
|
-
cluster: 'hvacThermostat',
|
|
2493
|
-
type: ['attributeReport', 'readResponse'],
|
|
2494
|
-
convert: (model, msg, publish, options, meta) => {
|
|
2495
|
-
const result = converters.thermostat.convert(model, msg, publish, options, meta);
|
|
2496
|
-
// Sinope seems to report pIHeatingDemand between 0 and 100 already
|
|
2497
|
-
if (msg.data.hasOwnProperty('pIHeatingDemand')) {
|
|
2498
|
-
result.pi_heating_demand = precisionRound(msg.data['pIHeatingDemand'], 0);
|
|
2499
|
-
}
|
|
2500
|
-
return result;
|
|
2501
|
-
},
|
|
2502
|
-
},
|
|
2503
2499
|
stelpro_thermostat: {
|
|
2504
2500
|
cluster: 'hvacThermostat',
|
|
2505
2501
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -3516,11 +3512,6 @@ const converters = {
|
|
|
3516
3512
|
type: ['attributeReport', 'readResponse'],
|
|
3517
3513
|
convert: (model, msg, publish, options, meta) => {
|
|
3518
3514
|
const result = {};
|
|
3519
|
-
// Danfoss sends pi_heating_demand as raw %
|
|
3520
|
-
if (typeof msg.data['pIHeatingDemand'] == 'number') {
|
|
3521
|
-
result[postfixWithEndpointName('pi_heating_demand', msg, model, meta)] =
|
|
3522
|
-
precisionRound(msg.data['pIHeatingDemand'], 0);
|
|
3523
|
-
}
|
|
3524
3515
|
if (msg.data.hasOwnProperty('danfossWindowOpenFeatureEnable')) {
|
|
3525
3516
|
result[postfixWithEndpointName('window_open_feature', msg, model, meta)] =
|
|
3526
3517
|
(msg.data['danfossWindowOpenFeatureEnable'] === 1);
|
|
@@ -6836,6 +6827,17 @@ const converters = {
|
|
|
6836
6827
|
case 7: {
|
|
6837
6828
|
return {battery: value};
|
|
6838
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
|
+
}
|
|
6839
6841
|
case 11: {
|
|
6840
6842
|
// value reported in seconds
|
|
6841
6843
|
return {timer_time_left: value / 60};
|
|
@@ -6849,6 +6851,43 @@ const converters = {
|
|
|
6849
6851
|
// value reported in seconds
|
|
6850
6852
|
return {last_valve_open_duration: value / 60};
|
|
6851
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
|
+
}
|
|
6852
6891
|
default: {
|
|
6853
6892
|
meta.logger.warn(`zigbee-herdsman-converters:RTXZVG1Valve: NOT RECOGNIZED DP ` +
|
|
6854
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/danfoss.js
CHANGED
|
@@ -16,6 +16,7 @@ module.exports = [
|
|
|
16
16
|
vendor: 'Danfoss',
|
|
17
17
|
description: 'Ally thermostat',
|
|
18
18
|
whiteLabel: [{vendor: 'Danfoss', model: '014G2463'}],
|
|
19
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
19
20
|
fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
|
|
20
21
|
toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
|
|
21
22
|
tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
|
|
@@ -213,7 +214,7 @@ module.exports = [
|
|
|
213
214
|
tz.danfoss_system_status_code,
|
|
214
215
|
tz.danfoss_multimaster_role,
|
|
215
216
|
],
|
|
216
|
-
meta: {multiEndpoint: true},
|
|
217
|
+
meta: {multiEndpoint: true, thermostat: {dontMapPIHeatingDemand: true}},
|
|
217
218
|
// ota: ota.zigbeeOTA,
|
|
218
219
|
endpoint: (device) => {
|
|
219
220
|
return {
|
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',
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const reporting = require('../lib/reporting');
|
|
5
|
+
const utils = require('../lib/utils');
|
|
6
|
+
const e = exposes.presets;
|
|
7
|
+
const ea = exposes.access;
|
|
8
|
+
|
|
9
|
+
const fzLocal = {
|
|
10
|
+
// MG-AUZG01 requires multiEndpoint only for on_off
|
|
11
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/13190
|
|
12
|
+
MGAUZG01_on_off: {
|
|
13
|
+
cluster: 'genOnOff',
|
|
14
|
+
type: ['attributeReport', 'readResponse'],
|
|
15
|
+
convert: (model, msg, publish, options, meta) => {
|
|
16
|
+
if (msg.data.hasOwnProperty('onOff')) {
|
|
17
|
+
const endpointName = utils.getKey(model.endpoint(meta.device), msg.endpoint.ID);
|
|
18
|
+
return {[`state_${endpointName}`]: msg.data['onOff'] === 1 ? 'ON' : 'OFF'};
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = [
|
|
25
|
+
{
|
|
26
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dd8wwzcy'}],
|
|
27
|
+
model: 'MG-AUZG01',
|
|
28
|
+
vendor: 'Makegood',
|
|
29
|
+
description: 'Double Zigbee power point',
|
|
30
|
+
fromZigbee: [fzLocal.MGAUZG01_on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
|
|
31
|
+
toZigbee: [tz.on_off],
|
|
32
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
|
|
33
|
+
e.energy()],
|
|
34
|
+
endpoint: (device) => {
|
|
35
|
+
return {'l1': 1, 'l2': 2};
|
|
36
|
+
},
|
|
37
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
38
|
+
const endpoint = device.getEndpoint(1);
|
|
39
|
+
await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
|
|
40
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
41
|
+
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
42
|
+
await reporting.rmsVoltage(endpoint, {change: 5});
|
|
43
|
+
await reporting.rmsCurrent(endpoint, {change: 50});
|
|
44
|
+
await reporting.activePower(endpoint, {change: 10});
|
|
45
|
+
await reporting.currentSummDelivered(endpoint);
|
|
46
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
|
|
47
|
+
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
48
|
+
device.save();
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
];
|
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/sinope.js
CHANGED
|
@@ -13,6 +13,7 @@ module.exports = [
|
|
|
13
13
|
model: 'TH1123ZB',
|
|
14
14
|
vendor: 'Sinopé',
|
|
15
15
|
description: 'Zigbee line volt thermostat',
|
|
16
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
16
17
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
17
18
|
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state],
|
|
18
19
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
@@ -20,8 +21,8 @@ module.exports = [
|
|
|
20
21
|
tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
|
|
21
22
|
tz.sinope_thermostat_enable_outdoor_temperature, tz.sinope_thermostat_outdoor_temperature, tz.sinope_time_format],
|
|
22
23
|
exposes: [e.local_temperature(), e.keypad_lockout(), e.power(), e.current(), e.voltage(), e.energy(),
|
|
23
|
-
exposes.climate().withSetpoint('occupied_heating_setpoint',
|
|
24
|
-
.withSystemMode(['off', '
|
|
24
|
+
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
25
|
+
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat']),
|
|
25
26
|
exposes.enum('backlight_auto_dim', ea.SET, ['on demand', 'sensing']).withDescription('Control backlight dimming behavior')],
|
|
26
27
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
27
28
|
const endpoint = device.getEndpoint(1);
|
|
@@ -69,6 +70,7 @@ module.exports = [
|
|
|
69
70
|
model: 'TH1124ZB',
|
|
70
71
|
vendor: 'Sinopé',
|
|
71
72
|
description: 'Zigbee line volt thermostat',
|
|
73
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
72
74
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
73
75
|
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state],
|
|
74
76
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
@@ -76,8 +78,8 @@ module.exports = [
|
|
|
76
78
|
tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
|
|
77
79
|
tz.sinope_thermostat_enable_outdoor_temperature, tz.sinope_thermostat_outdoor_temperature, tz.sinope_time_format],
|
|
78
80
|
exposes: [e.local_temperature(), e.keypad_lockout(), e.power(), e.current(), e.voltage(), e.energy(),
|
|
79
|
-
exposes.climate().withSetpoint('occupied_heating_setpoint',
|
|
80
|
-
.withSystemMode(['off', '
|
|
81
|
+
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
82
|
+
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand(),
|
|
81
83
|
exposes.enum('backlight_auto_dim', ea.SET, ['on demand', 'sensing']).withDescription('Control backlight dimming behavior')],
|
|
82
84
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
83
85
|
const endpoint = device.getEndpoint(1);
|
|
@@ -126,6 +128,7 @@ module.exports = [
|
|
|
126
128
|
model: 'TH1300ZB',
|
|
127
129
|
vendor: 'Sinopé',
|
|
128
130
|
description: 'Zigbee smart floor heating thermostat',
|
|
131
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
129
132
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement,
|
|
130
133
|
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_TH1300ZB_specific],
|
|
131
134
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
@@ -184,6 +187,7 @@ module.exports = [
|
|
|
184
187
|
model: 'TH1400ZB',
|
|
185
188
|
vendor: 'Sinopé',
|
|
186
189
|
description: 'Zigbee low volt thermostat',
|
|
190
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
187
191
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.sinope_thermostat_state],
|
|
188
192
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_temperature_display_mode,
|
|
189
193
|
tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
package/devices/tuya.js
CHANGED
|
@@ -19,7 +19,7 @@ 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', '
|
|
22
|
+
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx'];
|
|
23
23
|
|
|
24
24
|
const tzLocal = {
|
|
25
25
|
TS0504B_color: {
|
|
@@ -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/devices/ubisys.js
CHANGED
|
@@ -792,6 +792,7 @@ module.exports = [
|
|
|
792
792
|
model: 'H1',
|
|
793
793
|
vendor: 'Ubisys',
|
|
794
794
|
description: 'Heating regulator',
|
|
795
|
+
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
795
796
|
fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, ubisys.fz.thermostat_vacation_mode],
|
|
796
797
|
toZigbee: [
|
|
797
798
|
tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
package/lib/legacy.js
CHANGED
|
@@ -1726,7 +1726,7 @@ const fromZigbee = {
|
|
|
1726
1726
|
options: [exposes.options.legacy()],
|
|
1727
1727
|
convert: (model, msg, publish, options, meta) => {
|
|
1728
1728
|
if (!isLegacyEnabled(options)) {
|
|
1729
|
-
return fromZigbeeConverters.
|
|
1729
|
+
return fromZigbeeConverters.thermostat.convert(model, msg, publish, options, meta);
|
|
1730
1730
|
}
|
|
1731
1731
|
|
|
1732
1732
|
const result = fromZigbee.thermostat_att_report.convert(model, msg, publish, options, meta);
|
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
|
@@ -113,6 +113,8 @@ function addActionGroup(payload, msg, definition) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function postfixWithEndpointName(value, msg, definition, meta) {
|
|
116
|
+
// Prevent breaking change https://github.com/Koenkk/zigbee2mqtt/issues/13451
|
|
117
|
+
if (!meta) meta = {device: null};
|
|
116
118
|
if (definition.meta && definition.meta.multiEndpoint) {
|
|
117
119
|
const endpointName = definition.hasOwnProperty('endpoint') ?
|
|
118
120
|
getKey(definition.endpoint(meta.device), msg.endpoint.ID) : msg.endpoint.ID;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-herdsman-converters",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.591",
|
|
4
4
|
"description": "Collection of device converters to be used with zigbee-herdsman",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"buffer-crc32": "^0.2.13",
|
|
39
39
|
"https-proxy-agent": "^5.0.1",
|
|
40
40
|
"tar-stream": "^2.2.0",
|
|
41
|
-
"zigbee-herdsman": "^0.14.
|
|
41
|
+
"zigbee-herdsman": "^0.14.47"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"eslint": "*",
|