zigbee-herdsman-converters 14.0.317 → 14.0.321

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.
@@ -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,14 +4293,16 @@ const converters = {
4295
4293
  }
4296
4294
  },
4297
4295
  },
4298
- ikea_pm25: {
4299
- cluster: 'manuSpecificIkeaPM25Measurement',
4296
+ ikea_air_purifier: {
4297
+ cluster: 'manuSpecificIkeaAirPurifier',
4300
4298
  type: ['attributeReport', 'readResponse'],
4301
4299
  options: [exposes.options.precision('pm25'), exposes.options.calibration('pm25')],
4302
4300
  convert: (model, msg, publish, options, meta) => {
4303
- if (msg.data['measuredValue']) {
4304
- const pm25 = parseFloat(msg.data['measuredValue']) / 100.0;
4301
+ const state = {};
4302
+
4303
+ if (msg.data.hasOwnProperty('particulateMatter25Measurement')) {
4305
4304
  const pm25Property = postfixWithEndpointName('pm25', msg, model);
4305
+ let pm25 = parseFloat(msg.data['particulateMatter25Measurement']);
4306
4306
 
4307
4307
  // Air Quality Scale (ikea app):
4308
4308
  // 0-35=Good, 35-80=OK, 80+=Not Good
@@ -4318,8 +4318,52 @@ const converters = {
4318
4318
  airQuality = 'unknown';
4319
4319
  }
4320
4320
 
4321
- return {[pm25Property]: calibrateAndPrecisionRoundOptions(pm25, options, 'pm25'), [airQualityProperty]: airQuality};
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;
4322
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;
4323
4367
  },
4324
4368
  },
4325
4369
  E1524_E1810_levelctrl: {
@@ -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,10 +1922,69 @@ const converters = {
1911
1922
  await entity.read('genBasic', [0x0033], manufacturerOptions.hue);
1912
1923
  },
1913
1924
  },
1914
- ikea_pm25: {
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: {
1915
1958
  key: ['pm25', 'air_quality'],
1916
1959
  convertGet: async (entity, key, meta) => {
1917
- await entity.read('manuSpecificIkeaPM25Measurement', ['measuredValue']);
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']);
1918
1988
  },
1919
1989
  },
1920
1990
  RTCGQ13LM_motion_sensitivity: {
@@ -1962,7 +2032,7 @@ const converters = {
1962
2032
  xiaomi_switch_power_outage_memory: {
1963
2033
  key: ['power_outage_memory'],
1964
2034
  convertSet: async (entity, key, value, meta) => {
1965
- if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
2035
+ if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
1966
2036
  'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG31LM', 'QBCZ15LM', 'QBKG20LM', 'QBKG38LM',
1967
2037
  'QBKG34LM', 'QBCZ14LM', 'QBKG19LM'].includes(meta.mapped.model)) {
1968
2038
  await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
@@ -1985,7 +2055,7 @@ const converters = {
1985
2055
  return {state: {power_outage_memory: value}};
1986
2056
  },
1987
2057
  convertGet: async (entity, key, meta) => {
1988
- if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
2058
+ if (['ZNCZ04LM', 'QBKG25LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM', 'QBKG39LM', 'QBKG41LM', 'ZNCZ15LM',
1989
2059
  'WS-EUK02', 'WS-EUK01', 'QBKG31LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG20LM', 'QBKG34LM', 'QBKG19LM',
1990
2060
  'QBKG38LM'].includes(meta.mapped.model)) {
1991
2061
  await entity.read('aqaraOpple', [0x0201]);
@@ -2770,6 +2840,25 @@ const converters = {
2770
2840
  await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSminTempSet, temp);
2771
2841
  },
2772
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
+ },
2773
2862
  tvtwo_thermostat: {
2774
2863
  key: [
2775
2864
  'window_detection', 'frost_protection', 'child_lock',
@@ -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
@@ -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;
@@ -626,19 +627,44 @@ module.exports = [
626
627
  vendor: 'IKEA',
627
628
  description: 'STARKVIND air purifier',
628
629
  exposes: [
629
- e.fan().withModes(['off', 'low', 'medium', 'high', 'auto']),
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'),
630
633
  e.pm25().withAccess(ea.STATE_GET),
631
634
  exposes.enum('air_quality', ea.STATE_GET, [
632
635
  'good', 'ok', 'not_good', 'unknown',
633
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'),
634
641
  ],
635
642
  meta: {fanStateOn: 'auto'},
636
- fromZigbee: [fz.fan, fz.ikea_pm25],
637
- toZigbee: [tz.fan_mode, tz.ikea_pm25],
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
+ ],
638
649
  configure: async (device, coordinatorEndpoint, logger) => {
650
+ const options = {manufacturerCode: 0x117c};
639
651
  const endpoint = device.getEndpoint(1);
640
- await reporting.bind(endpoint, coordinatorEndpoint, ['hvacFanCtrl']);
641
- await reporting.fanMode(endpoint);
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']);
642
668
  },
643
669
  },
644
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
+ ];
@@ -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',
@@ -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/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.composite('programming_mode').withDescription('PROGRAMMING MODE ⏱ - In this mode, ' +
222
- 'the device executes a preset week programming temperature time and temperature. ')
223
- .withFeature(exposes.text('program_weekday', ea.STATE))
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'),
@@ -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',
@@ -1936,6 +1936,15 @@ module.exports = [
1936
1936
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
1937
1937
  ota: ota.zigbeeOTA,
1938
1938
  },
1939
+ {
1940
+ zigbeeModel: ['1741730V7'],
1941
+ model: '1741730V7',
1942
+ vendor: 'Philips',
1943
+ description: 'Hue Lily outdoor spot light',
1944
+ meta: {turnsOffAtBrightness1: true},
1945
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
1946
+ ota: ota.zigbeeOTA,
1947
+ },
1939
1948
  {
1940
1949
  zigbeeModel: ['1746730V7'],
1941
1950
  model: '1746730V7',
@@ -2095,7 +2104,7 @@ module.exports = [
2095
2104
  vendor: 'Philips',
2096
2105
  description: 'Hue Play gradient lightstrip 65',
2097
2106
  meta: {turnsOffAtBrightness1: true},
2098
- extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
2107
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2099
2108
  ota: ota.zigbeeOTA,
2100
2109
  },
2101
2110
  {
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'}, {modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'}],
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: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'},
1015
- {modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 69}],
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) => {
@@ -1182,7 +1189,7 @@ module.exports = [
1182
1189
  },
1183
1190
  },
1184
1191
  {
1185
- fingerprint: [{modelID: 'TS0011', manufacturerName: '_TZ3000_jl7qyupf'}],
1192
+ fingerprint: [{modelID: 'TS0011', manufacturerName: '_TZ3000_ji4araar'}],
1186
1193
  model: 'TS0011_switch_module',
1187
1194
  vendor: 'TuYa',
1188
1195
  description: '1 gang switch module - (without neutral)',
@@ -1271,7 +1278,7 @@ module.exports = [
1271
1278
  },
1272
1279
  },
1273
1280
  {
1274
- fingerprint: [{modelID: 'TS0013', manufacturerName: '_TZ3000_jl7qyupf'}],
1281
+ fingerprint: [{modelID: 'TS0013', manufacturerName: '_TZ3000_ypgri8yz'}],
1275
1282
  model: 'TS0013_switch_module',
1276
1283
  vendor: 'TuYa',
1277
1284
  description: '3 gang switch module - (without neutral)',