zigbee-herdsman-converters 14.0.318 → 14.0.322
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 +16 -91
- package/converters/toZigbee.js +32 -68
- package/devices/centralite.js +20 -0
- package/devices/elko.js +12 -1
- package/devices/ikea.js +170 -10
- package/devices/jethome.js +48 -0
- package/devices/keen_home.js +1 -1
- package/devices/moes.js +5 -6
- package/devices/philips.js +12 -3
- package/devices/tuya.js +11 -4
- package/devices/xiaomi.js +17 -1
- package/lib/exposes.js +1 -1
- package/lib/utils.js +1 -1
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
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,79 +4293,6 @@ const converters = {
|
|
|
4295
4293
|
}
|
|
4296
4294
|
},
|
|
4297
4295
|
},
|
|
4298
|
-
ikea_air_purifier: {
|
|
4299
|
-
cluster: 'manuSpecificIkeaAirPurifier',
|
|
4300
|
-
type: ['attributeReport', 'readResponse'],
|
|
4301
|
-
options: [exposes.options.precision('pm25'), exposes.options.calibration('pm25')],
|
|
4302
|
-
convert: (model, msg, publish, options, meta) => {
|
|
4303
|
-
const state = {};
|
|
4304
|
-
|
|
4305
|
-
if (msg.data.hasOwnProperty('particulateMatter25Measurement')) {
|
|
4306
|
-
const pm25Property = postfixWithEndpointName('pm25', msg, model);
|
|
4307
|
-
let pm25 = parseFloat(msg.data['particulateMatter25Measurement']);
|
|
4308
|
-
|
|
4309
|
-
// Air Quality Scale (ikea app):
|
|
4310
|
-
// 0-35=Good, 35-80=OK, 80+=Not Good
|
|
4311
|
-
let airQuality;
|
|
4312
|
-
const airQualityProperty = postfixWithEndpointName('air_quality', msg, model);
|
|
4313
|
-
if (pm25 <= 35) {
|
|
4314
|
-
airQuality = 'good';
|
|
4315
|
-
} else if (pm25 <= 80) {
|
|
4316
|
-
airQuality = 'ok';
|
|
4317
|
-
} else if (pm25 < 65535) {
|
|
4318
|
-
airQuality = 'not_good';
|
|
4319
|
-
} else {
|
|
4320
|
-
airQuality = 'unknown';
|
|
4321
|
-
}
|
|
4322
|
-
|
|
4323
|
-
// calibrate and round pm25 unless invalid
|
|
4324
|
-
pm25 = (pm25 == 65535) ? -1 : calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
4325
|
-
|
|
4326
|
-
state[pm25Property] = calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
4327
|
-
state[airQualityProperty] = airQuality;
|
|
4328
|
-
}
|
|
4329
|
-
|
|
4330
|
-
if (msg.data.hasOwnProperty('filterRunTime')) {
|
|
4331
|
-
// Filter needs to be replaced after 6 months
|
|
4332
|
-
state['replace_filter'] = (parseInt(msg.data['filterRunTime']) >= 259200);
|
|
4333
|
-
}
|
|
4334
|
-
|
|
4335
|
-
if (msg.data.hasOwnProperty('controlPanelLight')) {
|
|
4336
|
-
state['led_enable'] = (msg.data['controlPanelLight'] == 0);
|
|
4337
|
-
}
|
|
4338
|
-
|
|
4339
|
-
if (msg.data.hasOwnProperty('childLock')) {
|
|
4340
|
-
state['child_lock'] = (msg.data['childLock'] > 0 ? 'LOCK' : 'UNLOCK');
|
|
4341
|
-
}
|
|
4342
|
-
|
|
4343
|
-
if (msg.data.hasOwnProperty('fanSpeed')) {
|
|
4344
|
-
let fanSpeed = msg.data['fanSpeed'];
|
|
4345
|
-
if (fanSpeed >= 10) {
|
|
4346
|
-
fanSpeed = (((fanSpeed - 5) * 2) / 10);
|
|
4347
|
-
} else {
|
|
4348
|
-
fanSpeed = 0;
|
|
4349
|
-
}
|
|
4350
|
-
|
|
4351
|
-
state['fan_speed'] = fanSpeed;
|
|
4352
|
-
}
|
|
4353
|
-
|
|
4354
|
-
if (msg.data.hasOwnProperty('fanMode')) {
|
|
4355
|
-
let fanMode = msg.data['fanMode'];
|
|
4356
|
-
if (fanMode >= 10) {
|
|
4357
|
-
fanMode = (((fanMode - 5) * 2) / 10).toString();
|
|
4358
|
-
} else if (fanMode == 1) {
|
|
4359
|
-
fanMode = 'auto';
|
|
4360
|
-
} else {
|
|
4361
|
-
fanMode = 'off';
|
|
4362
|
-
}
|
|
4363
|
-
|
|
4364
|
-
state['fan_mode'] = fanMode;
|
|
4365
|
-
state['fan_state'] = (fanMode === 'off' ? 'OFF' : 'ON');
|
|
4366
|
-
}
|
|
4367
|
-
|
|
4368
|
-
return state;
|
|
4369
|
-
},
|
|
4370
|
-
},
|
|
4371
4296
|
E1524_E1810_levelctrl: {
|
|
4372
4297
|
cluster: 'genLevelCtrl',
|
|
4373
4298
|
type: [
|
package/converters/toZigbee.js
CHANGED
|
@@ -330,7 +330,7 @@ const converters = {
|
|
|
330
330
|
|
|
331
331
|
let info;
|
|
332
332
|
// https://github.com/Koenkk/zigbee2mqtt/issues/8310 some devices require the info to be reversed.
|
|
333
|
-
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)) {
|
|
334
334
|
info = (mode[values.mode]) + ((values.strobe ? 1 : 0) << 4) + (level[values.level] << 6);
|
|
335
335
|
} else {
|
|
336
336
|
info = (mode[values.mode] << 4) + ((values.strobe ? 1 : 0) << 2) + (level[values.level]);
|
|
@@ -1379,6 +1379,16 @@ const converters = {
|
|
|
1379
1379
|
// #endregion
|
|
1380
1380
|
|
|
1381
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
|
+
},
|
|
1382
1392
|
elko_display_text: {
|
|
1383
1393
|
key: ['display_text'],
|
|
1384
1394
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -1912,71 +1922,6 @@ const converters = {
|
|
|
1912
1922
|
await entity.read('genBasic', [0x0033], manufacturerOptions.hue);
|
|
1913
1923
|
},
|
|
1914
1924
|
},
|
|
1915
|
-
ikea_air_purifier_fan_mode: {
|
|
1916
|
-
key: ['fan_mode', 'fan_state'],
|
|
1917
|
-
convertSet: async (entity, key, value, meta) => {
|
|
1918
|
-
if (key == 'fan_state' && value.toLowerCase() == 'on') {
|
|
1919
|
-
value = utils.getMetaValue(entity, meta.mapped, 'fanStateOn', 'allEqual', 'on');
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
let fanMode;
|
|
1923
|
-
switch (value.toLowerCase()) {
|
|
1924
|
-
case 'off':
|
|
1925
|
-
fanMode = 0;
|
|
1926
|
-
break;
|
|
1927
|
-
case 'auto':
|
|
1928
|
-
fanMode = 1;
|
|
1929
|
-
break;
|
|
1930
|
-
default:
|
|
1931
|
-
fanMode = parseInt(((parseInt(value) / 2.0) * 10) + 5);
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
await entity.write('manuSpecificIkeaAirPurifier', {'fanMode': fanMode}, manufacturerOptions.ikea);
|
|
1935
|
-
return {state: {fan_mode: value.toLowerCase(), fan_state: value.toLowerCase() === 'off' ? 'OFF' : 'ON'}};
|
|
1936
|
-
},
|
|
1937
|
-
convertGet: async (entity, key, meta) => {
|
|
1938
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['fanMode']);
|
|
1939
|
-
},
|
|
1940
|
-
},
|
|
1941
|
-
ikea_air_purifier_fan_speed: {
|
|
1942
|
-
key: ['fan_speed'],
|
|
1943
|
-
convertGet: async (entity, key, meta) => {
|
|
1944
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['fanSpeed']);
|
|
1945
|
-
},
|
|
1946
|
-
},
|
|
1947
|
-
ikea_air_purifier_pm25: {
|
|
1948
|
-
key: ['pm25', 'air_quality'],
|
|
1949
|
-
convertGet: async (entity, key, meta) => {
|
|
1950
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['particulateMatter25Measurement']);
|
|
1951
|
-
},
|
|
1952
|
-
},
|
|
1953
|
-
ikea_air_purifier_replace_filter: {
|
|
1954
|
-
key: ['replace_filter'],
|
|
1955
|
-
convertGet: async (entity, key, meta) => {
|
|
1956
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['filterRunTime']);
|
|
1957
|
-
},
|
|
1958
|
-
},
|
|
1959
|
-
ikea_air_purifier_child_lock: {
|
|
1960
|
-
key: ['child_lock'],
|
|
1961
|
-
convertSet: async (entity, key, value, meta) => {
|
|
1962
|
-
await entity.write('manuSpecificIkeaAirPurifier', {'childLock': ((value.toLowerCase() === 'lock') ? 1 : 0)},
|
|
1963
|
-
manufacturerOptions.ikea);
|
|
1964
|
-
return {state: {child_lock: ((value.toLowerCase() === 'lock') ? 'LOCK' : 'UNLOCK')}};
|
|
1965
|
-
},
|
|
1966
|
-
convertGet: async (entity, key, meta) => {
|
|
1967
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['childLock']);
|
|
1968
|
-
},
|
|
1969
|
-
},
|
|
1970
|
-
ikea_air_purifier_led_enable: {
|
|
1971
|
-
key: ['led_enable'],
|
|
1972
|
-
convertSet: async (entity, key, value, meta) => {
|
|
1973
|
-
await entity.write('manuSpecificIkeaAirPurifier', {'controlPanelLight': ((value) ? 0 : 1)}, manufacturerOptions.ikea);
|
|
1974
|
-
return {state: {led_enable: ((value) ? true : false)}};
|
|
1975
|
-
},
|
|
1976
|
-
convertGet: async (entity, key, meta) => {
|
|
1977
|
-
await entity.read('manuSpecificIkeaAirPurifier', ['controlPanelLight']);
|
|
1978
|
-
},
|
|
1979
|
-
},
|
|
1980
1925
|
RTCGQ13LM_motion_sensitivity: {
|
|
1981
1926
|
key: ['motion_sensitivity'],
|
|
1982
1927
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -2022,7 +1967,7 @@ const converters = {
|
|
|
2022
1967
|
xiaomi_switch_power_outage_memory: {
|
|
2023
1968
|
key: ['power_outage_memory'],
|
|
2024
1969
|
convertSet: async (entity, key, value, meta) => {
|
|
2025
|
-
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
1970
|
+
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
2026
1971
|
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG31LM', 'QBCZ15LM', 'QBKG20LM', 'QBKG38LM',
|
|
2027
1972
|
'QBKG34LM', 'QBCZ14LM', 'QBKG19LM'].includes(meta.mapped.model)) {
|
|
2028
1973
|
await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
|
|
@@ -2045,7 +1990,7 @@ const converters = {
|
|
|
2045
1990
|
return {state: {power_outage_memory: value}};
|
|
2046
1991
|
},
|
|
2047
1992
|
convertGet: async (entity, key, meta) => {
|
|
2048
|
-
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
1993
|
+
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
2049
1994
|
'WS-EUK02', 'WS-EUK01', 'QBKG31LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG20LM', 'QBKG34LM', 'QBKG19LM',
|
|
2050
1995
|
'QBKG38LM'].includes(meta.mapped.model)) {
|
|
2051
1996
|
await entity.read('aqaraOpple', [0x0201]);
|
|
@@ -2830,6 +2775,25 @@ const converters = {
|
|
|
2830
2775
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSminTempSet, temp);
|
|
2831
2776
|
},
|
|
2832
2777
|
},
|
|
2778
|
+
moesS_thermostat_schedule_programming: {
|
|
2779
|
+
key: ['programming_mode'],
|
|
2780
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2781
|
+
const payload = [];
|
|
2782
|
+
const items = value.split(' ');
|
|
2783
|
+
for (let i = 0; i < 12; i++) {
|
|
2784
|
+
const hourTemperature = items[i].split('/');
|
|
2785
|
+
const hourMinute = hourTemperature[0].split(':', 2);
|
|
2786
|
+
const h = parseInt(hourMinute[0]);
|
|
2787
|
+
const m = parseInt(hourMinute[1]);
|
|
2788
|
+
const temp = parseInt(hourTemperature[1]);
|
|
2789
|
+
if (h < 0 || h >= 24 || m < 0 || m >= 60 || temp < 5 || temp >= 35) {
|
|
2790
|
+
throw new Error('Invalid hour, minute or temperature of:' + items[i]);
|
|
2791
|
+
}
|
|
2792
|
+
payload[i*3] = h; payload[i*3+1] = m; payload[i*3+2] = temp * 2;
|
|
2793
|
+
}
|
|
2794
|
+
return tuya.sendDataPointRaw(entity, tuya.dataPoints.moesSschedule, payload);
|
|
2795
|
+
},
|
|
2796
|
+
},
|
|
2833
2797
|
tvtwo_thermostat: {
|
|
2834
2798
|
key: [
|
|
2835
2799
|
'window_detection', 'frost_protection', 'child_lock',
|
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',
|
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')
|
|
@@ -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/ikea.js
CHANGED
|
@@ -8,6 +8,10 @@ const {repInterval} = require('../lib/constants');
|
|
|
8
8
|
const extend = require('../lib/extend');
|
|
9
9
|
const e = exposes.presets;
|
|
10
10
|
const ea = exposes.access;
|
|
11
|
+
const herdsman = require('zigbee-herdsman');
|
|
12
|
+
const {
|
|
13
|
+
calibrateAndPrecisionRoundOptions, postfixWithEndpointName, getMetaValue,
|
|
14
|
+
} = require('../lib/utils');
|
|
11
15
|
|
|
12
16
|
const bulbOnEvent = async (type, data, device) => {
|
|
13
17
|
/**
|
|
@@ -49,6 +53,161 @@ const tradfriExtend = {
|
|
|
49
53
|
}),
|
|
50
54
|
};
|
|
51
55
|
|
|
56
|
+
const manufacturerOptions = {manufacturerCode: herdsman.Zcl.ManufacturerCode.IKEA_OF_SWEDEN};
|
|
57
|
+
|
|
58
|
+
const ikea = {
|
|
59
|
+
fz: {
|
|
60
|
+
air_purifier: {
|
|
61
|
+
cluster: 'manuSpecificIkeaAirPurifier',
|
|
62
|
+
type: ['attributeReport', 'readResponse'],
|
|
63
|
+
options: [exposes.options.precision('pm25'), exposes.options.calibration('pm25')],
|
|
64
|
+
convert: (model, msg, publish, options, meta) => {
|
|
65
|
+
const state = {};
|
|
66
|
+
|
|
67
|
+
if (msg.data.hasOwnProperty('particulateMatter25Measurement')) {
|
|
68
|
+
const pm25Property = postfixWithEndpointName('pm25', msg, model);
|
|
69
|
+
let pm25 = parseFloat(msg.data['particulateMatter25Measurement']);
|
|
70
|
+
|
|
71
|
+
// Air Quality
|
|
72
|
+
// Scale based on EU AQI (https://www.eea.europa.eu/themes/air/air-quality-index)
|
|
73
|
+
// Using German IAQ labels to match the Develco Air Quality Sensor
|
|
74
|
+
let airQuality;
|
|
75
|
+
const airQualityProperty = postfixWithEndpointName('air_quality', msg, model);
|
|
76
|
+
if (pm25 <= 10) {
|
|
77
|
+
airQuality = 'excellent';
|
|
78
|
+
} else if (pm25 <= 20) {
|
|
79
|
+
airQuality = 'good';
|
|
80
|
+
} else if (pm25 <= 25) {
|
|
81
|
+
airQuality = 'moderate';
|
|
82
|
+
} else if (pm25 <= 50) {
|
|
83
|
+
airQuality = 'poor';
|
|
84
|
+
} else if (pm25 <= 75) {
|
|
85
|
+
airQuality = 'unhealthy';
|
|
86
|
+
} else if (pm25 <= 800) {
|
|
87
|
+
airQuality = 'hazardous';
|
|
88
|
+
} else if (pm25 < 65535) {
|
|
89
|
+
airQuality = 'out_of_range';
|
|
90
|
+
} else {
|
|
91
|
+
airQuality = 'unknown';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// calibrate and round pm25 unless invalid
|
|
95
|
+
pm25 = (pm25 == 65535) ? -1 : calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
96
|
+
|
|
97
|
+
state[pm25Property] = calibrateAndPrecisionRoundOptions(pm25, options, 'pm25');
|
|
98
|
+
state[airQualityProperty] = airQuality;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (msg.data.hasOwnProperty('filterRunTime')) {
|
|
102
|
+
// Filter needs to be replaced after 6 months
|
|
103
|
+
state['replace_filter'] = (parseInt(msg.data['filterRunTime']) >= 259200);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (msg.data.hasOwnProperty('controlPanelLight')) {
|
|
107
|
+
state['led_enable'] = (msg.data['controlPanelLight'] == 0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (msg.data.hasOwnProperty('childLock')) {
|
|
111
|
+
state['child_lock'] = (msg.data['childLock'] > 0 ? 'LOCK' : 'UNLOCK');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (msg.data.hasOwnProperty('fanSpeed')) {
|
|
115
|
+
let fanSpeed = msg.data['fanSpeed'];
|
|
116
|
+
if (fanSpeed >= 10) {
|
|
117
|
+
fanSpeed = (((fanSpeed - 5) * 2) / 10);
|
|
118
|
+
} else {
|
|
119
|
+
fanSpeed = 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
state['fan_speed'] = fanSpeed;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (msg.data.hasOwnProperty('fanMode')) {
|
|
126
|
+
let fanMode = msg.data['fanMode'];
|
|
127
|
+
if (fanMode >= 10) {
|
|
128
|
+
fanMode = (((fanMode - 5) * 2) / 10).toString();
|
|
129
|
+
} else if (fanMode == 1) {
|
|
130
|
+
fanMode = 'auto';
|
|
131
|
+
} else {
|
|
132
|
+
fanMode = 'off';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
state['fan_mode'] = fanMode;
|
|
136
|
+
state['fan_state'] = (fanMode === 'off' ? 'OFF' : 'ON');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return state;
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
tz: {
|
|
144
|
+
air_purifier_fan_mode: {
|
|
145
|
+
key: ['fan_mode', 'fan_state'],
|
|
146
|
+
convertSet: async (entity, key, value, meta) => {
|
|
147
|
+
if (key == 'fan_state' && value.toLowerCase() == 'on') {
|
|
148
|
+
value = getMetaValue(entity, meta.mapped, 'fanStateOn', 'allEqual', 'on');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let fanMode;
|
|
152
|
+
switch (value.toLowerCase()) {
|
|
153
|
+
case 'off':
|
|
154
|
+
fanMode = 0;
|
|
155
|
+
break;
|
|
156
|
+
case 'auto':
|
|
157
|
+
fanMode = 1;
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
fanMode = parseInt(((parseInt(value) / 2.0) * 10) + 5);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'fanMode': fanMode}, manufacturerOptions.ikea);
|
|
164
|
+
return {state: {fan_mode: value.toLowerCase(), fan_state: value.toLowerCase() === 'off' ? 'OFF' : 'ON'}};
|
|
165
|
+
},
|
|
166
|
+
convertGet: async (entity, key, meta) => {
|
|
167
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['fanMode']);
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
air_purifier_fan_speed: {
|
|
171
|
+
key: ['fan_speed'],
|
|
172
|
+
convertGet: async (entity, key, meta) => {
|
|
173
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['fanSpeed']);
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
air_purifier_pm25: {
|
|
177
|
+
key: ['pm25', 'air_quality'],
|
|
178
|
+
convertGet: async (entity, key, meta) => {
|
|
179
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['particulateMatter25Measurement']);
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
air_purifier_replace_filter: {
|
|
183
|
+
key: ['replace_filter'],
|
|
184
|
+
convertGet: async (entity, key, meta) => {
|
|
185
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['filterRunTime']);
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
air_purifier_child_lock: {
|
|
189
|
+
key: ['child_lock'],
|
|
190
|
+
convertSet: async (entity, key, value, meta) => {
|
|
191
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'childLock': ((value.toLowerCase() === 'lock') ? 1 : 0)},
|
|
192
|
+
manufacturerOptions);
|
|
193
|
+
return {state: {child_lock: ((value.toLowerCase() === 'lock') ? 'LOCK' : 'UNLOCK')}};
|
|
194
|
+
},
|
|
195
|
+
convertGet: async (entity, key, meta) => {
|
|
196
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['childLock']);
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
air_purifier_led_enable: {
|
|
200
|
+
key: ['led_enable'],
|
|
201
|
+
convertSet: async (entity, key, value, meta) => {
|
|
202
|
+
await entity.write('manuSpecificIkeaAirPurifier', {'controlPanelLight': ((value) ? 0 : 1)}, manufacturerOptions);
|
|
203
|
+
return {state: {led_enable: ((value) ? true : false)}};
|
|
204
|
+
},
|
|
205
|
+
convertGet: async (entity, key, meta) => {
|
|
206
|
+
await entity.read('manuSpecificIkeaAirPurifier', ['controlPanelLight']);
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
52
211
|
|
|
53
212
|
module.exports = [
|
|
54
213
|
{
|
|
@@ -632,7 +791,9 @@ module.exports = [
|
|
|
632
791
|
.withDescription('Current fan speed'),
|
|
633
792
|
e.pm25().withAccess(ea.STATE_GET),
|
|
634
793
|
exposes.enum('air_quality', ea.STATE_GET, [
|
|
635
|
-
'
|
|
794
|
+
'excellent', 'good', 'moderate', 'poor',
|
|
795
|
+
'unhealthy', 'hazardous', 'out_of_range',
|
|
796
|
+
'unknown',
|
|
636
797
|
]).withDescription('Measured air quality'),
|
|
637
798
|
exposes.binary('led_enable', ea.ALL, true, false).withDescription('Enabled LED'),
|
|
638
799
|
exposes.binary('child_lock', ea.ALL, 'LOCK', 'UNLOCK').withDescription('Enables/disables physical input on the device'),
|
|
@@ -640,29 +801,28 @@ module.exports = [
|
|
|
640
801
|
.withDescription('Filter is older than 6 months and needs replacing'),
|
|
641
802
|
],
|
|
642
803
|
meta: {fanStateOn: 'auto'},
|
|
643
|
-
fromZigbee: [fz.
|
|
804
|
+
fromZigbee: [ikea.fz.air_purifier],
|
|
644
805
|
toZigbee: [
|
|
645
|
-
tz.
|
|
646
|
-
tz.
|
|
647
|
-
tz.
|
|
806
|
+
ikea.tz.air_purifier_fan_mode, ikea.tz.air_purifier_fan_speed,
|
|
807
|
+
ikea.tz.air_purifier_pm25, ikea.tz.air_purifier_child_lock, ikea.tz.air_purifier_led_enable,
|
|
808
|
+
ikea.tz.air_purifier_replace_filter,
|
|
648
809
|
],
|
|
649
810
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
650
|
-
const options = {manufacturerCode: 0x117c};
|
|
651
811
|
const endpoint = device.getEndpoint(1);
|
|
652
812
|
|
|
653
813
|
await reporting.bind(endpoint, coordinatorEndpoint, ['manuSpecificIkeaAirPurifier']);
|
|
654
814
|
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'particulateMatter25Measurement',
|
|
655
815
|
minimumReportInterval: repInterval.MINUTE, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
656
|
-
|
|
816
|
+
manufacturerOptions);
|
|
657
817
|
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'filterRunTime',
|
|
658
818
|
minimumReportInterval: repInterval.HOUR, maximumReportInterval: repInterval.HOUR, reportableChange: 0}],
|
|
659
|
-
|
|
819
|
+
manufacturerOptions);
|
|
660
820
|
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'fanMode',
|
|
661
821
|
minimumReportInterval: 0, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
662
|
-
|
|
822
|
+
manufacturerOptions);
|
|
663
823
|
await endpoint.configureReporting('manuSpecificIkeaAirPurifier', [{attribute: 'fanSpeed',
|
|
664
824
|
minimumReportInterval: 0, maximumReportInterval: repInterval.HOUR, reportableChange: 1}],
|
|
665
|
-
|
|
825
|
+
manufacturerOptions);
|
|
666
826
|
|
|
667
827
|
await endpoint.read('manuSpecificIkeaAirPurifier', ['controlPanelLight', 'childLock', 'filterRunTime']);
|
|
668
828
|
},
|
|
@@ -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/moes.js
CHANGED
|
@@ -202,7 +202,8 @@ module.exports = [
|
|
|
202
202
|
tz.moesS_thermostat_boost_heating_countdown, tz.moesS_thermostat_system_mode,
|
|
203
203
|
tz.moesS_thermostat_boost_heating, tz.moesS_thermostat_boostHeatingCountdownTimeSet,
|
|
204
204
|
tz.moesS_thermostat_eco_temperature, tz.moesS_thermostat_max_temperature,
|
|
205
|
-
tz.moesS_thermostat_min_temperature, tz.moesS_thermostat_moesSecoMode
|
|
205
|
+
tz.moesS_thermostat_min_temperature, tz.moesS_thermostat_moesSecoMode,
|
|
206
|
+
tz.moesS_thermostat_schedule_programming],
|
|
206
207
|
exposes: [
|
|
207
208
|
e.battery(), e.child_lock(), e.eco_mode(), e.eco_temperature(), e.max_temperature(), e.min_temperature(),
|
|
208
209
|
e.position(), e.window_detection(),
|
|
@@ -218,11 +219,9 @@ module.exports = [
|
|
|
218
219
|
'to 15 degrees Celsius. After 10 days, the device will automatically switch to programming mode. ' +
|
|
219
220
|
'TEMPORARY MANUAL MODE - In this mode, ☝ icon will flash. At this time, the device executes the manually set ' +
|
|
220
221
|
'temperature and returns to the weekly programming mode in the next time period. '),
|
|
221
|
-
exposes.
|
|
222
|
-
'the device executes a preset week programming temperature time and temperature. '
|
|
223
|
-
|
|
224
|
-
.withFeature(exposes.text('program_saturday', ea.STATE))
|
|
225
|
-
.withFeature(exposes.text('program_sunday', ea.STATE)),
|
|
222
|
+
exposes.text('programming_mode', ea.STATE_SET).withDescription('PROGRAMMING MODE ⏱ - In this mode, ' +
|
|
223
|
+
'the device executes a preset week programming temperature time and temperature. ' +
|
|
224
|
+
'You can set up to 4 stages of temperature every for WEEKDAY ➀➁➂➃➄, SATURDAY ➅ and SUNDAY ➆.'),
|
|
226
225
|
exposes.binary('boost_heating', ea.STATE_SET, 'ON', 'OFF').withDescription('Boost Heating: press and hold "+" for 3 seconds, ' +
|
|
227
226
|
'the device will enter the boost heating mode, and the ▷╵◁ will flash. The countdown will be displayed in the APP'),
|
|
228
227
|
exposes.numeric('boost_heating_countdown', ea.STATE_SET).withUnit('min').withDescription('Countdown in minutes'),
|
package/devices/philips.js
CHANGED
|
@@ -441,7 +441,7 @@ module.exports = [
|
|
|
441
441
|
ota: ota.zigbeeOTA,
|
|
442
442
|
},
|
|
443
443
|
{
|
|
444
|
-
zigbeeModel: ['LWA003'],
|
|
444
|
+
zigbeeModel: ['LWA003', 'LWW002'],
|
|
445
445
|
model: '9290022268',
|
|
446
446
|
vendor: 'Philips',
|
|
447
447
|
description: 'Hue White A19 bulb with Bluetooth',
|
|
@@ -735,6 +735,15 @@ module.exports = [
|
|
|
735
735
|
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
736
736
|
ota: ota.zigbeeOTA,
|
|
737
737
|
},
|
|
738
|
+
{
|
|
739
|
+
zigbeeModel: ['LCA009'],
|
|
740
|
+
model: '9290024717',
|
|
741
|
+
vendor: 'Philips',
|
|
742
|
+
description: 'Hue white and color ambiance E26/A19 1600lm',
|
|
743
|
+
meta: {turnsOffAtBrightness1: true},
|
|
744
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
745
|
+
ota: ota.zigbeeOTA,
|
|
746
|
+
},
|
|
738
747
|
{
|
|
739
748
|
zigbeeModel: ['LCT001', 'LCT007', 'LCT010', 'LCT012', 'LCT014', 'LCT015', 'LCT016', 'LCT021'],
|
|
740
749
|
model: '9290012573A',
|
|
@@ -1306,7 +1315,7 @@ module.exports = [
|
|
|
1306
1315
|
vendor: 'Philips',
|
|
1307
1316
|
description: 'Hue Iris (generation 2, black)',
|
|
1308
1317
|
meta: {turnsOffAtBrightness1: true},
|
|
1309
|
-
extend: hueExtend.
|
|
1318
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1310
1319
|
ota: ota.zigbeeOTA,
|
|
1311
1320
|
},
|
|
1312
1321
|
{
|
|
@@ -2104,7 +2113,7 @@ module.exports = [
|
|
|
2104
2113
|
vendor: 'Philips',
|
|
2105
2114
|
description: 'Hue Play gradient lightstrip 65',
|
|
2106
2115
|
meta: {turnsOffAtBrightness1: true},
|
|
2107
|
-
extend: hueExtend.
|
|
2116
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
2108
2117
|
ota: ota.zigbeeOTA,
|
|
2109
2118
|
},
|
|
2110
2119
|
{
|
package/devices/tuya.js
CHANGED
|
@@ -140,7 +140,9 @@ module.exports = [
|
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3000_4whigl8i'},
|
|
143
|
-
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
|
|
143
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
|
|
144
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
|
|
145
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'}],
|
|
144
146
|
model: 'TS0501B',
|
|
145
147
|
description: 'Zigbee light',
|
|
146
148
|
vendor: 'TuYa',
|
|
@@ -974,7 +976,8 @@ module.exports = [
|
|
|
974
976
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_ps3dmato'},
|
|
975
977
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_mraovvmm'},
|
|
976
978
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_jvzvulen'},
|
|
977
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_w0qqde0g'}
|
|
979
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_w0qqde0g'},
|
|
980
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_nfnmi125'}],
|
|
978
981
|
model: 'TS011F_plug_1',
|
|
979
982
|
description: 'Smart plug (with power monitoring)',
|
|
980
983
|
vendor: 'TuYa',
|
|
@@ -1011,11 +1014,15 @@ module.exports = [
|
|
|
1011
1014
|
.withDescription('Recover state after power outage')],
|
|
1012
1015
|
},
|
|
1013
1016
|
{
|
|
1014
|
-
fingerprint: [
|
|
1015
|
-
{modelID: 'TS011F', manufacturerName: '
|
|
1017
|
+
fingerprint: [
|
|
1018
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'},
|
|
1019
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 69},
|
|
1020
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_5f43h46b'},
|
|
1021
|
+
],
|
|
1016
1022
|
model: 'TS011F_plug_3',
|
|
1017
1023
|
description: 'Smart plug (with power monitoring by polling)',
|
|
1018
1024
|
vendor: 'TuYa',
|
|
1025
|
+
whiteLabel: [{vendor: 'VIKEFON', model: 'TS011F'}],
|
|
1019
1026
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
|
|
1020
1027
|
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
1021
1028
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/devices/xiaomi.js
CHANGED
|
@@ -1357,7 +1357,7 @@ module.exports = [
|
|
|
1357
1357
|
await reporting.batteryVoltage(endpoint);
|
|
1358
1358
|
await reporting.illuminance(endpoint, {min: 15, max: constants.repInterval.HOUR, change: 500});
|
|
1359
1359
|
},
|
|
1360
|
-
exposes: [e.battery(), e.illuminance(), e.illuminance_lux()],
|
|
1360
|
+
exposes: [e.battery(), e.battery_voltage(), e.illuminance(), e.illuminance_lux()],
|
|
1361
1361
|
},
|
|
1362
1362
|
{
|
|
1363
1363
|
zigbeeModel: ['lumi.light.rgbac1'],
|
|
@@ -1426,6 +1426,22 @@ module.exports = [
|
|
|
1426
1426
|
device.save();
|
|
1427
1427
|
},
|
|
1428
1428
|
},
|
|
1429
|
+
{
|
|
1430
|
+
zigbeeModel: ['lumi.switch.l0acn1'],
|
|
1431
|
+
model: 'DLKZMK12LM',
|
|
1432
|
+
vendor: 'Xiaomi',
|
|
1433
|
+
description: 'Aqara single switch module T1 (without neutral). Doesn\'t work as a router and doesn\'t support power meter',
|
|
1434
|
+
fromZigbee: [fz.on_off, fz.xiaomi_switch_type, fz.xiaomi_switch_power_outage_memory],
|
|
1435
|
+
exposes: [e.switch(), e.power_outage_memory(), e.switch_type()],
|
|
1436
|
+
toZigbee: [tz.xiaomi_switch_type, tz.on_off, tz.xiaomi_switch_power_outage_memory],
|
|
1437
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1438
|
+
const endpoint = device.getEndpoint(1);
|
|
1439
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
1440
|
+
await reporting.onOff(endpoint);
|
|
1441
|
+
device.powerSource = 'Mains (single phase)';
|
|
1442
|
+
device.save();
|
|
1443
|
+
},
|
|
1444
|
+
},
|
|
1429
1445
|
{
|
|
1430
1446
|
zigbeeModel: ['lumi.switch.n4acn4'],
|
|
1431
1447
|
model: 'ZNCJMB14LM',
|
package/lib/exposes.js
CHANGED
|
@@ -503,7 +503,7 @@ module.exports = {
|
|
|
503
503
|
battery: () => new Numeric('battery', access.STATE).withUnit('%').withDescription('Remaining battery in %').withValueMin(0).withValueMax(100),
|
|
504
504
|
battery_low: () => new Binary('battery_low', access.STATE, true, false).withDescription('Indicates if the battery of this device is almost empty'),
|
|
505
505
|
battery_voltage: () => new Numeric('voltage', access.STATE).withUnit('mV').withDescription('Voltage of the battery in millivolts'),
|
|
506
|
-
boost_time: () => new Numeric('boost_time', access.STATE_SET).withUnit('s').withDescription('Boost time'),
|
|
506
|
+
boost_time: () => new Numeric('boost_time', access.STATE_SET).withUnit('s').withDescription('Boost time').withValueMin(0).withValueMax(600),
|
|
507
507
|
button_lock: () => new Binary('button_lock', access.ALL, 'ON', 'OFF').withDescription('Disables the physical switch button'),
|
|
508
508
|
carbon_monoxide: () => new Binary('carbon_monoxide', access.STATE, true, false).withDescription('Indicates if CO (carbon monoxide) is detected'),
|
|
509
509
|
child_lock: () => new Lock().withState('child_lock', 'LOCK', 'UNLOCK', 'Enables/disables physical input on the device', access.STATE_SET),
|
package/lib/utils.js
CHANGED
|
@@ -72,7 +72,7 @@ function hasAlreadyProcessedMessage(msg, ID=null, key=null) {
|
|
|
72
72
|
return false;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const defaultPrecision = {temperature: 2, humidity: 2, pressure: 1, pm25:
|
|
75
|
+
const defaultPrecision = {temperature: 2, humidity: 2, pressure: 1, pm25: 0};
|
|
76
76
|
function calibrateAndPrecisionRoundOptions(number, options, type) {
|
|
77
77
|
// Calibrate
|
|
78
78
|
const calibrateKey = `${type}_calibration`;
|
package/npm-shrinkwrap.json
CHANGED