zigbee-herdsman-converters 14.0.316 → 14.0.320
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/converters/fromZigbee.js +89 -18
- package/converters/toZigbee.js +96 -3
- package/devices/bitron.js +1 -1
- package/devices/centralite.js +24 -2
- package/devices/ecozy.js +2 -1
- package/devices/elko.js +13 -2
- package/devices/eurotronic.js +2 -1
- package/devices/hgkg.js +1 -1
- package/devices/ikea.js +37 -5
- package/devices/innr.js +24 -0
- package/devices/jethome.js +48 -0
- package/devices/keen_home.js +1 -1
- package/devices/leedarson.js +39 -0
- package/devices/leviton.js +2 -1
- package/devices/moes.js +9 -9
- package/devices/philips.js +55 -1
- package/devices/saswell.js +2 -1
- package/devices/schneider_electric.js +1 -1
- package/devices/tuya.js +11 -8
- package/devices/xiaomi.js +1 -1
- package/devices/zen.js +1 -1
- package/lib/exposes.js +3 -2
- package/lib/utils.js +1 -1
- package/npm-shrinkwrap.json +167 -154
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -1574,6 +1574,10 @@ const converters = {
|
|
|
1574
1574
|
const result = {};
|
|
1575
1575
|
const data = msg.data;
|
|
1576
1576
|
|
|
1577
|
+
if (data.hasOwnProperty(0x0401)) { // Load
|
|
1578
|
+
result.load = data[0x0401];
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1577
1581
|
if (data.hasOwnProperty(0x0402)) { // Display text
|
|
1578
1582
|
result.display_text = data[0x0402];
|
|
1579
1583
|
}
|
|
@@ -3551,24 +3555,6 @@ const converters = {
|
|
|
3551
3555
|
return {child_lock: value ? 'LOCK' : 'UNLOCK'};
|
|
3552
3556
|
case tuya.dataPoints.moesSbattery:
|
|
3553
3557
|
return {battery: value};
|
|
3554
|
-
case tuya.dataPoints.moesSschedule:
|
|
3555
|
-
return {
|
|
3556
|
-
program_weekday:
|
|
3557
|
-
{weekday: ' ' + value[0] + 'h:' + value[1] + 'm ' + value[2]/2 + '°C' +
|
|
3558
|
-
', ' + value[3] + 'h:' + value[4] + 'm ' + value[5]/2 + '°C' +
|
|
3559
|
-
', ' + value[6] + 'h:' + value[7] + 'm ' + value[8]/2 + '°C' +
|
|
3560
|
-
', ' + value[9] + 'h:' + value[10] + 'm ' + value[11]/2 + '°C '},
|
|
3561
|
-
program_saturday:
|
|
3562
|
-
{saturday: '' + value[12] + 'h:' + value[13] + 'm ' + value[14]/2 + '°C' +
|
|
3563
|
-
', ' + value[15] + 'h:' + value[16] + 'm ' + value[17]/2 + '°C' +
|
|
3564
|
-
', ' + value[18] + 'h:' + value[19] + 'm ' + value[20]/2 + '°C' +
|
|
3565
|
-
', ' + value[21] + 'h:' + value[22] + 'm ' + value[23]/2 + '°C '},
|
|
3566
|
-
program_sunday:
|
|
3567
|
-
{sunday: ' ' + value[24] + 'h:' + value[25] + 'm ' + value[26]/2 + '°C' +
|
|
3568
|
-
', ' + value[27] + 'h:' + value[28] + 'm ' + value[29]/2 + '°C' +
|
|
3569
|
-
', ' + value[30] + 'h:' + value[31] + 'm ' + value[32]/2 + '°C' +
|
|
3570
|
-
', ' + value[33] + 'h:' + value[34] + 'm ' + value[35]/2 + '°C '},
|
|
3571
|
-
};
|
|
3572
3558
|
case tuya.dataPoints.moesSboostHeatingCountdownTimeSet:
|
|
3573
3559
|
return {boost_heating_countdown_time_set: (value)};
|
|
3574
3560
|
case tuya.dataPoints.moesSvalvePosition:
|
|
@@ -3583,6 +3569,18 @@ const converters = {
|
|
|
3583
3569
|
return {max_temperature: value};
|
|
3584
3570
|
case tuya.dataPoints.moesSminTempSet:
|
|
3585
3571
|
return {min_temperature: value};
|
|
3572
|
+
case tuya.dataPoints.moesSschedule: {
|
|
3573
|
+
const items = [];
|
|
3574
|
+
const pMode = [];
|
|
3575
|
+
for (let i = 0; i < 12; i++) {
|
|
3576
|
+
const item = {h: value[i*3], m: value[i*3+1], temp: value[i*3+2] / 2};
|
|
3577
|
+
items[i] = item;
|
|
3578
|
+
pMode[i] = item['h'].toString().padStart(2, '0') + ':' +
|
|
3579
|
+
item['m'].toString().padStart(2, '0') + '/' +
|
|
3580
|
+
item['temp'] + '°C';
|
|
3581
|
+
}
|
|
3582
|
+
return {programming_mode: pMode.join(' ')};
|
|
3583
|
+
}
|
|
3586
3584
|
default:
|
|
3587
3585
|
meta.logger.warn(`zigbee-herdsman-converters:moesS_thermostat: NOT RECOGNIZED DP #${
|
|
3588
3586
|
dp} with data ${JSON.stringify(msg.data)}`);
|
|
@@ -4295,6 +4293,79 @@ const converters = {
|
|
|
4295
4293
|
}
|
|
4296
4294
|
},
|
|
4297
4295
|
},
|
|
4296
|
+
ikea_air_purifier: {
|
|
4297
|
+
cluster: 'manuSpecificIkeaAirPurifier',
|
|
4298
|
+
type: ['attributeReport', 'readResponse'],
|
|
4299
|
+
options: [exposes.options.precision('pm25'), exposes.options.calibration('pm25')],
|
|
4300
|
+
convert: (model, msg, publish, options, meta) => {
|
|
4301
|
+
const state = {};
|
|
4302
|
+
|
|
4303
|
+
if (msg.data.hasOwnProperty('particulateMatter25Measurement')) {
|
|
4304
|
+
const pm25Property = postfixWithEndpointName('pm25', msg, model);
|
|
4305
|
+
let pm25 = parseFloat(msg.data['particulateMatter25Measurement']);
|
|
4306
|
+
|
|
4307
|
+
// Air Quality Scale (ikea app):
|
|
4308
|
+
// 0-35=Good, 35-80=OK, 80+=Not Good
|
|
4309
|
+
let airQuality;
|
|
4310
|
+
const airQualityProperty = postfixWithEndpointName('air_quality', msg, model);
|
|
4311
|
+
if (pm25 <= 35) {
|
|
4312
|
+
airQuality = 'good';
|
|
4313
|
+
} else if (pm25 <= 80) {
|
|
4314
|
+
airQuality = 'ok';
|
|
4315
|
+
} else if (pm25 < 65535) {
|
|
4316
|
+
airQuality = 'not_good';
|
|
4317
|
+
} else {
|
|
4318
|
+
airQuality = 'unknown';
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4321
|
+
// calibrate and round pm25 unless invalid
|
|
4322
|
+
pm25 = (pm25 == 65535) ? -1 : calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
4323
|
+
|
|
4324
|
+
state[pm25Property] = calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
4325
|
+
state[airQualityProperty] = airQuality;
|
|
4326
|
+
}
|
|
4327
|
+
|
|
4328
|
+
if (msg.data.hasOwnProperty('filterRunTime')) {
|
|
4329
|
+
// Filter needs to be replaced after 6 months
|
|
4330
|
+
state['replace_filter'] = (parseInt(msg.data['filterRunTime']) >= 259200);
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
if (msg.data.hasOwnProperty('controlPanelLight')) {
|
|
4334
|
+
state['led_enable'] = (msg.data['controlPanelLight'] == 0);
|
|
4335
|
+
}
|
|
4336
|
+
|
|
4337
|
+
if (msg.data.hasOwnProperty('childLock')) {
|
|
4338
|
+
state['child_lock'] = (msg.data['childLock'] > 0 ? 'LOCK' : 'UNLOCK');
|
|
4339
|
+
}
|
|
4340
|
+
|
|
4341
|
+
if (msg.data.hasOwnProperty('fanSpeed')) {
|
|
4342
|
+
let fanSpeed = msg.data['fanSpeed'];
|
|
4343
|
+
if (fanSpeed >= 10) {
|
|
4344
|
+
fanSpeed = (((fanSpeed - 5) * 2) / 10);
|
|
4345
|
+
} else {
|
|
4346
|
+
fanSpeed = 0;
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
state['fan_speed'] = fanSpeed;
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
if (msg.data.hasOwnProperty('fanMode')) {
|
|
4353
|
+
let fanMode = msg.data['fanMode'];
|
|
4354
|
+
if (fanMode >= 10) {
|
|
4355
|
+
fanMode = (((fanMode - 5) * 2) / 10).toString();
|
|
4356
|
+
} else if (fanMode == 1) {
|
|
4357
|
+
fanMode = 'auto';
|
|
4358
|
+
} else {
|
|
4359
|
+
fanMode = 'off';
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
state['fan_mode'] = fanMode;
|
|
4363
|
+
state['fan_state'] = (fanMode === 'off' ? 'OFF' : 'ON');
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
return state;
|
|
4367
|
+
},
|
|
4368
|
+
},
|
|
4298
4369
|
E1524_E1810_levelctrl: {
|
|
4299
4370
|
cluster: 'genLevelCtrl',
|
|
4300
4371
|
type: [
|
package/converters/toZigbee.js
CHANGED
|
@@ -17,6 +17,7 @@ const manufacturerOptions = {
|
|
|
17
17
|
danfoss: {manufacturerCode: herdsman.Zcl.ManufacturerCode.DANFOSS},
|
|
18
18
|
develco: {manufacturerCode: herdsman.Zcl.ManufacturerCode.DEVELCO},
|
|
19
19
|
hue: {manufacturerCode: herdsman.Zcl.ManufacturerCode.PHILIPS},
|
|
20
|
+
ikea: {manufacturerCode: herdsman.Zcl.ManufacturerCode.IKEA_OF_SWEDEN},
|
|
20
21
|
sinope: {manufacturerCode: herdsman.Zcl.ManufacturerCode.SINOPE_TECH},
|
|
21
22
|
/*
|
|
22
23
|
* Ubisys doesn't accept a manufacturerCode on some commands
|
|
@@ -329,7 +330,7 @@ const converters = {
|
|
|
329
330
|
|
|
330
331
|
let info;
|
|
331
332
|
// https://github.com/Koenkk/zigbee2mqtt/issues/8310 some devices require the info to be reversed.
|
|
332
|
-
if (['SIRZB-110', 'SRAC-23B-ZBSR', 'AV2010/29A'].includes(meta.mapped.model)) {
|
|
333
|
+
if (['SIRZB-110', 'SRAC-23B-ZBSR', 'AV2010/29A', 'AV2010/24A'].includes(meta.mapped.model)) {
|
|
333
334
|
info = (mode[values.mode]) + ((values.strobe ? 1 : 0) << 4) + (level[values.level] << 6);
|
|
334
335
|
} else {
|
|
335
336
|
info = (mode[values.mode] << 4) + ((values.strobe ? 1 : 0) << 2) + (level[values.level]);
|
|
@@ -1378,6 +1379,16 @@ const converters = {
|
|
|
1378
1379
|
// #endregion
|
|
1379
1380
|
|
|
1380
1381
|
// #region Non-generic converters
|
|
1382
|
+
elko_load: {
|
|
1383
|
+
key: ['load'],
|
|
1384
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1385
|
+
await entity.write('hvacThermostat', {'elkoLoad': value});
|
|
1386
|
+
return {state: {load: value}};
|
|
1387
|
+
},
|
|
1388
|
+
convertGet: async (entity, key, meta) => {
|
|
1389
|
+
await entity.read('hvacThermostat', ['elkoLoad']);
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1381
1392
|
elko_display_text: {
|
|
1382
1393
|
key: ['display_text'],
|
|
1383
1394
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -1911,6 +1922,71 @@ const converters = {
|
|
|
1911
1922
|
await entity.read('genBasic', [0x0033], manufacturerOptions.hue);
|
|
1912
1923
|
},
|
|
1913
1924
|
},
|
|
1925
|
+
ikea_air_purifier_fan_mode: {
|
|
1926
|
+
key: ['fan_mode', 'fan_state'],
|
|
1927
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1928
|
+
if (key == 'fan_state' && value.toLowerCase() == 'on') {
|
|
1929
|
+
value = utils.getMetaValue(entity, meta.mapped, 'fanStateOn', 'allEqual', 'on');
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
let fanMode;
|
|
1933
|
+
switch (value.toLowerCase()) {
|
|
1934
|
+
case 'off':
|
|
1935
|
+
fanMode = 0;
|
|
1936
|
+
break;
|
|
1937
|
+
case 'auto':
|
|
1938
|
+
fanMode = 1;
|
|
1939
|
+
break;
|
|
1940
|
+
default:
|
|
1941
|
+
fanMode = parseInt(((parseInt(value) / 2.0) * 10) + 5);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'fanMode': fanMode}, manufacturerOptions.ikea);
|
|
1945
|
+
return {state: {fan_mode: value.toLowerCase(), fan_state: value.toLowerCase() === 'off' ? 'OFF' : 'ON'}};
|
|
1946
|
+
},
|
|
1947
|
+
convertGet: async (entity, key, meta) => {
|
|
1948
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['fanMode']);
|
|
1949
|
+
},
|
|
1950
|
+
},
|
|
1951
|
+
ikea_air_purifier_fan_speed: {
|
|
1952
|
+
key: ['fan_speed'],
|
|
1953
|
+
convertGet: async (entity, key, meta) => {
|
|
1954
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['fanSpeed']);
|
|
1955
|
+
},
|
|
1956
|
+
},
|
|
1957
|
+
ikea_air_purifier_pm25: {
|
|
1958
|
+
key: ['pm25', 'air_quality'],
|
|
1959
|
+
convertGet: async (entity, key, meta) => {
|
|
1960
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['particulateMatter25Measurement']);
|
|
1961
|
+
},
|
|
1962
|
+
},
|
|
1963
|
+
ikea_air_purifier_replace_filter: {
|
|
1964
|
+
key: ['replace_filter'],
|
|
1965
|
+
convertGet: async (entity, key, meta) => {
|
|
1966
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['filterRunTime']);
|
|
1967
|
+
},
|
|
1968
|
+
},
|
|
1969
|
+
ikea_air_purifier_child_lock: {
|
|
1970
|
+
key: ['child_lock'],
|
|
1971
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1972
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'childLock': ((value.toLowerCase() === 'lock') ? 1 : 0)},
|
|
1973
|
+
manufacturerOptions.ikea);
|
|
1974
|
+
return {state: {child_lock: ((value.toLowerCase() === 'lock') ? 'LOCK' : 'UNLOCK')}};
|
|
1975
|
+
},
|
|
1976
|
+
convertGet: async (entity, key, meta) => {
|
|
1977
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['childLock']);
|
|
1978
|
+
},
|
|
1979
|
+
},
|
|
1980
|
+
ikea_air_purifier_led_enable: {
|
|
1981
|
+
key: ['led_enable'],
|
|
1982
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1983
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'controlPanelLight': ((value) ? 0 : 1)}, manufacturerOptions.ikea);
|
|
1984
|
+
return {state: {led_enable: ((value) ? true : false)}};
|
|
1985
|
+
},
|
|
1986
|
+
convertGet: async (entity, key, meta) => {
|
|
1987
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['controlPanelLight']);
|
|
1988
|
+
},
|
|
1989
|
+
},
|
|
1914
1990
|
RTCGQ13LM_motion_sensitivity: {
|
|
1915
1991
|
key: ['motion_sensitivity'],
|
|
1916
1992
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -2764,6 +2840,25 @@ const converters = {
|
|
|
2764
2840
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSminTempSet, temp);
|
|
2765
2841
|
},
|
|
2766
2842
|
},
|
|
2843
|
+
moesS_thermostat_schedule_programming: {
|
|
2844
|
+
key: ['programming_mode'],
|
|
2845
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2846
|
+
const payload = [];
|
|
2847
|
+
const items = value.split(' ');
|
|
2848
|
+
for (let i = 0; i < 12; i++) {
|
|
2849
|
+
const hourTemperature = items[i].split('/');
|
|
2850
|
+
const hourMinute = hourTemperature[0].split(':', 2);
|
|
2851
|
+
const h = parseInt(hourMinute[0]);
|
|
2852
|
+
const m = parseInt(hourMinute[1]);
|
|
2853
|
+
const temp = parseInt(hourTemperature[1]);
|
|
2854
|
+
if (h < 0 || h >= 24 || m < 0 || m >= 60 || temp < 5 || temp >= 35) {
|
|
2855
|
+
throw new Error('Invalid hour, minute or temperature of:' + items[i]);
|
|
2856
|
+
}
|
|
2857
|
+
payload[i*3] = h; payload[i*3+1] = m; payload[i*3+2] = temp * 2;
|
|
2858
|
+
}
|
|
2859
|
+
return tuya.sendDataPointRaw(entity, tuya.dataPoints.moesSschedule, payload);
|
|
2860
|
+
},
|
|
2861
|
+
},
|
|
2767
2862
|
tvtwo_thermostat: {
|
|
2768
2863
|
key: [
|
|
2769
2864
|
'window_detection', 'frost_protection', 'child_lock',
|
|
@@ -5293,8 +5388,6 @@ const converters = {
|
|
|
5293
5388
|
saswell_thermostat_calibration: {
|
|
5294
5389
|
key: ['local_temperature_calibration'],
|
|
5295
5390
|
convertSet: async (entity, key, value, meta) => {
|
|
5296
|
-
if (value > 6) value = 6;
|
|
5297
|
-
if (value < -6) value = -6;
|
|
5298
5391
|
if (value < 0) value = 0xFFFFFFFF + value + 1;
|
|
5299
5392
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.saswellTempCalibration, value);
|
|
5300
5393
|
},
|
package/devices/bitron.js
CHANGED
|
@@ -190,7 +190,7 @@ module.exports = [
|
|
|
190
190
|
tz.thermostat_running_state, tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode],
|
|
191
191
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 0.5).withLocalTemperature()
|
|
192
192
|
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat', 'cool'])
|
|
193
|
-
.withLocalTemperatureCalibration(), e.keypad_lockout()],
|
|
193
|
+
.withLocalTemperatureCalibration(-20, 20, 1), e.keypad_lockout()],
|
|
194
194
|
meta: {battery: {voltageToPercentage: '3V_2500_3200'}},
|
|
195
195
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
196
196
|
const endpoint = device.getEndpoint(1);
|
package/devices/centralite.js
CHANGED
|
@@ -26,6 +26,26 @@ module.exports = [
|
|
|
26
26
|
await reporting.activePower(endpoint);
|
|
27
27
|
},
|
|
28
28
|
},
|
|
29
|
+
{
|
|
30
|
+
zigbeeModel: ['4256050-ZHAC'],
|
|
31
|
+
model: '4256050-ZHAC',
|
|
32
|
+
vendor: 'Centralite',
|
|
33
|
+
description: '3-Series smart dimming outlet',
|
|
34
|
+
fromZigbee: [fz.restorable_brightness, fz.on_off, fz.electrical_measurement],
|
|
35
|
+
toZigbee: [tz.light_onoff_restorable_brightness],
|
|
36
|
+
exposes: [e.light_brightness(), e.power(), e.voltage(), e.current()],
|
|
37
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
38
|
+
const endpoint = device.getEndpoint(1);
|
|
39
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'haElectricalMeasurement']);
|
|
40
|
+
await reporting.onOff(endpoint);
|
|
41
|
+
// 4256050-ZHAC doesn't support reading 'acVoltageMultiplier' or 'acVoltageDivisor'
|
|
42
|
+
await endpoint.read('haElectricalMeasurement', ['acCurrentMultiplier', 'acCurrentDivisor']);
|
|
43
|
+
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
44
|
+
await reporting.rmsVoltage(endpoint, {change: 2}); // Voltage reports in V
|
|
45
|
+
await reporting.rmsCurrent(endpoint, {change: 10}); // Current reports in mA
|
|
46
|
+
await reporting.activePower(endpoint, {change: 2}); // Power reports in 0.1W
|
|
47
|
+
},
|
|
48
|
+
},
|
|
29
49
|
{
|
|
30
50
|
zigbeeModel: ['4257050-ZHAC'],
|
|
31
51
|
model: '4257050-ZHAC',
|
|
@@ -154,7 +174,8 @@ module.exports = [
|
|
|
154
174
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 1).withLocalTemperature()
|
|
155
175
|
.withSystemMode(['off', 'heat', 'cool', 'emergency_heating'])
|
|
156
176
|
.withRunningState(['idle', 'heat', 'cool', 'fan_only']).withFanMode(['auto', 'on'])
|
|
157
|
-
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
177
|
+
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
178
|
+
.withLocalTemperatureCalibration(-20, 20, 1)],
|
|
158
179
|
meta: {battery: {voltageToPercentage: '3V_1500_2800'}},
|
|
159
180
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
160
181
|
const endpoint = device.getEndpoint(1);
|
|
@@ -179,7 +200,8 @@ module.exports = [
|
|
|
179
200
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 1).withLocalTemperature()
|
|
180
201
|
.withSystemMode(['off', 'heat', 'cool', 'emergency_heating'])
|
|
181
202
|
.withRunningState(['idle', 'heat', 'cool', 'fan_only']).withFanMode(['auto', 'on'])
|
|
182
|
-
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
203
|
+
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
204
|
+
.withLocalTemperatureCalibration(-20, 20, 1)],
|
|
183
205
|
meta: {battery: {voltageToPercentage: '3V_1500_2800'}},
|
|
184
206
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
185
207
|
const endpoint = device.getEndpoint(1);
|
package/devices/ecozy.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = [
|
|
|
18
18
|
tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_relay_status_log,
|
|
19
19
|
tz.thermostat_pi_heating_demand, tz.thermostat_running_state],
|
|
20
20
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature()
|
|
21
|
-
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat'])
|
|
21
|
+
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat'])
|
|
22
|
+
.withLocalTemperatureCalibration(-20, 20, 1)
|
|
22
23
|
.withPiHeatingDemand(ea.STATE_GET)],
|
|
23
24
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
24
25
|
const endpoint = device.getEndpoint(3);
|
package/devices/elko.js
CHANGED
|
@@ -27,11 +27,15 @@ module.exports = [
|
|
|
27
27
|
vendor: 'ELKO',
|
|
28
28
|
description: 'ESH Plus Super TR RF PH',
|
|
29
29
|
fromZigbee: [fz.elko_thermostat, fz.thermostat],
|
|
30
|
-
toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_heating_setpoint,
|
|
30
|
+
toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_heating_setpoint, tz.elko_load,
|
|
31
31
|
tz.elko_display_text, tz.elko_power_status, tz.elko_external_temp, tz.elko_mean_power, tz.elko_child_lock, tz.elko_frost_guard,
|
|
32
32
|
tz.elko_relay_state, tz.elko_sensor_mode, tz.elko_local_temperature_calibration, tz.elko_max_floor_temp,
|
|
33
33
|
tz.elko_regulator_mode, tz.elko_regulator_time, tz.elko_night_switching],
|
|
34
34
|
exposes: [exposes.text('display_text', ea.ALL).withDescription('Displayed text on thermostat display (zone). Max 14 characters'),
|
|
35
|
+
exposes.numeric('load', ea.ALL).withUnit('W')
|
|
36
|
+
.withDescription('Load in W when heating is on (between 0-2000 W). The thermostat uses the value as input to the ' +
|
|
37
|
+
'mean_power calculation.')
|
|
38
|
+
.withValueMin(0).withValueMax(2000),
|
|
35
39
|
exposes.binary('regulator_mode', ea.ALL, 'regulator', 'thermostat')
|
|
36
40
|
.withDescription('Device in regulator or thermostat mode.'),
|
|
37
41
|
exposes.numeric('regulator_time', ea.ALL).withUnit('min')
|
|
@@ -41,7 +45,7 @@ module.exports = [
|
|
|
41
45
|
'(quick) wooden floors.'),
|
|
42
46
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 50, 1)
|
|
43
47
|
.withLocalTemperature(ea.STATE)
|
|
44
|
-
.withLocalTemperatureCalibration()
|
|
48
|
+
.withLocalTemperatureCalibration(-20, 20, 1)
|
|
45
49
|
.withSystemMode(['off', 'heat']).withRunningState(['idle', 'heat'])
|
|
46
50
|
.withSensor(['air', 'floor', 'supervisor_floor']),
|
|
47
51
|
exposes.numeric('floor_temp', ea.STATE_GET).withUnit('°C')
|
|
@@ -69,6 +73,13 @@ module.exports = [
|
|
|
69
73
|
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
70
74
|
|
|
71
75
|
// ELKO attributes
|
|
76
|
+
// Load value
|
|
77
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
78
|
+
attribute: 'elkoLoad',
|
|
79
|
+
minimumReportInterval: 0,
|
|
80
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
81
|
+
reportableChange: null,
|
|
82
|
+
}]);
|
|
72
83
|
// Power status
|
|
73
84
|
await endpoint.configureReporting('hvacThermostat', [{
|
|
74
85
|
attribute: 'elkoPowerStatus',
|
package/devices/eurotronic.js
CHANGED
|
@@ -19,7 +19,8 @@ module.exports = [
|
|
|
19
19
|
tz.thermostat_remote_sensing, tz.thermostat_local_temperature, tz.thermostat_running_state,
|
|
20
20
|
tz.eurotronic_current_heating_setpoint, tz.eurotronic_trv_mode, tz.eurotronic_valve_position],
|
|
21
21
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
22
|
-
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat'])
|
|
22
|
+
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat'])
|
|
23
|
+
.withLocalTemperatureCalibration(-20, 20, 1)
|
|
23
24
|
.withPiHeatingDemand(),
|
|
24
25
|
exposes.enum('trv_mode', exposes.access.ALL, [1, 2])
|
|
25
26
|
.withDescription('Select between direct control of the valve via the `valve_position` or automatic control of the '+
|
package/devices/hgkg.js
CHANGED
|
@@ -17,7 +17,7 @@ module.exports = [
|
|
|
17
17
|
tz.moes_thermostat_deadzone_temperature, tz.moes_thermostat_max_temperature_limit],
|
|
18
18
|
exposes: [e.child_lock(), e.deadzone_temperature(), e.max_temperature_limit(),
|
|
19
19
|
exposes.climate().withSetpoint('current_heating_setpoint', 5, 30, 1, ea.STATE_SET)
|
|
20
|
-
.withLocalTemperature(ea.STATE).withLocalTemperatureCalibration(ea.STATE_SET)
|
|
20
|
+
.withLocalTemperature(ea.STATE).withLocalTemperatureCalibration(-20, 20, 1, ea.STATE_SET)
|
|
21
21
|
.withSystemMode(['off', 'cool'], ea.STATE_SET).withRunningState(['idle', 'heat', 'cool'], ea.STATE)
|
|
22
22
|
.withPreset(['hold', 'program']).withSensor(['IN', 'AL', 'OU'], ea.STATE_SET)],
|
|
23
23
|
onEvent: tuya.onEventSetLocalTime,
|
package/devices/ikea.js
CHANGED
|
@@ -4,6 +4,7 @@ const tz = require('../converters/toZigbee');
|
|
|
4
4
|
const ota = require('../lib/ota');
|
|
5
5
|
const constants = require('../lib/constants');
|
|
6
6
|
const reporting = require('../lib/reporting');
|
|
7
|
+
const {repInterval} = require('../lib/constants');
|
|
7
8
|
const extend = require('../lib/extend');
|
|
8
9
|
const e = exposes.presets;
|
|
9
10
|
const ea = exposes.access;
|
|
@@ -625,14 +626,45 @@ module.exports = [
|
|
|
625
626
|
model: 'E2007',
|
|
626
627
|
vendor: 'IKEA',
|
|
627
628
|
description: 'STARKVIND air purifier',
|
|
628
|
-
exposes: [
|
|
629
|
+
exposes: [
|
|
630
|
+
e.fan().withModes(['off', 'auto', '1', '2', '3', '4', '5', '6', '7', '8', '9']),
|
|
631
|
+
exposes.numeric('fan_speed', exposes.access.STATE_GET).withValueMin(0).withValueMax(9)
|
|
632
|
+
.withDescription('Current fan speed'),
|
|
633
|
+
e.pm25().withAccess(ea.STATE_GET),
|
|
634
|
+
exposes.enum('air_quality', ea.STATE_GET, [
|
|
635
|
+
'good', 'ok', 'not_good', 'unknown',
|
|
636
|
+
]).withDescription('Measured air quality'),
|
|
637
|
+
exposes.binary('led_enable', ea.ALL, true, false).withDescription('Enabled LED'),
|
|
638
|
+
exposes.binary('child_lock', ea.ALL, 'LOCK', 'UNLOCK').withDescription('Enables/disables physical input on the device'),
|
|
639
|
+
exposes.binary('replace_filter', ea.STATE_GET, true, false)
|
|
640
|
+
.withDescription('Filter is older than 6 months and needs replacing'),
|
|
641
|
+
],
|
|
629
642
|
meta: {fanStateOn: 'auto'},
|
|
630
|
-
fromZigbee: [fz.
|
|
631
|
-
toZigbee: [
|
|
643
|
+
fromZigbee: [fz.ikea_air_purifier],
|
|
644
|
+
toZigbee: [
|
|
645
|
+
tz.ikea_air_purifier_fan_mode, tz.ikea_air_purifier_fan_speed,
|
|
646
|
+
tz.ikea_air_purifier_pm25, tz.ikea_air_purifier_child_lock, tz.ikea_air_purifier_led_enable,
|
|
647
|
+
tz.ikea_air_purifier_replace_filter,
|
|
648
|
+
],
|
|
632
649
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
650
|
+
const options = {manufacturerCode: 0x117c};
|
|
633
651
|
const endpoint = device.getEndpoint(1);
|
|
634
|
-
|
|
635
|
-
await reporting.
|
|
652
|
+
|
|
653
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['manuSpecificIkeaAirPurifier']);
|
|
654
|
+
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'particulateMatter25Measurement',
|
|
655
|
+
minimumReportInterval: repInterval.MINUTE, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
656
|
+
options);
|
|
657
|
+
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'filterRunTime',
|
|
658
|
+
minimumReportInterval: repInterval.HOUR, maximumReportInterval: repInterval.HOUR, reportableChange: 0}],
|
|
659
|
+
options);
|
|
660
|
+
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'fanMode',
|
|
661
|
+
minimumReportInterval: 0, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
662
|
+
options);
|
|
663
|
+
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'fanSpeed',
|
|
664
|
+
minimumReportInterval: 0, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
665
|
+
options);
|
|
666
|
+
|
|
667
|
+
await endpoint.read('manuSpecificIkeaAirPurifier', ['controlPanelLight', 'childLock', 'filterRunTime']);
|
|
636
668
|
},
|
|
637
669
|
},
|
|
638
670
|
{
|
package/devices/innr.js
CHANGED
|
@@ -477,6 +477,30 @@ module.exports = [
|
|
|
477
477
|
await reporting.onOff(endpoint);
|
|
478
478
|
},
|
|
479
479
|
},
|
|
480
|
+
{
|
|
481
|
+
zigbeeModel: ['SP 234'],
|
|
482
|
+
model: 'SP 234',
|
|
483
|
+
vendor: 'Innr',
|
|
484
|
+
description: 'Smart plug',
|
|
485
|
+
fromZigbee: [fz.electrical_measurement, fz.on_off, fz.ignore_genLevelCtrl_report, fz.metering],
|
|
486
|
+
toZigbee: [tz.on_off],
|
|
487
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
488
|
+
const endpoint = device.getEndpoint(1);
|
|
489
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
490
|
+
await reporting.onOff(endpoint);
|
|
491
|
+
// Gives UNSUPPORTED_ATTRIBUTE on reporting.readEletricalMeasurementMultiplierDivisors.
|
|
492
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {
|
|
493
|
+
acCurrentDivisor: 1000,
|
|
494
|
+
acCurrentMultiplier: 1,
|
|
495
|
+
});
|
|
496
|
+
await reporting.activePower(endpoint);
|
|
497
|
+
await reporting.rmsCurrent(endpoint);
|
|
498
|
+
await reporting.rmsVoltage(endpoint);
|
|
499
|
+
// Gives UNSUPPORTED_ATTRIBUTE on reporting.readMeteringMultiplierDivisor.
|
|
500
|
+
endpoint.saveClusterAttributeKeyValue('seMetering', {multiplier: 1, divisor: 100});
|
|
501
|
+
},
|
|
502
|
+
exposes: [e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.switch(), e.energy()],
|
|
503
|
+
},
|
|
480
504
|
{
|
|
481
505
|
zigbeeModel: ['OFL 120 C'],
|
|
482
506
|
model: 'OFL 120 C',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
3
|
+
const reporting = require('../lib/reporting');
|
|
4
|
+
const utils = require('../lib/utils');
|
|
5
|
+
const e = exposes.presets;
|
|
6
|
+
|
|
7
|
+
const jetHome = {
|
|
8
|
+
fz: {
|
|
9
|
+
multiStateAction: {
|
|
10
|
+
cluster: 'genMultistateInput',
|
|
11
|
+
type: ['attributeReport', 'readResponse'],
|
|
12
|
+
convert: (model, msg, publish, options, meta) => {
|
|
13
|
+
const actionLookup = {0: 'release', 1: 'single', 2: 'double', 3: 'triple', 4: 'hold'};
|
|
14
|
+
const value = msg.data['presentValue'];
|
|
15
|
+
const action = actionLookup[value];
|
|
16
|
+
return {action: utils.postfixWithEndpointName(action, msg, model)};
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = [
|
|
23
|
+
{
|
|
24
|
+
fingerprint: [{modelID: 'WS7', manufacturerName: 'JetHome'}],
|
|
25
|
+
model: 'WS7',
|
|
26
|
+
vendor: 'JetHome',
|
|
27
|
+
description: '3-ch battery discrete input module',
|
|
28
|
+
fromZigbee: [fz.battery, jetHome.fz.multiStateAction],
|
|
29
|
+
toZigbee: [],
|
|
30
|
+
exposes: [
|
|
31
|
+
e.battery(), e.battery_voltage(), e.action(
|
|
32
|
+
['release_in1', 'single_in1', 'double_in1', 'hold_in1',
|
|
33
|
+
'release_in2', 'single_in2', 'double_in2', 'hold_in2',
|
|
34
|
+
'release_in3', 'single_in3', 'double_in3', 'hold_in3'])],
|
|
35
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
36
|
+
const endpoint = device.getEndpoint(1);
|
|
37
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
38
|
+
await reporting.batteryVoltage(endpoint);
|
|
39
|
+
await reporting.batteryPercentageRemaining(endpoint);
|
|
40
|
+
},
|
|
41
|
+
meta: {multiEndpoint: true},
|
|
42
|
+
endpoint: (device) => {
|
|
43
|
+
return {
|
|
44
|
+
'in1': 1, 'in2': 2, 'in3': 3,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
];
|
package/devices/keen_home.js
CHANGED
|
@@ -41,7 +41,7 @@ module.exports = [
|
|
|
41
41
|
exposes: [e.cover_position().setAccess('state', ea.ALL), e.temperature(), e.battery(), e.pressure()],
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
zigbeeModel: ['SV02-410-MP-1.3', 'SV02-610-MP-1.3', 'SV02-612-MP-1.3', 'SV02-410-MP-1.0'],
|
|
44
|
+
zigbeeModel: ['SV02-410-MP-1.3', 'SV02-412-MP-1.3', 'SV02-610-MP-1.3', 'SV02-612-MP-1.3', 'SV02-410-MP-1.0'],
|
|
45
45
|
model: 'SV02',
|
|
46
46
|
vendor: 'Keen Home',
|
|
47
47
|
description: 'Smart vent',
|
package/devices/leedarson.js
CHANGED
|
@@ -5,6 +5,27 @@ const extend = require('../lib/extend');
|
|
|
5
5
|
const e = exposes.presets;
|
|
6
6
|
|
|
7
7
|
module.exports = [
|
|
8
|
+
{
|
|
9
|
+
zigbeeModel: ['ZBT-DIMLight-GLS0800'],
|
|
10
|
+
model: 'ZBT-DIMLight-GLS0800',
|
|
11
|
+
vendor: 'Leedarson',
|
|
12
|
+
description: 'LED E27 warm white',
|
|
13
|
+
extend: extend.light_onoff_brightness(),
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
zigbeeModel: ['ZBT-CCTLight-GLS0904'],
|
|
17
|
+
model: 'ZBT-CCTLight-GLS0904',
|
|
18
|
+
vendor: 'Leedarson',
|
|
19
|
+
description: 'LED E27 tunable white',
|
|
20
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
zigbeeModel: ['ZBT-CCTLight-Candle0904'],
|
|
24
|
+
model: 'ZBT-CCTLight-Candle0904',
|
|
25
|
+
vendor: 'Leedarson',
|
|
26
|
+
description: 'LED E14 tunable white',
|
|
27
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
28
|
+
},
|
|
8
29
|
{
|
|
9
30
|
zigbeeModel: ['LED_GU10_OWDT'],
|
|
10
31
|
model: 'ZM350STW1TCF',
|
|
@@ -72,4 +93,22 @@ module.exports = [
|
|
|
72
93
|
toZigbee: [],
|
|
73
94
|
exposes: [e.occupancy(), e.illuminance(), e.illuminance_lux()],
|
|
74
95
|
},
|
|
96
|
+
{
|
|
97
|
+
zigbeeModel: ['ZB-SMART-PIRTH-V1'],
|
|
98
|
+
model: '7A-SS-ZABC-H0',
|
|
99
|
+
vendor: 'Leedarson',
|
|
100
|
+
description: '4-in-1-Sensor',
|
|
101
|
+
fromZigbee: [fz.battery, fz.ias_occupancy_alarm_1, fz.illuminance, fz.temperature, fz.humidity, fz.ignore_occupancy_report],
|
|
102
|
+
toZigbee: [],
|
|
103
|
+
exposes: [e.battery(), e.occupancy(), e.temperature(), e.illuminance(), e.illuminance_lux(), e.humidity()],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
zigbeeModel: ['ZB-MotionSensor-S0000'],
|
|
107
|
+
model: '8A-SS-BA-H0',
|
|
108
|
+
vendor: 'Leedarson',
|
|
109
|
+
description: 'Motion Sensor',
|
|
110
|
+
fromZigbee: [fz.battery, fz.ias_occupancy_alarm_1, fz.ignore_occupancy_report],
|
|
111
|
+
toZigbee: [],
|
|
112
|
+
exposes: [e.battery(), e.occupancy()],
|
|
113
|
+
},
|
|
75
114
|
];
|
package/devices/leviton.js
CHANGED
|
@@ -80,6 +80,7 @@ module.exports = [
|
|
|
80
80
|
exposes: [
|
|
81
81
|
exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 1).withLocalTemperature()
|
|
82
82
|
.withSystemMode(['off', 'auto', 'heat', 'cool']).withFanMode(['auto', 'on', 'smart'])
|
|
83
|
-
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
83
|
+
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
84
|
+
.withLocalTemperatureCalibration(-20, 20, 1).withPiHeatingDemand()],
|
|
84
85
|
},
|
|
85
86
|
];
|