zigbee-herdsman-converters 14.0.666 → 14.0.668
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 +16 -0
- package/converters/toZigbee.js +26 -15
- package/devices/awox.js +1 -1
- package/devices/eglo.js +7 -0
- package/devices/giex.js +8 -8
- package/devices/ikea.js +7 -0
- package/devices/innr.js +9 -0
- package/devices/leedarson.js +16 -0
- package/devices/legrand.js +22 -0
- package/devices/lonsonho.js +8 -6
- package/devices/namron.js +1 -1
- package/devices/owon.js +2 -2
- package/devices/paulmann.js +7 -0
- package/devices/saswell.js +1 -0
- package/devices/sinope.js +5 -4
- package/devices/sunricher.js +1 -1
- package/devices/tuya.js +125 -35
- package/devices/ubisys.js +6 -6
- package/devices/villeroy_boch.js +1 -1
- package/lib/extend.js +5 -3
- package/lib/reporting.js +1 -1
- package/lib/tuya.js +70 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ See [Zigbee2MQTT how to support new devices](https://www.zigbee2mqtt.io/advanced
|
|
|
9
9
|
## Submitting a pull request
|
|
10
10
|
If you'd like to submit a pull request, you should run the following commands to ensure your changes will pass the tests:
|
|
11
11
|
```sh
|
|
12
|
+
npm install
|
|
12
13
|
npm run lint
|
|
13
14
|
npm test
|
|
14
15
|
```
|
package/converters/fromZigbee.js
CHANGED
|
@@ -3476,6 +3476,22 @@ const converters = {
|
|
|
3476
3476
|
return result;
|
|
3477
3477
|
},
|
|
3478
3478
|
},
|
|
3479
|
+
sinope_thermostat: {
|
|
3480
|
+
cluster: 'hvacThermostat',
|
|
3481
|
+
type: ['readResponse'],
|
|
3482
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3483
|
+
const lookup = {0: 'unoccupied', 1: 'occupied'};
|
|
3484
|
+
const lookup1 = {0: 'on_demand', 1: 'sensing'};
|
|
3485
|
+
const result = {};
|
|
3486
|
+
if (msg.data.hasOwnProperty('1024')) {
|
|
3487
|
+
result.thermostat_occupancy = lookup[msg.data['1024']];
|
|
3488
|
+
}
|
|
3489
|
+
if (msg.data.hasOwnProperty('1026')) {
|
|
3490
|
+
result.backlight_auto_dim = lookup1[msg.data['1026']];
|
|
3491
|
+
}
|
|
3492
|
+
return result;
|
|
3493
|
+
},
|
|
3494
|
+
},
|
|
3479
3495
|
danfoss_thermostat: {
|
|
3480
3496
|
cluster: 'hvacThermostat',
|
|
3481
3497
|
type: ['attributeReport', 'readResponse'],
|
package/converters/toZigbee.js
CHANGED
|
@@ -884,17 +884,28 @@ const converters = {
|
|
|
884
884
|
// TODO: same problem as above.
|
|
885
885
|
// TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
|
|
886
886
|
if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
887
|
+
const levelConfig = utils.getObjectProperty(meta.state, 'level_config', {});
|
|
888
|
+
let onLevel = utils.getObjectProperty(levelConfig, 'on_level', 0);
|
|
889
|
+
if (onLevel === 0 && entity.meta.onLevelSupported !== false) {
|
|
890
|
+
try {
|
|
891
|
+
const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
|
|
892
|
+
if (attributeRead !== undefined) {
|
|
893
|
+
onLevel = attributeRead['onLevel'];
|
|
894
|
+
}
|
|
895
|
+
} catch (e) {
|
|
896
|
+
// OnLevel not supported
|
|
895
897
|
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
+
}
|
|
899
|
+
if (onLevel === 0) {
|
|
900
|
+
onLevel = 'previous';
|
|
901
|
+
entity.meta.onLevelSupported = false;
|
|
902
|
+
entity.save();
|
|
903
|
+
}
|
|
904
|
+
if (onLevel === 255 || onLevel === 'previous') {
|
|
905
|
+
const current = utils.getObjectProperty(meta.state, 'brightness', 254);
|
|
906
|
+
brightness = globalStore.getValue(entity, 'brightness', current);
|
|
907
|
+
} else {
|
|
908
|
+
brightness = onLevel;
|
|
898
909
|
}
|
|
899
910
|
// Published state might have gotten clobbered by reporting.
|
|
900
911
|
publishBrightness = true;
|
|
@@ -1308,7 +1319,7 @@ const converters = {
|
|
|
1308
1319
|
thermostat_occupancy: {
|
|
1309
1320
|
key: ['occupancy'],
|
|
1310
1321
|
convertGet: async (entity, key, meta) => {
|
|
1311
|
-
await entity.read('hvacThermostat', ['
|
|
1322
|
+
await entity.read('hvacThermostat', ['occupancy']);
|
|
1312
1323
|
},
|
|
1313
1324
|
},
|
|
1314
1325
|
thermostat_clear_weekly_schedule: {
|
|
@@ -1394,6 +1405,7 @@ const converters = {
|
|
|
1394
1405
|
}
|
|
1395
1406
|
const unoccupiedCoolingSetpoint = result;
|
|
1396
1407
|
await entity.write('hvacThermostat', {unoccupiedCoolingSetpoint});
|
|
1408
|
+
return {state: {unoccupied_heating_setpoint: value}};
|
|
1397
1409
|
},
|
|
1398
1410
|
convertGet: async (entity, key, meta) => {
|
|
1399
1411
|
await entity.read('hvacThermostat', ['unoccupiedCoolingSetpoint']);
|
|
@@ -4286,17 +4298,16 @@ const converters = {
|
|
|
4286
4298
|
const sinopeOccupancy = {0: 'unoccupied', 1: 'occupied'};
|
|
4287
4299
|
const SinopeOccupancy = utils.getKey(sinopeOccupancy, value, value, Number);
|
|
4288
4300
|
await entity.write('hvacThermostat', {SinopeOccupancy});
|
|
4301
|
+
return {state: {'thermostat_occupancy': value}};
|
|
4289
4302
|
},
|
|
4290
4303
|
},
|
|
4291
4304
|
sinope_thermostat_backlight_autodim_param: {
|
|
4292
4305
|
key: ['backlight_auto_dim'],
|
|
4293
4306
|
convertSet: async (entity, key, value, meta) => {
|
|
4294
|
-
const sinopeBacklightParam = {
|
|
4295
|
-
0: 'on demand',
|
|
4296
|
-
1: 'sensing',
|
|
4297
|
-
};
|
|
4307
|
+
const sinopeBacklightParam = {0: 'on_demand', 1: 'sensing'};
|
|
4298
4308
|
const SinopeBacklight = utils.getKey(sinopeBacklightParam, value, value, Number);
|
|
4299
4309
|
await entity.write('hvacThermostat', {SinopeBacklight});
|
|
4310
|
+
return {state: {'backlight_auto_dim': value}};
|
|
4300
4311
|
},
|
|
4301
4312
|
},
|
|
4302
4313
|
sinope_thermostat_enable_outdoor_temperature: {
|
package/devices/awox.js
CHANGED
package/devices/eglo.js
CHANGED
|
@@ -8,4 +8,11 @@ module.exports = [
|
|
|
8
8
|
description: 'ROVITO-Z ceiling light',
|
|
9
9
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
|
|
10
10
|
},
|
|
11
|
+
{
|
|
12
|
+
zigbeeModel: ['ESMLFzm_w6_TW'],
|
|
13
|
+
model: '12242',
|
|
14
|
+
vendor: 'EGLO',
|
|
15
|
+
description: 'ST64 adjustable white filament bulb',
|
|
16
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
17
|
+
},
|
|
11
18
|
];
|
package/devices/giex.js
CHANGED
|
@@ -118,18 +118,18 @@ module.exports = [
|
|
|
118
118
|
e.battery(),
|
|
119
119
|
exposes.binary('state', ea.STATE_SET, 'ON', 'OFF').withDescription('State'),
|
|
120
120
|
exposes.enum('mode', ea.STATE_SET, ['duration', 'capacity']).withDescription('Irrigation mode'),
|
|
121
|
-
exposes.numeric('irrigation_target', exposes.access.STATE_SET).withValueMin(0).withValueMax(
|
|
122
|
-
.withDescription('Irrigation
|
|
123
|
-
exposes.numeric('cycle_irrigation_num_times', exposes.access.STATE_SET).withValueMin(0).withValueMax(100)
|
|
121
|
+
exposes.numeric('irrigation_target', exposes.access.STATE_SET).withValueMin(0).withValueMax(3600).withUnit('seconds or litres')
|
|
122
|
+
.withDescription('Irrigation target, duration in seconds or capacity in litres (depending on mode)'),
|
|
123
|
+
exposes.numeric('cycle_irrigation_num_times', exposes.access.STATE_SET).withValueMin(0).withValueMax(100)
|
|
124
124
|
.withDescription('Number of cycle irrigation times, set to 0 for single cycle'),
|
|
125
|
-
exposes.numeric('cycle_irrigation_interval', exposes.access.STATE_SET).withValueMin(0).withValueMax(
|
|
125
|
+
exposes.numeric('cycle_irrigation_interval', exposes.access.STATE_SET).withValueMin(0).withValueMax(3600).withUnit('sec')
|
|
126
126
|
.withDescription('Cycle irrigation interval'),
|
|
127
|
-
exposes.numeric('irrigation_start_time', ea.STATE).
|
|
128
|
-
exposes.numeric('irrigation_end_time', ea.STATE).
|
|
129
|
-
exposes.numeric('last_irrigation_duration', exposes.access.STATE)
|
|
127
|
+
exposes.numeric('irrigation_start_time', ea.STATE).withDescription('Last irrigation start time (GMT)'),
|
|
128
|
+
exposes.numeric('irrigation_end_time', ea.STATE).withDescription('Last irrigation end time (GMT)'),
|
|
129
|
+
exposes.numeric('last_irrigation_duration', exposes.access.STATE)
|
|
130
130
|
.withDescription('Last irrigation duration'),
|
|
131
131
|
exposes.numeric('water_consumed', exposes.access.STATE).withUnit('L')
|
|
132
|
-
.withDescription('
|
|
132
|
+
.withDescription('Last irrigation water consumption'),
|
|
133
133
|
],
|
|
134
134
|
},
|
|
135
135
|
];
|
package/devices/ikea.js
CHANGED
|
@@ -999,4 +999,11 @@ module.exports = [
|
|
|
999
999
|
description: 'STOFTMOLN ceiling/wall lamp 24 warm light dimmable',
|
|
1000
1000
|
extend: tradfriExtend.light_onoff_brightness(),
|
|
1001
1001
|
},
|
|
1002
|
+
{
|
|
1003
|
+
zigbeeModel: ['TRADFRIbulbPAR38WS900lm'],
|
|
1004
|
+
model: 'LED2006R9',
|
|
1005
|
+
vendor: 'IKEA',
|
|
1006
|
+
description: 'TRADFRI E26 PAR38 LED bulb 900 lumen, dimmable, white spectrum, downlight',
|
|
1007
|
+
extend: tradfriExtend.light_onoff_brightness_colortemp(),
|
|
1008
|
+
},
|
|
1002
1009
|
];
|
package/devices/innr.js
CHANGED
|
@@ -176,6 +176,14 @@ module.exports = [
|
|
|
176
176
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 555], supportsHS: true}),
|
|
177
177
|
meta: {enhancedHue: false, applyRedFix: true, turnsOffAtBrightness1: true},
|
|
178
178
|
},
|
|
179
|
+
{
|
|
180
|
+
zigbeeModel: ['RB 286 C'],
|
|
181
|
+
model: 'RB 286 C',
|
|
182
|
+
vendor: 'Innr',
|
|
183
|
+
description: 'E27 bulb RGBW',
|
|
184
|
+
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 555], supportsHS: true}),
|
|
185
|
+
meta: {applyRedFix: true, turnsOffAtBrightness1: true},
|
|
186
|
+
},
|
|
179
187
|
{
|
|
180
188
|
zigbeeModel: ['BY 285 C'],
|
|
181
189
|
model: 'BY 285 C',
|
|
@@ -591,6 +599,7 @@ module.exports = [
|
|
|
591
599
|
await reporting.rmsVoltage(endpoint);
|
|
592
600
|
// Gives UNSUPPORTED_ATTRIBUTE on reporting.readMeteringMultiplierDivisor.
|
|
593
601
|
endpoint.saveClusterAttributeKeyValue('seMetering', {multiplier: 1, divisor: 100});
|
|
602
|
+
await reporting.currentSummDelivered(endpoint);
|
|
594
603
|
},
|
|
595
604
|
ota: ota.zigbeeOTA,
|
|
596
605
|
exposes: [e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.switch(), e.energy()],
|
package/devices/leedarson.js
CHANGED
|
@@ -111,4 +111,20 @@ module.exports = [
|
|
|
111
111
|
toZigbee: [],
|
|
112
112
|
exposes: [e.battery(), e.occupancy()],
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
zigbeeModel: ['LDHD2AZW'],
|
|
116
|
+
model: 'LDHD2AZW',
|
|
117
|
+
vendor: 'Leedarson',
|
|
118
|
+
description: 'Magnetic door & window contact sensor',
|
|
119
|
+
fromZigbee: [fz.ias_contact_alarm_1, fz.temperature, fz.battery],
|
|
120
|
+
toZigbee: [],
|
|
121
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
122
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
123
|
+
const endpoint = device.getEndpoint(1);
|
|
124
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
|
|
125
|
+
await reporting.temperature(endpoint);
|
|
126
|
+
await reporting.batteryVoltage(endpoint);
|
|
127
|
+
},
|
|
128
|
+
exposes: [e.contact(), e.battery_low(), e.tamper(), e.temperature(), e.battery()],
|
|
129
|
+
},
|
|
114
130
|
];
|
package/devices/legrand.js
CHANGED
|
@@ -16,6 +16,28 @@ const readInitialBatteryState = async (type, data, device) => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
module.exports = [
|
|
19
|
+
{
|
|
20
|
+
zigbeeModel: [' Dry contact\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
|
|
21
|
+
'\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
|
|
22
|
+
model: '412173',
|
|
23
|
+
description: 'DIN dry contactor module',
|
|
24
|
+
vendor: 'Legrand',
|
|
25
|
+
extend: extend.switch(),
|
|
26
|
+
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.legrand_cluster_fc01, fz.ignore_basic_report, fz.ignore_genOta],
|
|
27
|
+
toZigbee: [tz.legrand_deviceMode, tz.on_off, tz.legrand_identify, tz.electrical_measurement_power],
|
|
28
|
+
exposes: [exposes.switch().withState('state', true, 'On/off (works only if device is in "switch" mode)'),
|
|
29
|
+
e.power().withAccess(ea.STATE_GET), exposes.enum('device_mode', ea.ALL, ['switch', 'auto'])
|
|
30
|
+
.withDescription('switch: allow on/off, auto will use wired action via C1/C2 on contactor for example with HC/HP')],
|
|
31
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
32
|
+
const endpoint = device.getEndpoint(1);
|
|
33
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'haElectricalMeasurement']);
|
|
34
|
+
await reporting.onOff(endpoint);
|
|
35
|
+
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
36
|
+
await reporting.activePower(endpoint);
|
|
37
|
+
// Read configuration values that are not sent periodically as well as current power (activePower).
|
|
38
|
+
await endpoint.read('haElectricalMeasurement', ['activePower', 0xf000, 0xf001, 0xf002]);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
19
41
|
{
|
|
20
42
|
zigbeeModel: [' Contactor\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
|
|
21
43
|
'\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
|
package/devices/lonsonho.js
CHANGED
|
@@ -148,8 +148,10 @@ module.exports = [
|
|
|
148
148
|
model: 'QS-Zigbee-D02-TRIAC-LN',
|
|
149
149
|
vendor: 'Lonsonho',
|
|
150
150
|
description: '1 gang smart dimmer switch module with neutral',
|
|
151
|
-
fromZigbee: extend.light_onoff_brightness()
|
|
152
|
-
|
|
151
|
+
fromZigbee: extend.light_onoff_brightness({disableMoveStep: true, disableTransition: true})
|
|
152
|
+
.fromZigbee.concat([fz.tuya_min_brightness]),
|
|
153
|
+
toZigbee: extend.light_onoff_brightness({disableMoveStep: true, disableTransition: true})
|
|
154
|
+
.toZigbee.concat([tz.tuya_min_brightness]),
|
|
153
155
|
exposes: [e.light_brightness().withMinBrightness()],
|
|
154
156
|
},
|
|
155
157
|
{
|
|
@@ -268,10 +270,10 @@ module.exports = [
|
|
|
268
270
|
model: 'TS110E_2gang',
|
|
269
271
|
vendor: 'Lonsonho',
|
|
270
272
|
description: 'Zigbee smart dimmer module 2 gang with neutral',
|
|
271
|
-
fromZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true})
|
|
272
|
-
fz.tuya_switch_power_outage_memory, fzLocal.TS110E_switch_type]),
|
|
273
|
-
toZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true})
|
|
274
|
-
tz.tuya_switch_power_outage_memory, tzLocal.TS110E_switch_type]),
|
|
273
|
+
fromZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
274
|
+
.fromZigbee.concat([fz.tuya_switch_power_outage_memory, fzLocal.TS110E_switch_type]),
|
|
275
|
+
toZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
276
|
+
.toZigbee.concat([tz.tuya_switch_power_outage_memory, tzLocal.TS110E_switch_type]),
|
|
275
277
|
meta: {multiEndpoint: true},
|
|
276
278
|
exposes: [
|
|
277
279
|
e.light_brightness().withEndpoint('l1'),
|
package/devices/namron.js
CHANGED
|
@@ -461,7 +461,7 @@ module.exports = [
|
|
|
461
461
|
await reporting.thermostatKeypadLockMode(endpoint);
|
|
462
462
|
|
|
463
463
|
await endpoint.configureReporting('hvacThermostat', [{
|
|
464
|
-
attribute: '
|
|
464
|
+
attribute: 'occupancy',
|
|
465
465
|
minimumReportInterval: 0,
|
|
466
466
|
maximumReportInterval: constants.repInterval.HOUR,
|
|
467
467
|
reportableChange: null,
|
package/devices/owon.js
CHANGED
|
@@ -123,8 +123,8 @@ module.exports = [
|
|
|
123
123
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
124
124
|
const endpoint2 = device.getEndpoint(2);
|
|
125
125
|
const endpoint3 = device.getEndpoint(3);
|
|
126
|
-
await reporting.bind(endpoint2, coordinatorEndpoint, ['
|
|
127
|
-
await reporting.bind(endpoint3, coordinatorEndpoint, ['
|
|
126
|
+
await reporting.bind(endpoint2, coordinatorEndpoint, ['msIlluminanceMeasurement']);
|
|
127
|
+
await reporting.bind(endpoint3, coordinatorEndpoint, ['msTemperatureMeasurement', 'msRelativeHumidity']);
|
|
128
128
|
device.powerSource = 'Battery';
|
|
129
129
|
device.save();
|
|
130
130
|
},
|
package/devices/paulmann.js
CHANGED
|
@@ -113,6 +113,13 @@ module.exports = [
|
|
|
113
113
|
description: 'LED panels',
|
|
114
114
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 350]}),
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
zigbeeModel: ['500.44'],
|
|
118
|
+
model: '500.44',
|
|
119
|
+
vendor: 'Paulmann',
|
|
120
|
+
description: 'URail power supply',
|
|
121
|
+
extend: extend.light_onoff_brightness_color(),
|
|
122
|
+
},
|
|
116
123
|
{
|
|
117
124
|
zigbeeModel: ['500.45'],
|
|
118
125
|
model: '500.45',
|
package/devices/saswell.js
CHANGED
|
@@ -20,6 +20,7 @@ module.exports = [
|
|
|
20
20
|
{modelID: 'TS0601', manufacturerName: '_TZE200_9gvruqf5'},
|
|
21
21
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zr9c0day'},
|
|
22
22
|
{modelID: 'TS0601', manufacturerName: '_TZE200_0dvm9mva'},
|
|
23
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_h4cgnbzg'},
|
|
23
24
|
],
|
|
24
25
|
model: 'SEA801-Zigbee/SEA802-Zigbee',
|
|
25
26
|
vendor: 'Saswell',
|
package/devices/sinope.js
CHANGED
|
@@ -15,20 +15,20 @@ module.exports = [
|
|
|
15
15
|
description: 'Zigbee line volt thermostat',
|
|
16
16
|
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
17
17
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
18
|
-
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state],
|
|
18
|
+
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_thermostat],
|
|
19
19
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
20
20
|
tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
|
21
21
|
tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
|
|
22
22
|
tz.sinope_thermostat_enable_outdoor_temperature, tz.sinope_thermostat_outdoor_temperature, tz.sinope_time_format],
|
|
23
23
|
exposes: [e.local_temperature(), e.keypad_lockout(), e.power(), e.current(), e.voltage(), e.energy(),
|
|
24
24
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
25
|
-
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat']),
|
|
25
|
+
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand(),
|
|
26
|
+
exposes.enum('thermostat_occupancy', ea.SET, ['unoccupied', 'occupied']).withDescription('Occupancy state of the thermostat'),
|
|
26
27
|
exposes.enum('backlight_auto_dim', ea.SET, ['on demand', 'sensing']).withDescription('Control backlight dimming behavior')],
|
|
27
28
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
28
29
|
const endpoint = device.getEndpoint(1);
|
|
29
30
|
const binds = ['genBasic', 'genIdentify', 'genGroups', 'hvacThermostat', 'hvacUserInterfaceCfg', 'msTemperatureMeasurement',
|
|
30
31
|
'haElectricalMeasurement', 'seMetering', 'manuSpecificSinope'];
|
|
31
|
-
|
|
32
32
|
await reporting.bind(endpoint, coordinatorEndpoint, binds);
|
|
33
33
|
await reporting.thermostatTemperature(endpoint);
|
|
34
34
|
await reporting.thermostatPIHeatingDemand(endpoint);
|
|
@@ -72,7 +72,7 @@ module.exports = [
|
|
|
72
72
|
description: 'Zigbee line volt thermostat',
|
|
73
73
|
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
74
74
|
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
75
|
-
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state],
|
|
75
|
+
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_thermostat],
|
|
76
76
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
77
77
|
tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
|
78
78
|
tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
|
|
@@ -80,6 +80,7 @@ module.exports = [
|
|
|
80
80
|
exposes: [e.local_temperature(), e.keypad_lockout(), e.power(), e.current(), e.voltage(), e.energy(),
|
|
81
81
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
82
82
|
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand(),
|
|
83
|
+
exposes.enum('thermostat_occupancy', ea.SET, ['unoccupied', 'occupied']).withDescription('Occupancy state of the thermostat'),
|
|
83
84
|
exposes.enum('backlight_auto_dim', ea.SET, ['on demand', 'sensing']).withDescription('Control backlight dimming behavior')],
|
|
84
85
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
85
86
|
const endpoint = device.getEndpoint(1);
|
package/devices/sunricher.js
CHANGED
|
@@ -465,7 +465,7 @@ module.exports = [
|
|
|
465
465
|
await reporting.thermostatKeypadLockMode(endpoint);
|
|
466
466
|
|
|
467
467
|
await endpoint.configureReporting('hvacThermostat', [{
|
|
468
|
-
attribute: '
|
|
468
|
+
attribute: 'occupancy',
|
|
469
469
|
minimumReportInterval: 0,
|
|
470
470
|
maximumReportInterval: constants.repInterval.HOUR,
|
|
471
471
|
reportableChange: null,
|
package/devices/tuya.js
CHANGED
|
@@ -22,7 +22,7 @@ const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak',
|
|
|
22
22
|
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx',
|
|
23
23
|
'_TZ3000_ss98ec5d', '_TZ3000_gznh2xla', '_TZ3000_hdopuwv6', '_TZ3000_gvn91tmx', '_TZ3000_dksbtrzs', '_TZ3000_b28wrpvx',
|
|
24
24
|
'_TZ3000_aim0ztek', '_TZ3000_mlswgkc3', '_TZ3000_7dndcnnb', '_TZ3000_waho4jtj', '_TZ3000_nmsciidq', '_TZ3000_jtgxgmks',
|
|
25
|
-
'_TZ3000_rdfh8cfs', '_TZ3000_yujkchbz', '_TZ3000_fgwhjm9j'];
|
|
25
|
+
'_TZ3000_rdfh8cfs', '_TZ3000_yujkchbz', '_TZ3000_fgwhjm9j', '_TZ3000_qeuvnohg'];
|
|
26
26
|
|
|
27
27
|
const tzLocal = {
|
|
28
28
|
SA12IZL_silence_siren: {
|
|
@@ -1768,12 +1768,13 @@ module.exports = [
|
|
|
1768
1768
|
exposes: [e.battery(), e.water_leak()],
|
|
1769
1769
|
},
|
|
1770
1770
|
{
|
|
1771
|
-
fingerprint: tuya.fingerprint('TS0001', ['_TZ3000_xkap8wtb', '_TZ3000_qnejhcsu', '_TZ3000_x3ewpzyr']),
|
|
1771
|
+
fingerprint: tuya.fingerprint('TS0001', ['_TZ3000_xkap8wtb', '_TZ3000_qnejhcsu', '_TZ3000_x3ewpzyr', '_TZ3000_mkhkxx1p']),
|
|
1772
1772
|
model: 'TS0001_power',
|
|
1773
1773
|
description: 'Switch with power monitoring',
|
|
1774
1774
|
vendor: 'TuYa',
|
|
1775
|
-
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report,
|
|
1776
|
-
|
|
1775
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report,
|
|
1776
|
+
fz.tuya_switch_power_outage_memory, fz.tuya_switch_type],
|
|
1777
|
+
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.tuya_switch_type],
|
|
1777
1778
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1778
1779
|
await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
|
|
1779
1780
|
const endpoint = device.getEndpoint(1);
|
|
@@ -1786,7 +1787,7 @@ module.exports = [
|
|
|
1786
1787
|
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
1787
1788
|
device.save();
|
|
1788
1789
|
},
|
|
1789
|
-
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(),
|
|
1790
|
+
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(), e.switch_type_2(),
|
|
1790
1791
|
exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore']).withDescription('Recover state after power outage')],
|
|
1791
1792
|
},
|
|
1792
1793
|
{
|
|
@@ -2117,19 +2118,21 @@ module.exports = [
|
|
|
2117
2118
|
exposes: [
|
|
2118
2119
|
e.battery_low(), e.child_lock(), e.open_window(), e.open_window_temperature().withValueMin(5).withValueMax(30),
|
|
2119
2120
|
e.comfort_temperature().withValueMin(5).withValueMax(30), e.eco_temperature().withValueMin(5).withValueMax(30),
|
|
2120
|
-
exposes.
|
|
2121
|
-
|
|
2122
|
-
'
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
.
|
|
2121
|
+
tuya.exposes.errorStatus(), tuya.exposes.frostProtection('The device display "AF", press the pair button to cancel.'),
|
|
2122
|
+
exposes.climate()
|
|
2123
|
+
.withSystemMode(['off', 'heat'], ea.STATE_SET, 'When switched to the "off" mode, the device will display ' +
|
|
2124
|
+
'"HS" and the valve will be fully closed. Press the pair button to cancel or switch back to "heat" mode. Battery life' +
|
|
2125
|
+
' can be prolonged by switching the heating off. After switching to `heat` mode, `preset` will be reset to `auto` and' +
|
|
2126
|
+
' after changing `preset` to `manual` temperature setpoint will be 20 degrees.')
|
|
2127
|
+
.withPreset(['auto', 'manual', 'holiday'],
|
|
2128
|
+
'`auto` uses schedule properties, check them. `manual` allows you to control the device, `holiday` uses ' +
|
|
2129
|
+
'`holiday_start_stop` and `holiday_temperature` properties.')
|
|
2130
|
+
.withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
|
|
2131
|
+
.withLocalTemperature(ea.STATE)
|
|
2132
|
+
.withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET),
|
|
2127
2133
|
exposes.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('second').withDescription('Setting '+
|
|
2128
2134
|
'minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining '+
|
|
2129
2135
|
'time for the function will be counted down in seconds ( 465 to 0 ).').withValueMin(0).withValueMax(465),
|
|
2130
|
-
exposes.binary('frost_protection', ea.STATE_SET, 'ON', 'OFF').withDescription('When Anti-Freezing function'+
|
|
2131
|
-
' is activated, the temperature in the house is kept at 8 °C, the device display "AF".press the '+
|
|
2132
|
-
'pair button to cancel.'),
|
|
2133
2136
|
exposes.binary('heating_stop', ea.STATE_SET, 'ON', 'OFF').withDescription('Same as `system_mode`. Left for compatibility.'),
|
|
2134
2137
|
exposes.numeric('holiday_temperature', ea.STATE_SET).withUnit('°C').withDescription('Holiday temperature')
|
|
2135
2138
|
.withValueMin(5).withValueMax(30),
|
|
@@ -2153,17 +2156,10 @@ module.exports = [
|
|
|
2153
2156
|
'18:40/24 22:50/19.5`; `06:00/21.5 17:20/26 24:00/18`. The temperature will be set from the beginning/start of one ' +
|
|
2154
2157
|
'period and until the next period, e.g., `04:00/20 24:00/22` means that from 00:00 to 04:00 temperature will be 20 ' +
|
|
2155
2158
|
'degrees and from 04:00 to 00:00 temperature will be 22 degrees.'),
|
|
2156
|
-
exposes.
|
|
2157
|
-
exposes.text('schedule_tuesday', ea.STATE),
|
|
2158
|
-
exposes.text('schedule_wednesday', ea.STATE),
|
|
2159
|
-
exposes.text('schedule_thursday', ea.STATE),
|
|
2160
|
-
exposes.text('schedule_friday', ea.STATE),
|
|
2161
|
-
exposes.text('schedule_saturday', ea.STATE),
|
|
2162
|
-
exposes.text('schedule_sunday', ea.STATE),
|
|
2159
|
+
...tuya.exposes.scheduleAllDays(ea.STATE, 'HH:MM/C'),
|
|
2163
2160
|
exposes.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('Turn on this property to poll current data from the ' +
|
|
2164
2161
|
'device. It can be used to periodically fetch a new local temperature since the device doesn\'t update itself. ' +
|
|
2165
2162
|
'Setting this property doesn\'t turn on the display.'),
|
|
2166
|
-
exposes.numeric('error_status', ea.STATE).withDescription('Error status'),
|
|
2167
2163
|
],
|
|
2168
2164
|
meta: {
|
|
2169
2165
|
tuyaDatapoints: [
|
|
@@ -2184,20 +2180,67 @@ module.exports = [
|
|
|
2184
2180
|
[102, 'open_window_temperature', tuya.valueConverter.divideBy10],
|
|
2185
2181
|
[104, 'comfort_temperature', tuya.valueConverter.divideBy10],
|
|
2186
2182
|
[105, 'eco_temperature', tuya.valueConverter.divideBy10],
|
|
2187
|
-
[106, 'schedule', tuya.valueConverter.
|
|
2183
|
+
[106, 'schedule', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2188
2184
|
[107, null, tuya.valueConverter.TV02SystemMode],
|
|
2189
2185
|
[107, 'system_mode', tuya.valueConverterBasic.lookup({'heat': false, 'off': true})],
|
|
2190
2186
|
[107, 'heating_stop', tuya.valueConverter.onOff],
|
|
2191
2187
|
[115, 'online', tuya.valueConverter.onOffNotStrict],
|
|
2192
|
-
[108, 'schedule_monday', tuya.valueConverter.
|
|
2193
|
-
[112, 'schedule_tuesday', tuya.valueConverter.
|
|
2194
|
-
[109, 'schedule_wednesday', tuya.valueConverter.
|
|
2195
|
-
[113, 'schedule_thursday', tuya.valueConverter.
|
|
2196
|
-
[110, 'schedule_friday', tuya.valueConverter.
|
|
2197
|
-
[114, 'schedule_saturday', tuya.valueConverter.
|
|
2198
|
-
[111, 'schedule_sunday', tuya.valueConverter.
|
|
2188
|
+
[108, 'schedule_monday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2189
|
+
[112, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2190
|
+
[109, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2191
|
+
[113, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2192
|
+
[110, 'schedule_friday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2193
|
+
[114, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2194
|
+
[111, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDaySingleDP],
|
|
2195
|
+
],
|
|
2196
|
+
},
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
fingerprint: tuya.fingerprint('TS0601', [
|
|
2200
|
+
'_TZE200_0hg58wyk', /* model: 'S366', vendor: 'Cloud Even' */
|
|
2201
|
+
]),
|
|
2202
|
+
model: 'TS0601_thermostat_2',
|
|
2203
|
+
vendor: 'TuYa',
|
|
2204
|
+
description: 'Thermostat radiator valve',
|
|
2205
|
+
whiteLabel: [
|
|
2206
|
+
{vendor: 'S366', model: 'Cloud Even'},
|
|
2207
|
+
],
|
|
2208
|
+
fromZigbee: [tuya.fzDataPoints],
|
|
2209
|
+
toZigbee: [tuya.tzDataPoints],
|
|
2210
|
+
onEvent: tuya.onEventSetLocalTime,
|
|
2211
|
+
configure: tuya.configureMagicPacket,
|
|
2212
|
+
meta: {
|
|
2213
|
+
tuyaDatapoints: [
|
|
2214
|
+
[1, 'system_mode', tuya.valueConverterBasic.lookup({'heat': true, 'off': false})],
|
|
2215
|
+
[2, 'preset', tuya.valueConverterBasic.lookup({'manual': tuya.enum(0), 'holiday': tuya.enum(1), 'program': tuya.enum(2)})],
|
|
2216
|
+
[3, null, null], // TODO: Unknown DP
|
|
2217
|
+
[8, 'open_window', tuya.valueConverter.onOff],
|
|
2218
|
+
[10, 'frost_protection', tuya.valueConverter.onOff],
|
|
2219
|
+
[16, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
|
|
2220
|
+
[24, 'local_temperature', tuya.valueConverter.divideBy10],
|
|
2221
|
+
[27, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration],
|
|
2222
|
+
[35, 'battery_low', tuya.valueConverter.true0ElseFalse],
|
|
2223
|
+
[40, 'child_lock', tuya.valueConverter.lockUnlock],
|
|
2224
|
+
[45, 'error_status', tuya.valueConverter.raw],
|
|
2225
|
+
[101, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2226
|
+
[102, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2227
|
+
[103, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2228
|
+
[104, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2229
|
+
[105, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2230
|
+
[106, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2231
|
+
[107, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDP],
|
|
2199
2232
|
],
|
|
2200
2233
|
},
|
|
2234
|
+
exposes: [
|
|
2235
|
+
e.battery_low(), e.child_lock(), e.open_window(), tuya.exposes.frostProtection(), tuya.exposes.errorStatus(),
|
|
2236
|
+
exposes.climate()
|
|
2237
|
+
.withSystemMode(['off', 'heat'], ea.STATE_SET)
|
|
2238
|
+
.withPreset(['manual', 'holiday', 'program'])
|
|
2239
|
+
.withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
|
|
2240
|
+
.withLocalTemperature(ea.STATE)
|
|
2241
|
+
.withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET),
|
|
2242
|
+
...tuya.exposes.scheduleAllDays(ea.STATE_SET, 'HH:MM/C HH:MM/C HH:MM/C HH:MM/C'),
|
|
2243
|
+
],
|
|
2201
2244
|
},
|
|
2202
2245
|
{
|
|
2203
2246
|
fingerprint: [
|
|
@@ -2467,7 +2510,7 @@ module.exports = [
|
|
|
2467
2510
|
onEvent: tuya.onEventsetTime,
|
|
2468
2511
|
},
|
|
2469
2512
|
{
|
|
2470
|
-
fingerprint: tuya.fingerprint('TS0601', ['
|
|
2513
|
+
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_bkkmqmyo', '_TZE200_eaac7dkw']),
|
|
2471
2514
|
model: 'TS0601_din_1',
|
|
2472
2515
|
vendor: 'TuYa',
|
|
2473
2516
|
description: 'Zigbee DIN energy meter',
|
|
@@ -2479,7 +2522,7 @@ module.exports = [
|
|
|
2479
2522
|
meta: {
|
|
2480
2523
|
tuyaDatapoints: [
|
|
2481
2524
|
[1, 'energy', tuya.valueConverter.divideBy100],
|
|
2482
|
-
[6, null, tuya.valueConverter.
|
|
2525
|
+
[6, null, tuya.valueConverter.phaseVariant1], // voltage and current
|
|
2483
2526
|
[16, 'state', tuya.valueConverter.onOff],
|
|
2484
2527
|
[102, 'produced_energy', tuya.valueConverter.divideBy100],
|
|
2485
2528
|
[103, 'power', tuya.valueConverter.raw],
|
|
@@ -2496,6 +2539,54 @@ module.exports = [
|
|
|
2496
2539
|
},
|
|
2497
2540
|
whiteLabel: [{vendor: 'Hiking', model: 'DDS238-2'}, {vendor: 'TuYa', model: 'RC-MCB'}],
|
|
2498
2541
|
},
|
|
2542
|
+
{
|
|
2543
|
+
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_lsanae15']),
|
|
2544
|
+
model: 'TS0601_din_2',
|
|
2545
|
+
vendor: 'TuYa',
|
|
2546
|
+
description: 'Zigbee DIN energy meter',
|
|
2547
|
+
fromZigbee: [tuya.fzDataPoints],
|
|
2548
|
+
toZigbee: [tuya.tzDataPoints],
|
|
2549
|
+
configure: tuya.configureMagicPacket,
|
|
2550
|
+
whiteLabel: [{vendor: 'XOCA', model: 'DAC2161C'}],
|
|
2551
|
+
exposes: [tuya.exposes.switch(), e.energy(), e.power(), e.voltage(), e.current(),
|
|
2552
|
+
exposes.enum('fault', ea.STATE, ['clear', 'over_current_threshold', 'over_power_threshold',
|
|
2553
|
+
'over_voltage threshold', 'wrong_frequency_threshold']).withDescription('Fault status of the device (clear = nothing)'),
|
|
2554
|
+
exposes.enum('threshold_1', ea.STATE, ['not_set', 'over_current_threshold', 'over_voltage_threshold'])
|
|
2555
|
+
.withDescription('State of threshold_1'),
|
|
2556
|
+
exposes.binary('threshold_1_protection', ea.STATE, 'ON', 'OFF')
|
|
2557
|
+
.withDescription('OFF - alarm only, ON - relay will be off when threshold reached'),
|
|
2558
|
+
exposes.numeric('threshold_1_value', ea.STATE)
|
|
2559
|
+
.withDescription('Can be in Volt or Ampere depending on threshold setting. Setup the value on the device'),
|
|
2560
|
+
exposes.enum('threshold_2', ea.STATE, ['not_set', 'over_current_threshold', 'over_voltage_threshold'])
|
|
2561
|
+
.withDescription('State of threshold_2'),
|
|
2562
|
+
exposes.binary('threshold_2_protection', ea.STATE, 'ON', 'OFF')
|
|
2563
|
+
.withDescription('OFF - alarm only, ON - relay will be off when threshold reached'),
|
|
2564
|
+
exposes.numeric('threshold_2_value', ea.STATE)
|
|
2565
|
+
.withDescription('Setup value on the device'),
|
|
2566
|
+
exposes.binary('clear_fault', ea.STATE_SET, 'ON', 'OFF')
|
|
2567
|
+
.withDescription('Turn ON to clear last the fault'),
|
|
2568
|
+
exposes.text('meter_id', ea.STATE).withDescription('Meter ID (ID of device)'),
|
|
2569
|
+
],
|
|
2570
|
+
meta: {
|
|
2571
|
+
tuyaDatapoints: [
|
|
2572
|
+
[1, 'energy', tuya.valueConverter.divideBy100],
|
|
2573
|
+
[3, null, null], // Monthly, but sends data only after request
|
|
2574
|
+
[4, null, null], // Dayly, but sends data only after request
|
|
2575
|
+
[6, null, tuya.valueConverter.phaseVariant2], // voltage and current
|
|
2576
|
+
[10, 'fault', tuya.valueConverterBasic.lookup({'clear': 0, 'over_current_threshold': 1,
|
|
2577
|
+
'over_power_threshold': 2, 'over_voltage_threshold': 4, 'wrong_frequency_threshold': 8})],
|
|
2578
|
+
[11, null, null], // Frozen - strange function, in native app - nothing is clear
|
|
2579
|
+
[16, 'state', tuya.valueConverter.onOff],
|
|
2580
|
+
[17, null, tuya.valueConverter.threshold], // It's settable, but can't write converter
|
|
2581
|
+
[18, 'meter_id', tuya.valueConverter.raw],
|
|
2582
|
+
[20, 'clear_fault', tuya.valueConverter.onOff], // Clear fault
|
|
2583
|
+
[21, null, null], // Forward Energy T1 - don't know what this
|
|
2584
|
+
[22, null, null], // Forward Energy T2 - don't know what this
|
|
2585
|
+
[23, null, null], // Forward Energy T3 - don't know what this
|
|
2586
|
+
[24, null, null], // Forward Energy T4 - don't know what this
|
|
2587
|
+
],
|
|
2588
|
+
},
|
|
2589
|
+
},
|
|
2499
2590
|
{
|
|
2500
2591
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_byzdayie'},
|
|
2501
2592
|
{modelID: 'TS0601', manufacturerName: '_TZE200_fsb6zw01'},
|
|
@@ -3015,8 +3106,7 @@ module.exports = [
|
|
|
3015
3106
|
},
|
|
3016
3107
|
{
|
|
3017
3108
|
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_8bxrzyxz'},
|
|
3018
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_ky0fq4ho'},
|
|
3019
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_qeuvnohg'}],
|
|
3109
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_ky0fq4ho'}],
|
|
3020
3110
|
model: 'TS011F_din_smart_relay',
|
|
3021
3111
|
description: 'Din smart relay (with power monitoring)',
|
|
3022
3112
|
vendor: 'TuYa',
|
package/devices/ubisys.js
CHANGED
|
@@ -80,10 +80,10 @@ const ubisys = {
|
|
|
80
80
|
type: ['attributeReport', 'readResponse'],
|
|
81
81
|
convert: (model, msg, publish, options, meta) => {
|
|
82
82
|
const result = {};
|
|
83
|
-
if (msg.data
|
|
84
|
-
result['input_configurations'] = msg.data['
|
|
83
|
+
if (msg.data['inputConfigurations'] != null) {
|
|
84
|
+
result['input_configurations'] = msg.data['inputConfigurations'];
|
|
85
85
|
}
|
|
86
|
-
if (msg.data
|
|
86
|
+
if (msg.data['inputActions'] != null) {
|
|
87
87
|
result['input_actions'] = msg.data['inputActions'].map(function(el) {
|
|
88
88
|
return Object.values(el);
|
|
89
89
|
});
|
|
@@ -95,8 +95,8 @@ const ubisys = {
|
|
|
95
95
|
cluster: 'hvacThermostat',
|
|
96
96
|
type: ['attributeReport', 'readResponse'],
|
|
97
97
|
convert: (model, msg, publish, options, meta) => {
|
|
98
|
-
if (msg.data.hasOwnProperty('
|
|
99
|
-
return {vacation_mode: msg.data.
|
|
98
|
+
if (msg.data.hasOwnProperty('occupancy')) {
|
|
99
|
+
return {vacation_mode: msg.data.occupancy === 0};
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
102
|
},
|
|
@@ -516,7 +516,7 @@ const ubisys = {
|
|
|
516
516
|
thermostat_vacation_mode: {
|
|
517
517
|
key: ['vacation_mode'],
|
|
518
518
|
convertGet: async (entity, key, meta) => {
|
|
519
|
-
await entity.read('hvacThermostat', ['
|
|
519
|
+
await entity.read('hvacThermostat', ['occupancy']);
|
|
520
520
|
},
|
|
521
521
|
},
|
|
522
522
|
},
|
package/devices/villeroy_boch.js
CHANGED
package/lib/extend.js
CHANGED
|
@@ -12,11 +12,13 @@ const extend = {
|
|
|
12
12
|
return {exposes, fromZigbee, toZigbee};
|
|
13
13
|
},
|
|
14
14
|
light_onoff_brightness: (options={}) => {
|
|
15
|
-
options = {disableEffect: false, disablePowerOnBehavior: false, ...options};
|
|
15
|
+
options = {disableEffect: false, disablePowerOnBehavior: false, disableMoveStep: false, disableTransition: false, ...options};
|
|
16
16
|
const exposes = [e.light_brightness(), ...(!options.disableEffect ? [e.effect()] : [])];
|
|
17
17
|
const fromZigbee = [fz.on_off, fz.brightness, fz.level_config, fz.ignore_basic_report];
|
|
18
|
-
const toZigbee = [tz.light_onoff_brightness, tz.
|
|
19
|
-
|
|
18
|
+
const toZigbee = [tz.light_onoff_brightness, tz.ignore_rate, tz.level_config,
|
|
19
|
+
...(!options.disableTransition ? [tz.ignore_transition] : []),
|
|
20
|
+
...(!options.disableEffect ? [tz.effect] : []),
|
|
21
|
+
...(!options.disableMoveStep ? [tz.light_brightness_move, tz.light_brightness_step] : [])];
|
|
20
22
|
|
|
21
23
|
if (!options.disablePowerOnBehavior) {
|
|
22
24
|
exposes.push(e.power_on_behavior(['off', 'on', 'toggle', 'previous']));
|
package/lib/reporting.js
CHANGED
|
@@ -179,7 +179,7 @@ module.exports = {
|
|
|
179
179
|
await endpoint.configureReporting('hvacThermostat', p);
|
|
180
180
|
},
|
|
181
181
|
thermostatOcupancy: async (endpoint, overrides) => {
|
|
182
|
-
const p = payload('
|
|
182
|
+
const p = payload('occupancy', 0, repInterval.HOUR, 0, overrides);
|
|
183
183
|
await endpoint.configureReporting('hvacThermostat', p);
|
|
184
184
|
},
|
|
185
185
|
thermostatTemperatureSetpointHold: async (endpoint, overrides) => {
|
package/lib/tuya.js
CHANGED
|
@@ -1165,6 +1165,11 @@ const tuyaExposes = {
|
|
|
1165
1165
|
.withDescription('Result of the self-test'),
|
|
1166
1166
|
faultAlarm: () => exposes.binary('fault_alarm', ea.STATE, true, false).withDescription('Indicates whether a fault was detected'),
|
|
1167
1167
|
silence: () => exposes.binary('silence', ea.STATE_SET, true, false).withDescription('Silence the alarm'),
|
|
1168
|
+
frostProtection: (extraNote='') => exposes.binary('frost_protection', ea.STATE_SET, 'ON', 'OFF').withDescription(
|
|
1169
|
+
`When Anti-Freezing function is activated, the temperature in the house is kept at 8 °C.${extraNote}`),
|
|
1170
|
+
errorStatus: () => exposes.numeric('error_status', ea.STATE).withDescription('Error status'),
|
|
1171
|
+
scheduleAllDays: (access, format) => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
|
|
1172
|
+
.map((day) => exposes.text(`schedule_${day}`, access).withDescription(`Schedule for ${day}, format: "${format}"`)),
|
|
1168
1173
|
};
|
|
1169
1174
|
|
|
1170
1175
|
const skip = {
|
|
@@ -1252,12 +1257,33 @@ const valueConverter = {
|
|
|
1252
1257
|
divideBy100: valueConverterBasic.divideBy(100),
|
|
1253
1258
|
divideBy10: valueConverterBasic.divideBy(10),
|
|
1254
1259
|
raw: valueConverterBasic.raw(),
|
|
1255
|
-
|
|
1260
|
+
phaseVariant1: {
|
|
1256
1261
|
from: (v) => {
|
|
1257
1262
|
const buffer = Buffer.from(v, 'base64');
|
|
1258
1263
|
return {voltage: (buffer[14] | buffer[13] << 8) / 10, current: (buffer[12] | buffer[11] << 8) / 1000};
|
|
1259
1264
|
},
|
|
1260
1265
|
},
|
|
1266
|
+
phaseVariant2: {
|
|
1267
|
+
from: (v) => {
|
|
1268
|
+
const buf = Buffer.from(v, 'base64');
|
|
1269
|
+
return {voltage: (buf[1] | buf[0] << 8) / 10, current: (buf[4] | buf[3] << 8) / 1000, power: (buf[7] | buf[6] << 8)};
|
|
1270
|
+
},
|
|
1271
|
+
},
|
|
1272
|
+
threshold: {
|
|
1273
|
+
from: (v) => {
|
|
1274
|
+
const buffer = Buffer.from(v, 'base64');
|
|
1275
|
+
const stateLookup = {0: 'not_set', 1: 'over_current_threshold', 3: 'over_voltage_threshold'};
|
|
1276
|
+
const protectionLookup = {0: 'OFF', 1: 'ON'};
|
|
1277
|
+
return {
|
|
1278
|
+
threshold_1_protection: protectionLookup[buffer[1]],
|
|
1279
|
+
threshold_1: stateLookup[buffer[0]],
|
|
1280
|
+
threshold_1_value: (buffer[3] | buffer[2] << 8),
|
|
1281
|
+
threshold_2_protection: protectionLookup[buffer[5]],
|
|
1282
|
+
threshold_2: stateLookup[buffer[4]],
|
|
1283
|
+
threshold_2_value: (buffer[7] | buffer[6] << 8),
|
|
1284
|
+
};
|
|
1285
|
+
},
|
|
1286
|
+
},
|
|
1261
1287
|
true0ElseFalse: {from: (v) => v === 0},
|
|
1262
1288
|
selfTestResult: valueConverterBasic.lookup({'checking': 0, 'success': 1, 'failure': 2, 'others': 3}),
|
|
1263
1289
|
lockUnlock: valueConverterBasic.lookup({'LOCK': true, 'UNLOCK': false}),
|
|
@@ -1291,7 +1317,7 @@ const valueConverter = {
|
|
|
1291
1317
|
return v.match(numberPattern).join([]).toString();
|
|
1292
1318
|
},
|
|
1293
1319
|
},
|
|
1294
|
-
|
|
1320
|
+
thermostatScheduleDaySingleDP: {
|
|
1295
1321
|
from: (v) => {
|
|
1296
1322
|
// day splitted to 10 min segments = total 144 segments
|
|
1297
1323
|
const maxPeriodsInDay = 10;
|
|
@@ -1381,6 +1407,46 @@ const valueConverter = {
|
|
|
1381
1407
|
return payload;
|
|
1382
1408
|
},
|
|
1383
1409
|
},
|
|
1410
|
+
thermostatScheduleDayMultiDP: {
|
|
1411
|
+
from: (v) => {
|
|
1412
|
+
const schedule = [];
|
|
1413
|
+
for (let index = 1; index < 17; index = index + 4) {
|
|
1414
|
+
schedule.push(
|
|
1415
|
+
String(parseInt(v[index+0])).padStart(2, '0') + ':' +
|
|
1416
|
+
String(parseInt(v[index+1])).padStart(2, '0') + '/' +
|
|
1417
|
+
(parseFloat((v[index+2] << 8) + v[index+3]) / 10.0).toFixed(1),
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
return schedule.join(' ');
|
|
1421
|
+
},
|
|
1422
|
+
to: (v) => {
|
|
1423
|
+
const payload = [0];
|
|
1424
|
+
const transitions = v.split(' ');
|
|
1425
|
+
if (transitions.length != 4) {
|
|
1426
|
+
throw new Error('Invalid schedule: there should be 4 transitions');
|
|
1427
|
+
}
|
|
1428
|
+
for (const transition of transitions) {
|
|
1429
|
+
const timeTemp = transition.split('/');
|
|
1430
|
+
if (timeTemp.length != 2) {
|
|
1431
|
+
throw new Error('Invalid schedule: wrong transition format: ' + transition);
|
|
1432
|
+
}
|
|
1433
|
+
const hourMin = timeTemp[0].split(':');
|
|
1434
|
+
const hour = hourMin[0];
|
|
1435
|
+
const min = hourMin[1];
|
|
1436
|
+
const temperature = Math.floor(timeTemp[1] *10);
|
|
1437
|
+
if (hour < 0 || hour > 24 || min < 0 || min > 60 || temperature < 50 || temperature > 300) {
|
|
1438
|
+
throw new Error('Invalid hour, minute or temperature of: ' + transition);
|
|
1439
|
+
}
|
|
1440
|
+
payload.push(
|
|
1441
|
+
hour,
|
|
1442
|
+
min,
|
|
1443
|
+
(temperature & 0xff00) >> 8,
|
|
1444
|
+
temperature & 0xff,
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
return payload;
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1384
1450
|
TV02SystemMode: {
|
|
1385
1451
|
from: (v) => {
|
|
1386
1452
|
return {system_mode: v === false ? 'heat' : 'off', heating_stop: v === false ? 'OFF' : 'ON'};
|
|
@@ -1395,7 +1461,8 @@ const tzDataPoints = {
|
|
|
1395
1461
|
'countdown', 'light_type', 'silence', 'self_test', 'child_lock', 'open_window', 'open_window_temperature', 'frost_protection',
|
|
1396
1462
|
'system_mode', 'heating_stop', 'current_heating_setpoint', 'local_temperature_calibration', 'preset', 'boost_timeset_countdown',
|
|
1397
1463
|
'holiday_start_stop', 'holiday_temperature', 'comfort_temperature', 'eco_temperature', 'working_day', 'week_schedule_programming',
|
|
1398
|
-
'online', 'holiday_mode_date', 'schedule',
|
|
1464
|
+
'online', 'holiday_mode_date', 'schedule', 'schedule_monday', 'schedule_tuesday', 'schedule_wednesday', 'schedule_thursday',
|
|
1465
|
+
'schedule_friday', 'schedule_saturday', 'schedule_sunday', 'clear_fault',
|
|
1399
1466
|
],
|
|
1400
1467
|
convertSet: async (entity, key, value, meta) => {
|
|
1401
1468
|
// A set converter is only called once; therefore we need to loop
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-herdsman-converters",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.668",
|
|
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.71"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"eslint": "*",
|