zigbee-herdsman-converters 14.0.392 → 14.0.396

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.
@@ -699,6 +699,8 @@ const converters = {
699
699
  */
700
700
  cluster: 'haElectricalMeasurement',
701
701
  type: ['attributeReport', 'readResponse'],
702
+ options: [exposes.options.calibration('power', 'percentual'), exposes.options.calibration('current', 'percentual'),
703
+ exposes.options.calibration('voltage', 'percentual')],
702
704
  convert: (model, msg, publish, options, meta) => {
703
705
  const getFactor = (key) => {
704
706
  const multiplier = msg.endpoint.getClusterAttributeValue('haElectricalMeasurement', `${key}Multiplier`);
@@ -724,7 +726,8 @@ const converters = {
724
726
  if (msg.data.hasOwnProperty(entry.key)) {
725
727
  const factor = getFactor(entry.factor);
726
728
  const property = postfixWithEndpointName(entry.name, msg, model);
727
- payload[property] = precisionRound(msg.data[entry.key] * factor, 2);
729
+ const value = msg.data[entry.key] * factor;
730
+ payload[property] = calibrateAndPrecisionRoundOptions(value, options, entry.name);
728
731
  }
729
732
  }
730
733
  return payload;
@@ -2502,8 +2505,9 @@ const converters = {
2502
2505
  cluster: 'manuSpecificTuya',
2503
2506
  type: ['commandDataReport', 'commandDataResponse'],
2504
2507
  convert: (model, msg, publish, options, meta) => {
2505
- const dp = msg.data.dp;
2506
- const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
2508
+ const dpValue = tuya.firstDpValue(msg, meta, 'neo_alarm');
2509
+ const dp = dpValue.dp;
2510
+ const value = tuya.getDataValue(dpValue);
2507
2511
 
2508
2512
  switch (dp) {
2509
2513
  case tuya.dataPoints.neoAOAlarm: // 0x13 [TRUE,FALSE]
@@ -7757,6 +7761,31 @@ const converters = {
7757
7761
  return result;
7758
7762
  },
7759
7763
  },
7764
+ matsee_garage_door_opener: {
7765
+ cluster: 'manuSpecificTuya',
7766
+ type: ['commandDataReport', 'raw'],
7767
+ convert: (model, msg, publish, options, meta) => {
7768
+ const result = {};
7769
+ for (const dpValue of msg.data.dpValues) {
7770
+ const value = tuya.getDataValue(dpValue);
7771
+ switch (dpValue.dp) {
7772
+ case tuya.dataPoints.garageDoorTrigger:
7773
+ result.action = 'trigger';
7774
+ break;
7775
+ case tuya.dataPoints.garageDoorContact:
7776
+ result.garage_door_contact = Boolean(!value);
7777
+ break;
7778
+ case tuya.dataPoints.garageDoorStatus:
7779
+ // This reports a garage door status (open, closed), but it is very naive and misleading
7780
+ break;
7781
+ default:
7782
+ meta.logger.debug(`zigbee-herdsman-converters:matsee_garage_door_opener: NOT RECOGNIZED ` +
7783
+ `DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
7784
+ }
7785
+ }
7786
+ return result;
7787
+ },
7788
+ },
7760
7789
  moes_thermostat_tv: {
7761
7790
  cluster: 'manuSpecificTuya',
7762
7791
  type: ['commandDataResponse', 'commandDataReport', 'raw'],
@@ -2333,6 +2333,12 @@ const converters = {
2333
2333
  tuya.sendDataPointRaw(entity, tuya.dataPoints.lidlTimer, tuya.convertDecimalValueTo4ByteHexArray(value));
2334
2334
  },
2335
2335
  },
2336
+ matsee_garage_door_opener: {
2337
+ key: ['trigger'],
2338
+ convertSet: (entity, key, value, meta) => {
2339
+ tuya.sendDataPointBool(entity, tuya.dataPoints.garageDoorTrigger, true);
2340
+ },
2341
+ },
2336
2342
  SPZ01_power_outage_memory: {
2337
2343
  key: ['power_outage_memory'],
2338
2344
  convertSet: async (entity, key, value, meta) => {
@@ -5090,7 +5096,7 @@ const converters = {
5090
5096
  await tuya.sendDataPointEnum(
5091
5097
  entity,
5092
5098
  tuya.dataPoints.neoAOVolume,
5093
- {'low': 2, 'medium': 1, 'high': 0}[value]);
5099
+ {'low': 0, 'medium': 1, 'high': 2}[value]);
5094
5100
  break;
5095
5101
  case 'duration':
5096
5102
  await tuya.sendDataPointValue(entity, tuya.dataPoints.neoAODuration, value);
@@ -332,4 +332,25 @@ module.exports = [
332
332
  },
333
333
  exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
334
334
  },
335
+ {
336
+ zigbeeModel: ['EFEKTA_PWS_MaxPro'],
337
+ model: 'EFEKTA_PWS_MaxPro',
338
+ vendor: 'Custom devices (DiY)',
339
+ description: '[Plant watering sensor EFEKTA PWS Max Pro, long battery life](http://efektalab.com/PWS_MaxPro)',
340
+ fromZigbee: [fz.temperature, fz.humidity, fz.illuminance, fz.soil_moisture, fz.battery],
341
+ toZigbee: [tz.factory_reset],
342
+ configure: async (device, coordinatorEndpoint, logger) => {
343
+ const firstEndpoint = device.getEndpoint(1);
344
+ await reporting.bind(firstEndpoint, coordinatorEndpoint, [
345
+ 'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity', 'msIlluminanceMeasurement', 'msSoilMoisture']);
346
+ const overides = {min: 0, max: 21600, change: 0};
347
+ await reporting.batteryVoltage(firstEndpoint, overides);
348
+ await reporting.batteryPercentageRemaining(firstEndpoint, overides);
349
+ await reporting.temperature(firstEndpoint, overides);
350
+ await reporting.humidity(firstEndpoint, overides);
351
+ await reporting.illuminance(firstEndpoint, overides);
352
+ await reporting.soil_moisture(firstEndpoint, overides);
353
+ },
354
+ exposes: [e.soil_moisture(), e.battery(), e.illuminance(), e.temperature(), e.humidity()],
355
+ },
335
356
  ];
@@ -5,6 +5,7 @@ const reporting = require('../lib/reporting');
5
5
  const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
7
  const ea = exposes.access;
8
+ const ota = require('../lib/ota');
8
9
 
9
10
  const readInitialBatteryState = async (type, data, device) => {
10
11
  if (['deviceAnnounce'].includes(type)) {
@@ -63,6 +64,7 @@ module.exports = [
63
64
  fromZigbee: [fz.identify, fz.ignore_basic_report, fz.command_cover_open, fz.command_cover_close, fz.command_cover_stop, fz.battery,
64
65
  fz.legrand_binary_input_moving],
65
66
  toZigbee: [],
67
+ ota: ota.zigbeeOTA,
66
68
  exposes: [e.battery(), e.action(['identify', 'open', 'close', 'stop', 'moving', 'stopped'])],
67
69
  configure: async (device, coordinatorEndpoint, logger) => {
68
70
  const endpoint = device.getEndpoint(1);
@@ -182,6 +184,7 @@ module.exports = [
182
184
  zigbeeModel: [' Connected outlet\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
183
185
  model: '067775/741811',
184
186
  vendor: 'Legrand',
187
+ ota: ota.zigbeeOTA,
185
188
  description: 'Power socket with power consumption monitoring',
186
189
  fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
187
190
  toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_identify],
@@ -200,6 +203,7 @@ module.exports = [
200
203
  vendor: 'Legrand',
201
204
  description: 'Wired micromodule switch',
202
205
  extend: extend.switch(),
206
+ ota: ota.zigbeeOTA,
203
207
  fromZigbee: [fz.identify, fz.on_off],
204
208
  toZigbee: [tz.on_off, tz.legrand_identify],
205
209
  configure: async (device, coordinatorEndpoint, logger) => {
package/devices/lidl.js CHANGED
@@ -394,7 +394,7 @@ module.exports = [
394
394
  },
395
395
  {
396
396
  fingerprint: [{modelID: 'TY0202', manufacturerName: '_TZ1800_fcdjzz3s'}],
397
- model: 'HG06335',
397
+ model: 'HG06335/HG07310',
398
398
  vendor: 'Lidl',
399
399
  description: 'Silvercrest smart motion sensor',
400
400
  fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery],
@@ -0,0 +1,31 @@
1
+ const fz = require('../converters/fromZigbee');
2
+ const exposes = require('../lib/exposes');
3
+ const reporting = require('../lib/reporting');
4
+ const extend = require('../lib/extend');
5
+ const e = exposes.presets;
6
+ const ea = exposes.access;
7
+
8
+
9
+ module.exports = [
10
+ {
11
+ zigbeeModel: ['SZ1000'],
12
+ model: 'ZB250',
13
+ vendor: 'Micro Matic Norge AS',
14
+ description: 'Zigbee dimmer for LED',
15
+ fromZigbee: extend.light_onoff_brightness().fromZigbee.concat([fz.electrical_measurement, fz.metering]),
16
+ toZigbee: extend.light_onoff_brightness().toZigbee,
17
+ configure: async (device, coordinatorEndpoint, logger) => {
18
+ await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
19
+ const endpoint = device.getEndpoint(1);
20
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'haElectricalMeasurement', 'seMetering']);
21
+ await reporting.brightness(endpoint);
22
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
23
+ await reporting.rmsVoltage(endpoint, {min: 10, change: 20}); // Voltage - Min change of 2V
24
+ await reporting.rmsCurrent(endpoint, {min: 10, change: 10}); // A - z2m displays only the first decimals, change of 10 / 0,01A
25
+ await reporting.activePower(endpoint, {min: 10, change: 15}); // W - Min change of 1,5W
26
+ await reporting.currentSummDelivered(endpoint, {min: 300}); // Report KWH every 5min
27
+ },
28
+ exposes: [e.light_brightness(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy()],
29
+ },
30
+ ];
31
+
@@ -29,6 +29,13 @@ const hueExtend = {
29
29
  };
30
30
 
31
31
  module.exports = [
32
+ {
33
+ zigbeeModel: ['929003055801'],
34
+ model: '929003055801',
35
+ vendor: 'Philips',
36
+ description: 'Hue white ambiance bathroom ceiling light Adore with Bluetooth',
37
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
38
+ },
32
39
  {
33
40
  zigbeeModel: ['929003056901'],
34
41
  model: '929003056901',
@@ -261,7 +268,7 @@ module.exports = [
261
268
  ota: ota.zigbeeOTA,
262
269
  },
263
270
  {
264
- zigbeeModel: ['LLC012', 'LLC011'],
271
+ zigbeeModel: ['LLC012', 'LLC011', 'LLC013'],
265
272
  model: '7299760PH',
266
273
  vendor: 'Philips',
267
274
  description: 'Hue Bloom',
@@ -314,6 +321,14 @@ module.exports = [
314
321
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
315
322
  ota: ota.zigbeeOTA,
316
323
  },
324
+ {
325
+ zigbeeModel: ['929003055901'],
326
+ model: '929003055901',
327
+ vendor: 'Philips',
328
+ description: 'Hue white ambiance bathroom ceiling light Adore with Bluetooth',
329
+ extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 454]}),
330
+ ota: ota.zigbeeOTA,
331
+ },
317
332
  {
318
333
  zigbeeModel: ['LLC020'],
319
334
  model: '7146060PH',
@@ -1014,7 +1029,7 @@ module.exports = [
1014
1029
  ota: ota.zigbeeOTA,
1015
1030
  },
1016
1031
  {
1017
- zigbeeModel: ['3417931P6'],
1032
+ zigbeeModel: ['3417931P6', '929003056201'],
1018
1033
  model: '3417931P6',
1019
1034
  vendor: 'Philips',
1020
1035
  description: 'Hue white ambiance Adore GU10 with Bluetooth (2 spots)',
@@ -1203,7 +1218,7 @@ module.exports = [
1203
1218
  ota: ota.zigbeeOTA,
1204
1219
  },
1205
1220
  {
1206
- zigbeeModel: ['3261031P6', '929003055001'],
1221
+ zigbeeModel: ['3261031P6', '929003055001', '929003055101'],
1207
1222
  model: '3261031P6',
1208
1223
  vendor: 'Philips',
1209
1224
  description: 'Hue Being white',
@@ -1337,7 +1352,7 @@ module.exports = [
1337
1352
  ota: ota.zigbeeOTA,
1338
1353
  },
1339
1354
  {
1340
- zigbeeModel: ['929003099001'],
1355
+ zigbeeModel: ['929003099001', '929003099201'],
1341
1356
  model: '929003099001',
1342
1357
  vendor: 'Philips',
1343
1358
  description: 'Hue white ambiance Aurelle square panel light',
@@ -2645,4 +2660,13 @@ module.exports = [
2645
2660
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2646
2661
  ota: ota.zigbeeOTA,
2647
2662
  },
2663
+ {
2664
+ zigbeeModel: ['3417611P6', '3417511P9'],
2665
+ model: '3417511P9',
2666
+ vendor: 'Philips',
2667
+ description: 'Hue white ambiance bathroom recessed downlight Adore with Bluetooth',
2668
+ meta: {turnsOffAtBrightness1: true},
2669
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2670
+ ota: ota.zigbeeOTA,
2671
+ },
2648
2672
  ];
@@ -0,0 +1,20 @@
1
+ const reporting = require('../lib/reporting');
2
+ const extend = require('../lib/extend');
3
+
4
+ module.exports = [
5
+ {
6
+ zigbeeModel: ['12501'],
7
+ model: '12501',
8
+ vendor: 'Scan Products',
9
+ description: 'Zigbee push dimmer',
10
+ fromZigbee: extend.light_onoff_brightness().fromZigbee,
11
+ toZigbee: extend.light_onoff_brightness().toZigbee,
12
+ extend: extend.light_onoff_brightness({noConfigure: true}),
13
+ configure: async (device, coordinatorEndpoint, logger) => {
14
+ await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
15
+ const endpoint = device.getEndpoint(1);
16
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
17
+ await reporting.onOff(endpoint);
18
+ },
19
+ },
20
+ ];
@@ -46,7 +46,7 @@ module.exports = [
46
46
  toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
47
47
  exposes: [
48
48
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
49
- ea.STATE_SET).withColor('hs'),
49
+ ea.STATE_SET).withColor(['hs']),
50
50
  ],
51
51
  },
52
52
  {
@@ -61,7 +61,7 @@ module.exports = [
61
61
  toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
62
62
  exposes: [
63
63
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
64
- ea.STATE_SET).withColor('hs'),
64
+ ea.STATE_SET).withColor(['hs']),
65
65
  exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
66
66
  'White brightness of this light'),
67
67
  ],
@@ -79,7 +79,7 @@ module.exports = [
79
79
  toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
80
80
  exposes: [
81
81
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
82
- ea.STATE_SET).withColor('hs').withColorTemp([250, 454]).setAccess('color_temp',
82
+ ea.STATE_SET).withColor(['hs']).withColorTemp([250, 454]).setAccess('color_temp',
83
83
  ea.STATE_SET),
84
84
  exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
85
85
  'White brightness of this light'),
package/devices/tuya.js CHANGED
@@ -206,7 +206,8 @@ module.exports = [
206
206
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
207
207
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
208
208
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'},
209
- {modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'}],
209
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'},
210
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_e5t9bfdv'}],
210
211
  model: 'TS0501B',
211
212
  description: 'Zigbee light',
212
213
  vendor: 'TuYa',
@@ -509,6 +510,7 @@ module.exports = [
509
510
  {modelID: 'TS0502B', manufacturerName: '_TZ3000_zw7wr5uo'},
510
511
  {modelID: 'TS0502B', manufacturerName: '_TZ3210_pz9zmxjj'},
511
512
  {modelID: 'TS0502B', manufacturerName: '_TZ3000_fzwhym79'},
513
+ {modelID: 'TS0502B', manufacturerName: '_TZ3210_rm0hthdo'},
512
514
  ],
513
515
  model: 'TS0502B',
514
516
  vendor: 'TuYa',
@@ -1288,7 +1290,7 @@ module.exports = [
1288
1290
  exposes: [e.humidity(), e.temperature(), e.battery()],
1289
1291
  },
1290
1292
  {
1291
- fingerprint: [{modelID: 'TS0011', manufacturerName: '_TZ3000_l8fsgo6p'}, {modelID: 'TS0011', manufacturerName: '_TZ3000_ji4araar'}],
1293
+ fingerprint: [{modelID: 'TS0011', manufacturerName: '_TZ3000_l8fsgo6p'}],
1292
1294
  zigbeeModel: ['TS0011'],
1293
1295
  model: 'TS0011',
1294
1296
  vendor: 'TuYa',
@@ -1309,7 +1311,7 @@ module.exports = [
1309
1311
  },
1310
1312
  {
1311
1313
  fingerprint: [{modelID: 'TS0011', manufacturerName: '_TZ3000_qmi1cfuq'},
1312
- {modelID: 'TS0011', manufacturerName: '_TZ3000_txpirhfq'}],
1314
+ {modelID: 'TS0011', manufacturerName: '_TZ3000_txpirhfq'}, {modelID: 'TS0011', manufacturerName: '_TZ3000_ji4araar'}],
1313
1315
  model: 'TS0011_switch_module',
1314
1316
  vendor: 'TuYa',
1315
1317
  description: '1 gang switch module - (without neutral)',
@@ -1664,6 +1666,21 @@ module.exports = [
1664
1666
  e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
1665
1667
  .withDescription('Recover state after power outage')],
1666
1668
  },
1669
+ {
1670
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_nklqjk62'}],
1671
+ model: 'PJ-ZGD01',
1672
+ vendor: 'TuYa',
1673
+ description: 'Garage door opener',
1674
+ fromZigbee: [fz.matsee_garage_door_opener, fz.ignore_basic_report],
1675
+ toZigbee: [tz.matsee_garage_door_opener, tz.tuya_data_point_test],
1676
+ whiteLabel: [{vendor: 'MatSee Plus', model: 'PJ-ZGD01'}],
1677
+ configure: async (device, coordinatorEndpoint, logger) => {
1678
+ const endpoint = device.getEndpoint(1);
1679
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
1680
+ },
1681
+ exposes: [exposes.binary('trigger', ea.STATE_SET, true, false).withDescription('Trigger the door movement'),
1682
+ e.action(['trigger']), exposes.binary('garage_door_contact', ea.STATE, true, false)],
1683
+ },
1667
1684
  {
1668
1685
  fingerprint: [{modelID: 'TS0201', manufacturerName: '_TZ3000_qaaysllp'}],
1669
1686
  model: 'LCZ030',
@@ -22,6 +22,24 @@ module.exports = [
22
22
  return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5};
23
23
  },
24
24
  },
25
+ {
26
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cfnprab5'}],
27
+ model: 'SM-0306E-2W',
28
+ vendor: 'UseeLink',
29
+ description: '4 gang switch, with USB',
30
+ exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
31
+ e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5')],
32
+ extend: extend.switch(),
33
+ meta: {multiEndpoint: true},
34
+ configure: async (device, coordinatorEndpoint, logger) => {
35
+ for (const ID of [1, 2, 3, 4, 5]) {
36
+ await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ['genOnOff']);
37
+ }
38
+ },
39
+ endpoint: (device) => {
40
+ return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5};
41
+ },
42
+ },
25
43
  {
26
44
  fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_tvuarksa'}],
27
45
  model: 'SM-AZ713',
package/devices/xiaomi.js CHANGED
@@ -1448,6 +1448,7 @@ module.exports = [
1448
1448
  await reporting.onOff(endpoint);
1449
1449
  await reporting.deviceTemperature(endpoint);
1450
1450
  device.powerSource = 'Mains (single phase)';
1451
+ device.type = 'Router';
1451
1452
  device.save();
1452
1453
  },
1453
1454
  },
@@ -1654,6 +1655,7 @@ module.exports = [
1654
1655
  const payload = reporting.payload('presentValue', 10, constants.repInterval.HOUR, 5);
1655
1656
  await endpoint.configureReporting('genAnalogInput', payload);
1656
1657
  },
1658
+ ota: ota.zigbeeOTA,
1657
1659
  },
1658
1660
  {
1659
1661
  zigbeeModel: ['lumi.switch.b2nc01'],
package/lib/exposes.js CHANGED
@@ -294,20 +294,22 @@ class Light extends Base {
294
294
 
295
295
  withColor(types) {
296
296
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
297
- if (types.includes('xy')) {
298
- const colorXY = new Composite('color_xy', 'color')
299
- .withFeature(new Numeric('x', access.ALL))
300
- .withFeature(new Numeric('y', access.ALL))
301
- .withDescription('Color of this light in the CIE 1931 color space (x/y)');
302
- this.features.push(colorXY);
303
- }
304
-
305
- if (types.includes('hs')) {
306
- const colorHS = new Composite('color_hs', 'color')
307
- .withFeature(new Numeric('hue', access.ALL))
308
- .withFeature(new Numeric('saturation', access.ALL))
309
- .withDescription('Color of this light expressed as hue/saturation');
310
- this.features.push(colorHS);
297
+ for (const type of types) {
298
+ if (type === 'xy') {
299
+ const colorXY = new Composite('color_xy', 'color')
300
+ .withFeature(new Numeric('x', access.ALL))
301
+ .withFeature(new Numeric('y', access.ALL))
302
+ .withDescription('Color of this light in the CIE 1931 color space (x/y)');
303
+ this.features.push(colorXY);
304
+ } else if (type === 'hs') {
305
+ const colorHS = new Composite('color_hs', 'color')
306
+ .withFeature(new Numeric('hue', access.ALL))
307
+ .withFeature(new Numeric('saturation', access.ALL))
308
+ .withDescription('Color of this light expressed as hue/saturation');
309
+ this.features.push(colorHS);
310
+ } else {
311
+ assert(false, `Unsupported color type ${type}`);
312
+ }
311
313
  }
312
314
 
313
315
  return this;
@@ -547,10 +549,10 @@ module.exports = {
547
549
  keypad_lockout: () => new Enum('keypad_lockout', access.ALL, ['unlock', 'lock1', 'lock2']).withDescription('Enables/disables physical input on the device'),
548
550
  led_disabled_night: () => new Binary('led_disabled_night', access.ALL, true, false).withDescription('Enable/disable the LED at night'),
549
551
  light_brightness: () => new Light().withBrightness(),
550
- light_brightness_color: () => new Light().withBrightness().withColor((['xy', 'hs'])),
552
+ light_brightness_color: (preferHS) => new Light().withBrightness().withColor((preferHS ? ['hs', 'xy'] : ['xy', 'hs'])),
551
553
  light_brightness_colorhs: () => new Light().withBrightness().withColor(['hs']),
552
554
  light_brightness_colortemp: (colorTempRange) => new Light().withBrightness().withColorTemp(colorTempRange).withColorTempStartup(colorTempRange),
553
- light_brightness_colortemp_color: (colorTempRange) => new Light().withBrightness().withColorTemp(colorTempRange).withColorTempStartup(colorTempRange).withColor(['xy', 'hs']),
555
+ light_brightness_colortemp_color: (colorTempRange, preferHS) => new Light().withBrightness().withColorTemp(colorTempRange).withColorTempStartup(colorTempRange).withColor(preferHS ? ['hs', 'xy'] : ['xy', 'hs']),
554
556
  light_brightness_colortemp_colorhs: (colorTempRange) => new Light().withBrightness().withColorTemp(colorTempRange).withColorTempStartup(colorTempRange).withColor(['hs']),
555
557
  light_brightness_colortemp_colorxy: (colorTempRange) => new Light().withBrightness().withColorTemp(colorTempRange).withColorTempStartup(colorTempRange).withColor(['xy']),
556
558
  light_brightness_colorxy: () => new Light().withBrightness().withColor((['xy'])),
package/lib/extend.js CHANGED
@@ -50,8 +50,8 @@ const extend = {
50
50
  return result;
51
51
  },
52
52
  light_onoff_brightness_color: (options={}) => {
53
- options = {disableEffect: false, supportsHS: false, ...options};
54
- const exposes = [(options.supportsHS ? e.light_brightness_color() : e.light_brightness_colorxy()),
53
+ options = {disableEffect: false, supportsHS: false, preferHS: false, ...options};
54
+ const exposes = [(options.supportsHS ? e.light_brightness_color(options.preferHS) : e.light_brightness_colorxy()),
55
55
  ...(!options.disableEffect ? [e.effect()] : [])];
56
56
  const fromZigbee = [fz.color_colortemp, fz.on_off, fz.brightness, fz.level_config, fz.power_on_behavior, fz.ignore_basic_report];
57
57
  const toZigbee = [tz.light_onoff_brightness, tz.light_color, tz.ignore_transition, tz.ignore_rate, tz.light_brightness_move,
@@ -66,8 +66,8 @@ const extend = {
66
66
  };
67
67
  },
68
68
  light_onoff_brightness_colortemp_color: (options={}) => {
69
- options = {disableEffect: false, supportsHS: false, disableColorTempStartup: false, ...options};
70
- const exposes = [(options.supportsHS ? e.light_brightness_colortemp_color(options.colorTempRange) :
69
+ options = {disableEffect: false, supportsHS: false, disableColorTempStartup: false, preferHS: false, ...options};
70
+ const exposes = [(options.supportsHS ? e.light_brightness_colortemp_color(options.colorTempRange, options.preferHS) :
71
71
  e.light_brightness_colortemp_colorxy(options.colorTempRange)), ...(!options.disableEffect ? [e.effect()] : [])];
72
72
  const fromZigbee = [fz.color_colortemp, fz.on_off, fz.brightness, fz.level_config, fz.power_on_behavior, fz.ignore_basic_report];
73
73
  const toZigbee = [
package/lib/tuya.js CHANGED
@@ -571,6 +571,10 @@ const dataPoints = {
571
571
  AM02Border: 16,
572
572
  AM02MotorWorkingMode: 20,
573
573
  AM02AddRemoter: 101,
574
+ // Matsee Tuya Garage Door Opener
575
+ garageDoorTrigger: 1,
576
+ garageDoorContact: 3,
577
+ garageDoorStatus: 12,
574
578
  };
575
579
 
576
580
  const thermostatWeekFormat = {
package/lib/utils.js CHANGED
@@ -72,12 +72,12 @@ 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: 0};
75
+ const defaultPrecision = {temperature: 2, humidity: 2, pressure: 1, pm25: 0, power: 2, voltage: 2, current: 2};
76
76
  function calibrateAndPrecisionRoundOptions(number, options, type) {
77
77
  // Calibrate
78
78
  const calibrateKey = `${type}_calibration`;
79
79
  let calibrationOffset = options && options.hasOwnProperty(calibrateKey) ? options[calibrateKey] : 0;
80
- if (type == 'illuminance' || type === 'illuminance_lux') {
80
+ if (['illuminance', 'illuminance_lux', 'power', 'current', 'voltage'].includes(type)) {
81
81
  // linear calibration because measured value is zero based
82
82
  // +/- percent
83
83
  calibrationOffset = Math.round(number * calibrationOffset / 100);