zigbee-herdsman-converters 14.0.320 → 14.0.324
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 +2 -75
- package/converters/toZigbee.js +4 -69
- package/devices/ikea.js +170 -10
- package/devices/osram.js +8 -0
- package/devices/philips.js +38 -2
- package/devices/tuya.js +6 -2
- 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
|
@@ -1425,11 +1425,11 @@ const converters = {
|
|
|
1425
1425
|
const invert = model.meta && model.meta.coverInverted ? !options.invert_cover : options.invert_cover;
|
|
1426
1426
|
if (msg.data.hasOwnProperty('currentPositionLiftPercentage') && msg.data['currentPositionLiftPercentage'] <= 100) {
|
|
1427
1427
|
const value = msg.data['currentPositionLiftPercentage'];
|
|
1428
|
-
result
|
|
1428
|
+
result[postfixWithEndpointName('position', msg, model)] = invert ? value : 100 - value;
|
|
1429
1429
|
}
|
|
1430
1430
|
if (msg.data.hasOwnProperty('currentPositionTiltPercentage') && msg.data['currentPositionTiltPercentage'] <= 100) {
|
|
1431
1431
|
const value = msg.data['currentPositionTiltPercentage'];
|
|
1432
|
-
result
|
|
1432
|
+
result[postfixWithEndpointName('tilt', msg, model)] = invert ? value : 100 - value;
|
|
1433
1433
|
}
|
|
1434
1434
|
return result;
|
|
1435
1435
|
},
|
|
@@ -4293,79 +4293,6 @@ const converters = {
|
|
|
4293
4293
|
}
|
|
4294
4294
|
},
|
|
4295
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
|
-
},
|
|
4369
4296
|
E1524_E1810_levelctrl: {
|
|
4370
4297
|
cluster: 'genLevelCtrl',
|
|
4371
4298
|
type: [
|
package/converters/toZigbee.js
CHANGED
|
@@ -1922,71 +1922,6 @@ const converters = {
|
|
|
1922
1922
|
await entity.read('genBasic', [0x0033], manufacturerOptions.hue);
|
|
1923
1923
|
},
|
|
1924
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
|
-
},
|
|
1990
1925
|
RTCGQ13LM_motion_sensitivity: {
|
|
1991
1926
|
key: ['motion_sensitivity'],
|
|
1992
1927
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -2032,9 +1967,9 @@ const converters = {
|
|
|
2032
1967
|
xiaomi_switch_power_outage_memory: {
|
|
2033
1968
|
key: ['power_outage_memory'],
|
|
2034
1969
|
convertSet: async (entity, key, value, meta) => {
|
|
2035
|
-
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
1970
|
+
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
2036
1971
|
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG31LM', 'QBCZ15LM', 'QBKG20LM', 'QBKG38LM',
|
|
2037
|
-
'QBKG34LM', 'QBCZ14LM', 'QBKG19LM'].includes(meta.mapped.model)) {
|
|
1972
|
+
'QBKG34LM', 'QBCZ14LM', 'QBKG19LM', 'QBKG40LM', 'QBKG41LM'].includes(meta.mapped.model)) {
|
|
2038
1973
|
await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
|
|
2039
1974
|
} else if (['ZNCZ02LM', 'QBCZ11LM'].includes(meta.mapped.model)) {
|
|
2040
1975
|
const payload = value ?
|
|
@@ -2055,9 +1990,9 @@ const converters = {
|
|
|
2055
1990
|
return {state: {power_outage_memory: value}};
|
|
2056
1991
|
},
|
|
2057
1992
|
convertGet: async (entity, key, meta) => {
|
|
2058
|
-
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
1993
|
+
if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
|
|
2059
1994
|
'WS-EUK02', 'WS-EUK01', 'QBKG31LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG20LM', 'QBKG34LM', 'QBKG19LM',
|
|
2060
|
-
'QBKG38LM'].includes(meta.mapped.model)) {
|
|
1995
|
+
'QBKG38LM', 'QBKG40LM', 'QBKG41LM'].includes(meta.mapped.model)) {
|
|
2061
1996
|
await entity.read('aqaraOpple', [0x0201]);
|
|
2062
1997
|
} else if (['ZNCZ02LM', 'QBCZ11LM', 'ZNCZ11LM'].includes(meta.mapped.model)) {
|
|
2063
1998
|
await entity.read('aqaraOpple', [0xFFF0]);
|
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
|
},
|
package/devices/osram.js
CHANGED
|
@@ -30,6 +30,14 @@ module.exports = [
|
|
|
30
30
|
extend: extend.ledvance.light_onoff_brightness_colortemp_color(),
|
|
31
31
|
ota: ota.ledvance,
|
|
32
32
|
},
|
|
33
|
+
{
|
|
34
|
+
zigbeeModel: ['LIGHTIFY RT RGBW'],
|
|
35
|
+
model: '73741_LIGHTIFY',
|
|
36
|
+
vendor: 'OSRAM',
|
|
37
|
+
description: 'LIGHTIFY RT5/6 LED',
|
|
38
|
+
extend: extend.ledvance.light_onoff_brightness_colortemp_color(),
|
|
39
|
+
ota: ota.ledvance,
|
|
40
|
+
},
|
|
33
41
|
{
|
|
34
42
|
zigbeeModel: ['Classic A60 RGBW'],
|
|
35
43
|
model: 'AA69697',
|
package/devices/philips.js
CHANGED
|
@@ -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',
|
|
@@ -1058,6 +1067,15 @@ module.exports = [
|
|
|
1058
1067
|
extend: hueExtend.light_onoff_brightness_colortemp_color(),
|
|
1059
1068
|
ota: ota.zigbeeOTA,
|
|
1060
1069
|
},
|
|
1070
|
+
{
|
|
1071
|
+
zigbeeModel: ['4090231P9'],
|
|
1072
|
+
model: '4090231P9',
|
|
1073
|
+
vendor: 'Philips',
|
|
1074
|
+
description: 'Hue Liane',
|
|
1075
|
+
meta: {turnsOffAtBrightness1: true},
|
|
1076
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1077
|
+
ota: ota.zigbeeOTA,
|
|
1078
|
+
},
|
|
1061
1079
|
{
|
|
1062
1080
|
zigbeeModel: ['LTC001'],
|
|
1063
1081
|
model: '3261030P7',
|
|
@@ -1306,7 +1324,7 @@ module.exports = [
|
|
|
1306
1324
|
vendor: 'Philips',
|
|
1307
1325
|
description: 'Hue Iris (generation 2, black)',
|
|
1308
1326
|
meta: {turnsOffAtBrightness1: true},
|
|
1309
|
-
extend: hueExtend.
|
|
1327
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1310
1328
|
ota: ota.zigbeeOTA,
|
|
1311
1329
|
},
|
|
1312
1330
|
{
|
|
@@ -1408,6 +1426,15 @@ module.exports = [
|
|
|
1408
1426
|
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1409
1427
|
ota: ota.zigbeeOTA,
|
|
1410
1428
|
},
|
|
1429
|
+
{
|
|
1430
|
+
zigbeeModel: ['LCT020'],
|
|
1431
|
+
model: '4080148P7',
|
|
1432
|
+
vendor: 'Philips',
|
|
1433
|
+
description: 'Hue Signe table light',
|
|
1434
|
+
meta: {turnsOffAtBrightness1: true},
|
|
1435
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1436
|
+
ota: ota.zigbeeOTA,
|
|
1437
|
+
},
|
|
1411
1438
|
{
|
|
1412
1439
|
zigbeeModel: ['4080148P9'],
|
|
1413
1440
|
model: '4080148P9',
|
|
@@ -2104,7 +2131,7 @@ module.exports = [
|
|
|
2104
2131
|
vendor: 'Philips',
|
|
2105
2132
|
description: 'Hue Play gradient lightstrip 65',
|
|
2106
2133
|
meta: {turnsOffAtBrightness1: true},
|
|
2107
|
-
extend: hueExtend.
|
|
2134
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
2108
2135
|
ota: ota.zigbeeOTA,
|
|
2109
2136
|
},
|
|
2110
2137
|
{
|
|
@@ -2314,4 +2341,13 @@ module.exports = [
|
|
|
2314
2341
|
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
2315
2342
|
ota: ota.zigbeeOTA,
|
|
2316
2343
|
},
|
|
2344
|
+
{
|
|
2345
|
+
zigbeeModel: ['LTA005'],
|
|
2346
|
+
model: '8719514392830',
|
|
2347
|
+
vendor: 'Philips',
|
|
2348
|
+
description: 'Hue White Ambiance E27 filament screw globe',
|
|
2349
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2350
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [222, 454]}),
|
|
2351
|
+
ota: ota.zigbeeOTA,
|
|
2352
|
+
},
|
|
2317
2353
|
];
|
package/devices/tuya.js
CHANGED
|
@@ -1014,11 +1014,15 @@ module.exports = [
|
|
|
1014
1014
|
.withDescription('Recover state after power outage')],
|
|
1015
1015
|
},
|
|
1016
1016
|
{
|
|
1017
|
-
fingerprint: [
|
|
1018
|
-
{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
|
+
],
|
|
1019
1022
|
model: 'TS011F_plug_3',
|
|
1020
1023
|
description: 'Smart plug (with power monitoring by polling)',
|
|
1021
1024
|
vendor: 'TuYa',
|
|
1025
|
+
whiteLabel: [{vendor: 'VIKEFON', model: 'TS011F'}],
|
|
1022
1026
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
|
|
1023
1027
|
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
1024
1028
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/devices/xiaomi.js
CHANGED
|
@@ -116,7 +116,7 @@ module.exports = [
|
|
|
116
116
|
model: 'JWDL001A',
|
|
117
117
|
vendor: 'Xiaomi',
|
|
118
118
|
description: 'Aqara embedded spot led light',
|
|
119
|
-
extend: xiaomiExtend.light_onoff_brightness_colortemp(),
|
|
119
|
+
extend: xiaomiExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
122
|
zigbeeModel: ['lumi.sensor_switch'],
|
|
@@ -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