zigbee-herdsman-converters 14.0.450 → 14.0.453

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.
@@ -674,7 +674,9 @@ const converters = {
674
674
  type: ['attributeReport', 'readResponse'],
675
675
  convert: (model, msg, publish, options, meta) => {
676
676
  const result = converters.metering.convert(model, msg, publish, options, meta);
677
- result.power /= 1000;
677
+ if (result.hasOwnProperty('power')) {
678
+ result.power /= 1000;
679
+ }
678
680
  return result;
679
681
  },
680
682
  },
@@ -4446,8 +4448,9 @@ const converters = {
4446
4448
  const dpValue = tuya.firstDpValue(msg, meta, 'tuya_thermostat');
4447
4449
  const dp = dpValue.dp;
4448
4450
  const value = tuya.getDataValue(dpValue);
4449
-
4450
4451
  switch (dp) {
4452
+ case tuya.dataPoints.windowOpen:
4453
+ return {window_open: value};
4451
4454
  case tuya.dataPoints.windowDetection:
4452
4455
  return {
4453
4456
  window_detection: value[0] ? 'ON' : 'OFF',
@@ -5263,10 +5266,22 @@ const converters = {
5263
5266
  return {power: precisionRound(msg.data['presentValue'], 2)};
5264
5267
  },
5265
5268
  },
5266
- xiaomi_switch_basic: {
5269
+ xiaomi_basic: {
5267
5270
  cluster: 'genBasic',
5268
5271
  type: ['attributeReport', 'readResponse'],
5269
- options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
5272
+ options: (definition) => {
5273
+ const result = [];
5274
+ if (definition.exposes.find((e) => e.name === 'temperature')) {
5275
+ result.push(exposes.options.precision('temperature'), exposes.options.calibration('temperature'));
5276
+ }
5277
+ if (definition.exposes.find((e) => e.name === 'illuminance')) {
5278
+ result.push(exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual'));
5279
+ }
5280
+ if (definition.exposes.find((e) => e.name === 'illuminance_lux')) {
5281
+ result.push(exposes.options.precision('illuminance_lux'), exposes.options.calibration('illuminance_lux', 'percentual'));
5282
+ }
5283
+ return result;
5284
+ },
5270
5285
  convert: (model, msg, publish, options, meta) => {
5271
5286
  const payload = xiaomi.numericAttributes2Payload(msg, meta, model, options, msg.data);
5272
5287
  return payload;
@@ -5309,31 +5324,6 @@ const converters = {
5309
5324
  return payload;
5310
5325
  },
5311
5326
  },
5312
- xiaomi_battery: {
5313
- cluster: 'genBasic',
5314
- type: ['attributeReport', 'readResponse'],
5315
- convert: (model, msg, publish, options, meta) => {
5316
- let voltage = null;
5317
- if (msg.data['65281']) {
5318
- voltage = msg.data['65281']['1'];
5319
- } else if (msg.data['65282']) {
5320
- voltage = msg.data['65282']['1'].elmVal;
5321
- }
5322
-
5323
- if (voltage) {
5324
- const payload = {
5325
- voltage: voltage, // @deprecated
5326
- // voltage: voltage / 1000.0,
5327
- };
5328
-
5329
- if (model.meta && model.meta.battery && model.meta.battery.voltageToPercentage) {
5330
- payload.battery = batteryVoltageToPercentage(payload.voltage, model.meta.battery.voltageToPercentage);
5331
- }
5332
-
5333
- return payload;
5334
- }
5335
- },
5336
- },
5337
5327
  xiaomi_on_off_action: {
5338
5328
  cluster: 'genOnOff',
5339
5329
  type: ['attributeReport'],
@@ -5401,32 +5391,6 @@ const converters = {
5401
5391
  }
5402
5392
  },
5403
5393
  },
5404
- RTCGQ11LM_interval: {
5405
- cluster: 'genBasic',
5406
- type: ['attributeReport', 'readResponse'],
5407
- options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature'),
5408
- exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual'),
5409
- exposes.options.precision('illuminance_lux'), exposes.options.calibration('illuminance_lux', 'percentual')],
5410
- convert: (model, msg, publish, options, meta) => {
5411
- if (msg.data['65281']) {
5412
- const result = {};
5413
- if (msg.data['65281'].hasOwnProperty('11')) {
5414
- const illuminance = msg.data['65281']['11'];
5415
- // DEPRECATED: remove illuminance_lux here.
5416
- result.illuminance = calibrateAndPrecisionRoundOptions(illuminance, options, 'illuminance');
5417
- result.illuminance_lux = calibrateAndPrecisionRoundOptions(illuminance, options, 'illuminance_lux');
5418
- }
5419
-
5420
- if (msg.data['65281'].hasOwnProperty('3')) {
5421
- let temperature = msg.data['65281']['3'];
5422
- temperature = calibrateAndPrecisionRoundOptions(temperature, options, 'temperature');
5423
- result.temperature = temperature;
5424
- }
5425
-
5426
- return result;
5427
- }
5428
- },
5429
- },
5430
5394
  RTCGQ11LM_illuminance: {
5431
5395
  cluster: 'msIlluminanceMeasurement',
5432
5396
  type: ['attributeReport', 'readResponse'],
@@ -5559,27 +5523,6 @@ const converters = {
5559
5523
  return {contact: msg.data['onOff'] === 0};
5560
5524
  },
5561
5525
  },
5562
- xiaomi_contact_interval: {
5563
- cluster: 'genBasic',
5564
- type: ['attributeReport', 'readResponse'],
5565
- options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
5566
- convert: (model, msg, publish, options, meta) => {
5567
- if (msg.data.hasOwnProperty('65281')) {
5568
- const result = {};
5569
- if (msg.data['65281'].hasOwnProperty('100')) {
5570
- result.contact = msg.data['65281']['100'] === 0;
5571
- }
5572
-
5573
- if (msg.data['65281'].hasOwnProperty('3')) {
5574
- let temperature = msg.data['65281']['3'];
5575
- temperature = calibrateAndPrecisionRoundOptions(temperature, options, 'temperature');
5576
- result.temperature = temperature;
5577
- }
5578
-
5579
- return result;
5580
- }
5581
- },
5582
- },
5583
5526
  W2_module_carbon_monoxide: {
5584
5527
  cluster: 'ssIasZone',
5585
5528
  type: 'commandStatusChangeNotification',
@@ -5590,39 +5533,6 @@ const converters = {
5590
5533
  };
5591
5534
  },
5592
5535
  },
5593
- WSDCGQ01LM_WSDCGQ11LM_interval: {
5594
- cluster: 'genBasic',
5595
- type: ['attributeReport', 'readResponse'],
5596
- options: [exposes.options.precision('pressure'), exposes.options.calibration('pressure'),
5597
- exposes.options.precision('temperature'), exposes.options.calibration('temperature'),
5598
- exposes.options.precision('humidity'), exposes.options.calibration('humidity')],
5599
- convert: (model, msg, publish, options, meta) => {
5600
- if (msg.data['65281']) {
5601
- const result = {};
5602
- const temperature = parseFloat(msg.data['65281']['100']) / 100.0;
5603
- const humidity = parseFloat(msg.data['65281']['101']) / 100.0;
5604
-
5605
- // https://github.com/Koenkk/zigbee2mqtt/issues/798
5606
- // Sometimes the sensor publishes non-realistic vales, filter these
5607
- if (temperature > -65 && temperature < 65) {
5608
- result.temperature = calibrateAndPrecisionRoundOptions(temperature, options, 'temperature');
5609
- }
5610
-
5611
- // in the 0 - 100 range, don't produce messages beyond these values.
5612
- if (humidity >= 0 && humidity <= 100) {
5613
- result.humidity = calibrateAndPrecisionRoundOptions(humidity, options, 'humidity');
5614
- }
5615
-
5616
- // Check if contains pressure (WSDCGQ11LM only)
5617
- if (msg.data['65281'].hasOwnProperty('102')) {
5618
- const pressure = parseFloat(msg.data['65281']['102']) / 100.0;
5619
- result.pressure = calibrateAndPrecisionRoundOptions(pressure, options, 'pressure');
5620
- }
5621
-
5622
- return result;
5623
- }
5624
- },
5625
- },
5626
5536
  xiaomi_temperature: {
5627
5537
  cluster: 'msTemperatureMeasurement',
5628
5538
  options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
@@ -5637,22 +5547,6 @@ const converters = {
5637
5547
  }
5638
5548
  },
5639
5549
  },
5640
- SJCGQ11LM_temperature: {
5641
- cluster: 'genBasic',
5642
- type: ['attributeReport', 'readResponse'],
5643
- convert: (model, msg, publish, options, meta) => {
5644
- if (msg.data.hasOwnProperty('65281')) {
5645
- const result = {};
5646
- if (msg.data['65281'].hasOwnProperty('3')) {
5647
- let temperature = msg.data['65281']['3'];
5648
- temperature = calibrateAndPrecisionRoundOptions(temperature, options, 'temperature');
5649
- result.temperature = temperature;
5650
- }
5651
-
5652
- return result;
5653
- }
5654
- },
5655
- },
5656
5550
  xiaomi_WXKG11LM_action: {
5657
5551
  cluster: 'genOnOff',
5658
5552
  type: ['attributeReport', 'readResponse'],
@@ -6664,19 +6558,6 @@ const converters = {
6664
6558
  return result;
6665
6559
  },
6666
6560
  },
6667
- JTYJGD01LMBW_smoke_density: {
6668
- cluster: 'genBasic',
6669
- type: ['attributeReport', 'readResponse'],
6670
- convert: (model, msg, publish, options, meta) => {
6671
- const data = msg.data;
6672
- if (data && data['65281']) {
6673
- const basicAttrs = data['65281'];
6674
- if (basicAttrs.hasOwnProperty('100')) {
6675
- return {smoke_density: basicAttrs['100']};
6676
- }
6677
- }
6678
- },
6679
- },
6680
6561
  JTQJBF01LMBW_sensitivity: {
6681
6562
  cluster: 'ssIasZone',
6682
6563
  type: ['attributeReport', 'readResponse'],
@@ -2116,7 +2116,7 @@ const converters = {
2116
2116
  'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
2117
2117
  'QBKG31LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM'].includes(meta.mapped.model)) {
2118
2118
  await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
2119
- } else if (['ZNCZ02LM', 'QBCZ11LM'].includes(meta.mapped.model)) {
2119
+ } else if (['ZNCZ02LM', 'QBCZ11LM', 'LLKZMK11LM'].includes(meta.mapped.model)) {
2120
2120
  const payload = value ?
2121
2121
  [[0xaa, 0x80, 0x05, 0xd1, 0x47, 0x07, 0x01, 0x10, 0x01], [0xaa, 0x80, 0x03, 0xd3, 0x07, 0x08, 0x01]] :
2122
2122
  [[0xaa, 0x80, 0x05, 0xd1, 0x47, 0x09, 0x01, 0x10, 0x00], [0xaa, 0x80, 0x03, 0xd3, 0x07, 0x0a, 0x01]];
@@ -2453,6 +2453,18 @@ const converters = {
2453
2453
  await entity.read('genAnalogOutput', [0x0055]);
2454
2454
  },
2455
2455
  },
2456
+ xiaomi_curtain_acn002_charging_status: {
2457
+ key: ['charging_status'],
2458
+ convertGet: async (entity, key, meta) => {
2459
+ await entity.read('aqaraOpple', [0x0409], manufacturerOptions.xiaomi);
2460
+ },
2461
+ },
2462
+ xiaomi_curtain_acn002_battery: {
2463
+ key: ['battery'],
2464
+ convertGet: async (entity, key, meta) => {
2465
+ await entity.read('aqaraOpple', [0x040a], manufacturerOptions.xiaomi);
2466
+ },
2467
+ },
2456
2468
  ledvance_commands: {
2457
2469
  /* deprectated osram_*/
2458
2470
  key: ['set_transition', 'remember_state', 'osram_set_transition', 'osram_remember_state'],
package/devices/innr.js CHANGED
@@ -95,6 +95,14 @@ module.exports = [
95
95
  extend: extend.light_onoff_brightness(),
96
96
  meta: {turnsOffAtBrightness1: true},
97
97
  },
98
+ {
99
+ zigbeeModel: ['RB 266'],
100
+ model: 'RB 266',
101
+ vendor: 'Innr',
102
+ description: 'E27 bulb',
103
+ extend: extend.light_onoff_brightness(),
104
+ meta: {turnsOffAtBrightness1: true},
105
+ },
98
106
  {
99
107
  zigbeeModel: ['RF 265'],
100
108
  model: 'RF 265',
@@ -55,6 +55,22 @@ module.exports = [
55
55
  extend: extend.ledvance.light_onoff_brightness_colortemp_color(),
56
56
  ota: ota.ledvance,
57
57
  },
58
+ {
59
+ zigbeeModel: ['PAR16S RGBW'],
60
+ model: 'AC33906',
61
+ vendor: 'LEDVANCE',
62
+ description: 'SMART+ spot GU10 multicolor RGBW',
63
+ extend: extend.ledvance.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
64
+ ota: ota.ledvance,
65
+ },
66
+ {
67
+ zigbeeModel: ['PAR16S TW'],
68
+ model: 'AC33905',
69
+ vendor: 'LEDVANCE',
70
+ description: 'SMART+ spot GU10 tunable white',
71
+ extend: extend.ledvance.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
72
+ ota: ota.ledvance,
73
+ },
58
74
  {
59
75
  zigbeeModel: ['B40 TW Z3'],
60
76
  model: '4058075208414',
@@ -63,6 +79,14 @@ module.exports = [
63
79
  extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
64
80
  ota: ota.ledvance,
65
81
  },
82
+ {
83
+ zigbeeModel: ['P40S TW'],
84
+ model: 'AC33903',
85
+ vendor: 'LEDVANCE',
86
+ description: 'SMART+ classic P 40 E14 tunable white',
87
+ extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
88
+ ota: ota.ledvance,
89
+ },
66
90
  {
67
91
  zigbeeModel: ['FLEX RGBW Z3'],
68
92
  model: '4058075208339',
package/devices/lixee.js CHANGED
@@ -509,6 +509,14 @@ function getCurrentConfig(device, options, logger=console) {
509
509
  break;
510
510
  }
511
511
 
512
+ // Filter exposed attributes with user whitelist
513
+ if (options && options.hasOwnProperty('tic_command_whitelist')) {
514
+ const tic_commands_str = options['tic_command_whitelist'].toUpperCase();
515
+ if (tic_commands_str !== 'ALL') {
516
+ const tic_commands = tic_commands_str.split(',').map((a) => a.trim());
517
+ myExpose = myExpose.filter((a) => tic_commands.includes(a.exposes.name));
518
+ }
519
+ }
512
520
 
513
521
  return myExpose;
514
522
  }
@@ -547,6 +555,7 @@ const definition = {
547
555
  .withDescription(`Overrides the automatic current tarif. This option will exclude unnecesary attributes. Open a issue to support more of them. Default: auto`),
548
556
  exposes.options.precision(`kWh`),
549
557
  exposes.numeric(`measurement_poll_chunk`, ea.SET).withValueMin(1).withDescription(`During the poll, request multiple exposes to the Zlinky at once for reducing Zigbee network overload. Too much request at once could exceed device limit. Requieres Z2M restart. Default: 1`),
558
+ exposes.text(`tic_command_whitelist`, ea.SET).withDescription(`List of TIC commands to be exposed (separated by comma). Reconfigure device after change. Default: all`),
550
559
  ],
551
560
  configure: async (device, coordinatorEndpoint, logger, options) => {
552
561
  const endpoint = device.getEndpoint(1);
@@ -558,7 +567,11 @@ const definition = {
558
567
  clustersDef._0xFF66, /* liXeePrivate */
559
568
  ]);
560
569
 
561
- await endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], {manufacturerCode: null});
570
+ await endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], {manufacturerCode: null})
571
+ .catch((e) => {
572
+ // https://github.com/Koenkk/zigbee2mqtt/issues/11674
573
+ logger.warn(`Failed to read zigbee attributes: ${e}`);
574
+ });
562
575
 
563
576
  const configReportings = [];
564
577
  const suscribeNew = getCurrentConfig(device, options, logger).filter((e) => e.reportable);
@@ -599,7 +612,11 @@ const definition = {
599
612
  onEvent: async (type, data, device, options) => {
600
613
  const endpoint = device.getEndpoint(1);
601
614
  if (type === 'start') {
602
- endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], {manufacturerCode: null});
615
+ endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], {manufacturerCode: null})
616
+ .catch((e) => {
617
+ // https://github.com/Koenkk/zigbee2mqtt/issues/11674
618
+ console.warn(`Failed to read zigbee attributes: ${e}`);
619
+ });
603
620
  } else if (type === 'stop') {
604
621
  clearInterval(globalStore.getValue(device, 'interval'));
605
622
  globalStore.clearValue(device, 'interval');
@@ -621,7 +638,11 @@ const definition = {
621
638
  // Split array by chunks
622
639
  for (i = 0, j = targ.length; i < j; i += measurement_poll_chunk) {
623
640
  await endpoint
624
- .read(cluster, targ.slice(i, i + measurement_poll_chunk), {manufacturerCode: null});
641
+ .read(cluster, targ.slice(i, i + measurement_poll_chunk), {manufacturerCode: null})
642
+ .catch((e) => {
643
+ // https://github.com/Koenkk/zigbee2mqtt/issues/11674
644
+ console.warn(`Failed to read zigbee attributes: ${e}`);
645
+ });
625
646
  }
626
647
  }
627
648
  }
@@ -759,6 +759,15 @@ module.exports = [
759
759
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
760
760
  ota: ota.zigbeeOTA,
761
761
  },
762
+ {
763
+ zigbeeModel: ['LTA012'],
764
+ model: '929002335105',
765
+ vendor: 'Philips',
766
+ description: 'Hue white ambiance E26 1600lm with Bluetooth',
767
+ ota: ota.zigbeeOTA,
768
+ meta: {turnsOffAtBrightness1: true},
769
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
770
+ },
762
771
  {
763
772
  zigbeeModel: ['LTA008'],
764
773
  model: '9290022267A',
@@ -2435,6 +2444,15 @@ module.exports = [
2435
2444
  extend: hueExtend.light_onoff_brightness_colortemp(),
2436
2445
  ota: ota.zigbeeOTA,
2437
2446
  },
2447
+ {
2448
+ zigbeeModel: ['929003047101'],
2449
+ model: '929003047101',
2450
+ vendor: 'Philips',
2451
+ description: 'Hue White ambiance Milliskin (round)',
2452
+ meta: {turnsOffAtBrightness1: true},
2453
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2454
+ ota: ota.zigbeeOTA,
2455
+ },
2438
2456
  {
2439
2457
  zigbeeModel: ['5047131P9', '5047131P6'],
2440
2458
  model: '5047131P9',
@@ -3,6 +3,7 @@ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/lega
3
3
  const tz = require('../converters/toZigbee');
4
4
  const reporting = require('../lib/reporting');
5
5
  const e = exposes.presets;
6
+ const ea = exposes.access;
6
7
 
7
8
  module.exports = [
8
9
  {
@@ -21,4 +22,23 @@ module.exports = [
21
22
  },
22
23
  exposes: [e.switch(), e.power(), e.energy()],
23
24
  },
25
+ {
26
+ zigbeeModel: ['106-03'],
27
+ model: '106-03',
28
+ vendor: 'Plugwise',
29
+ description: 'Tom thermostatic radiator valve',
30
+ fromZigbee: [fz.thermostat, fz.temperature, fz.battery],
31
+ toZigbee: [tz.thermostat_system_mode, tz.thermostat_occupied_heating_setpoint, tz.thermostat_pi_heating_demand],
32
+ configure: async (device, coordinatorEndpoint, logger) => {
33
+ const endpoint = device.getEndpoint(1);
34
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic', 'genPowerCfg', 'hvacThermostat']);
35
+ await reporting.batteryPercentageRemaining(endpoint);
36
+ },
37
+ exposes: [e.battery(),
38
+ exposes.climate()
39
+ .withSetpoint('occupied_heating_setpoint', 5, 30, 0.5, ea.ALL).withLocalTemperature(ea.STATE)
40
+ .withSystemMode(['off', 'auto'], ea.ALL)
41
+ .withPiHeatingDemand(ea.STATE_GET),
42
+ ],
43
+ },
24
44
  ];
package/devices/tuya.js CHANGED
@@ -143,7 +143,8 @@ module.exports = [
143
143
  description: 'Smart air house keeper',
144
144
  fromZigbee: [fz.tuya_air_quality],
145
145
  toZigbee: [],
146
- exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd().withUnit('ppm'), e.pm25()],
146
+ exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd().withUnit('ppm'),
147
+ e.pm25().withValueMin(0).withValueMax(999).withValueStep(1)],
147
148
  },
148
149
  {
149
150
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_7bztmfm1'}],
@@ -228,6 +229,7 @@ module.exports = [
228
229
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_kohbva1f'},
229
230
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_wslkvrau'},
230
231
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_0rn9qhnu'},
232
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_ejctepku'},
231
233
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
232
234
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_jmiuubkz'},
233
235
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
@@ -287,6 +289,7 @@ module.exports = [
287
289
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
288
290
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_i680rtja'},
289
291
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'},
292
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_nehayyhx'},
290
293
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'},
291
294
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_e5t9bfdv'}],
292
295
  model: 'TS0501B',
@@ -883,6 +886,27 @@ module.exports = [
883
886
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
884
887
  },
885
888
  },
889
+ {
890
+ fingerprint: [{modelID: 'TS0002', manufacturerName: '_TZ3000_fisb3ajo'}],
891
+ model: 'TS0002_switch_module_2',
892
+ vendor: 'TuYa',
893
+ description: '2 gang switch module',
894
+ toZigbee: extend.switch().toZigbee.concat([tz.moes_power_on_behavior]),
895
+ fromZigbee: extend.switch().fromZigbee.concat([fz.moes_power_on_behavior]),
896
+ exposes: [
897
+ e.switch().withEndpoint('l1'),
898
+ e.switch().withEndpoint('l2'),
899
+ exposes.presets.power_on_behavior(),
900
+ ],
901
+ endpoint: (device) => {
902
+ return {'l1': 1, 'l2': 2};
903
+ },
904
+ meta: {multiEndpoint: true},
905
+ configure: async (device, coordinatorEndpoint, logger) => {
906
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
907
+ await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
908
+ },
909
+ },
886
910
  {
887
911
  fingerprint: [{modelID: 'TS0003', manufacturerName: '_TZ3000_vsasbzkf'},
888
912
  {modelID: 'TS0003', manufacturerName: '_TZ3000_odzoiovu'}],
@@ -1039,7 +1063,9 @@ module.exports = [
1039
1063
  tz.tuya_thermostat_window_detect, tz.tuya_thermostat_schedule, tz.tuya_thermostat_week, tz.tuya_thermostat_away_preset,
1040
1064
  tz.tuya_thermostat_schedule_programming_mode],
1041
1065
  exposes: [
1042
- e.child_lock(), e.window_detection(), e.battery_low(), e.valve_detection(), e.position(),
1066
+ e.child_lock(), e.window_detection(),
1067
+ exposes.binary('window_open', ea.STATE).withDescription('Window open?'),
1068
+ e.battery_low(), e.valve_detection(), e.position(),
1043
1069
  exposes.climate().withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
1044
1070
  .withLocalTemperature(ea.STATE).withSystemMode(['heat', 'auto', 'off'], ea.STATE_SET,
1045
1071
  'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
package/devices/waxman.js CHANGED
@@ -21,7 +21,7 @@ module.exports = [
21
21
  },
22
22
  },
23
23
  {
24
- zigbeeModel: ['House Water Valve - MDL-TBD'],
24
+ zigbeeModel: ['House Water Valve - MDL-TBD', 'leakSMART Water Valve v2.10'],
25
25
  // Should work with all manufacturer model numbers for the 2.0 series:
26
26
  // 8850000 3/4"
27
27
  // 8850100 1"
package/devices/xiaomi.js CHANGED
@@ -159,7 +159,7 @@ module.exports = [
159
159
  vendor: 'Xiaomi',
160
160
  description: 'MiJia wireless switch',
161
161
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
162
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_WXKG01LM_action, fz.legacy.WXKG01LM_click],
162
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_WXKG01LM_action, fz.legacy.WXKG01LM_click],
163
163
  exposes: [e.battery(), e.action(['single', 'double', 'triple', 'quadruple', 'hold', 'release', 'many']), e.battery_voltage()],
164
164
  toZigbee: [],
165
165
  },
@@ -170,7 +170,7 @@ module.exports = [
170
170
  description: 'Aqara wireless switch',
171
171
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
172
172
  exposes: [e.battery(), e.battery_voltage(), e.action(['single', 'double', 'triple', 'quadruple', 'hold', 'release'])],
173
- fromZigbee: [fz.xiaomi_multistate_action, fz.xiaomi_WXKG11LM_action, fz.xiaomi_battery,
173
+ fromZigbee: [fz.xiaomi_multistate_action, fz.xiaomi_WXKG11LM_action, fz.xiaomi_basic,
174
174
  fz.legacy.WXKG11LM_click, fz.legacy.xiaomi_action_click_multistate],
175
175
  toZigbee: [],
176
176
  },
@@ -181,7 +181,7 @@ module.exports = [
181
181
  description: 'Aqara wireless switch (with gyroscope)',
182
182
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
183
183
  exposes: [e.battery(), e.action(['single', 'double', 'hold', 'release', 'shake']), e.battery_voltage()],
184
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_multistate_action, fz.legacy.WXKG12LM_action_click_multistate],
184
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_multistate_action, fz.legacy.WXKG12LM_action_click_multistate],
185
185
  toZigbee: [],
186
186
  },
187
187
  {
@@ -191,7 +191,7 @@ module.exports = [
191
191
  description: 'Aqara single key wireless wall switch (2016 model)',
192
192
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
193
193
  exposes: [e.battery(), e.action(['single']), e.battery_voltage()],
194
- fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_battery, fz.legacy.WXKG03LM_click],
194
+ fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_basic, fz.legacy.WXKG03LM_click],
195
195
  toZigbee: [],
196
196
  onEvent: preventReset,
197
197
  },
@@ -202,7 +202,7 @@ module.exports = [
202
202
  description: 'Aqara single key wireless wall switch (2018 model)',
203
203
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
204
204
  exposes: [e.battery(), e.action(['single', 'double', 'hold']), e.battery_voltage()],
205
- fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_battery,
205
+ fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_basic,
206
206
  fz.legacy.WXKG03LM_click, fz.legacy.xiaomi_action_click_multistate],
207
207
  toZigbee: [],
208
208
  onEvent: preventReset,
@@ -212,7 +212,7 @@ module.exports = [
212
212
  model: 'WXKG06LM',
213
213
  vendor: 'Xiaomi',
214
214
  description: 'Aqara D1 single key wireless wall switch',
215
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_on_off_action, fz.xiaomi_multistate_action],
215
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_on_off_action, fz.xiaomi_multistate_action],
216
216
  toZigbee: [],
217
217
  exposes: [e.battery(),
218
218
  e.action(['single', 'double', 'hold']),
@@ -235,7 +235,7 @@ module.exports = [
235
235
  description: 'Aqara double key wireless wall switch (2016 model)',
236
236
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
237
237
  exposes: [e.battery(), e.action(['single_left', 'single_right', 'single_both']), e.battery_voltage()],
238
- fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_battery, fz.legacy.WXKG02LM_click],
238
+ fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_basic, fz.legacy.WXKG02LM_click],
239
239
  toZigbee: [],
240
240
  onEvent: preventReset,
241
241
  },
@@ -247,7 +247,7 @@ module.exports = [
247
247
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
248
248
  exposes: [e.battery(), e.action(['single_left', 'single_right', 'single_both', 'double_left', 'double_right', 'double_both',
249
249
  'hold_left', 'hold_right', 'hold_both']), e.battery_voltage()],
250
- fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_battery,
250
+ fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_basic,
251
251
  fz.legacy.WXKG02LM_click, fz.legacy.WXKG02LM_click_multistate],
252
252
  toZigbee: [],
253
253
  onEvent: preventReset,
@@ -454,7 +454,7 @@ module.exports = [
454
454
  vendor: 'Xiaomi',
455
455
  description: 'Aqara single key wired wall switch',
456
456
  fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_on_off_ignore_endpoint_4_5_6,
457
- fz.legacy.QBKG04LM_QBKG11LM_click, fz.xiaomi_switch_basic, fz.xiaomi_operation_mode_basic,
457
+ fz.legacy.QBKG04LM_QBKG11LM_click, fz.xiaomi_basic, fz.xiaomi_operation_mode_basic,
458
458
  fz.legacy.QBKG11LM_click, fz.ignore_multistate_report, fz.xiaomi_power],
459
459
  exposes: [
460
460
  e.switch(), e.power().withAccess(ea.STATE_GET), e.temperature(),
@@ -475,7 +475,7 @@ module.exports = [
475
475
  vendor: 'Xiaomi',
476
476
  description: 'Aqara double key wired wall switch without neutral wire. Doesn\'t work as a router and doesn\'t support power meter',
477
477
  fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_on_off_ignore_endpoint_4_5_6, fz.legacy.QBKG03LM_QBKG12LM_click,
478
- fz.legacy.QBKG03LM_buttons, fz.xiaomi_operation_mode_basic, fz.xiaomi_switch_basic],
478
+ fz.legacy.QBKG03LM_buttons, fz.xiaomi_operation_mode_basic, fz.xiaomi_basic],
479
479
  exposes: [
480
480
  e.switch().withEndpoint('left'),
481
481
  e.switch().withEndpoint('right'),
@@ -508,7 +508,7 @@ module.exports = [
508
508
  vendor: 'Xiaomi',
509
509
  description: 'Aqara double key wired wall switch',
510
510
  fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_on_off_ignore_endpoint_4_5_6,
511
- fz.legacy.QBKG03LM_QBKG12LM_click, fz.xiaomi_switch_basic, fz.xiaomi_operation_mode_basic, fz.legacy.QBKG12LM_click,
511
+ fz.legacy.QBKG03LM_QBKG12LM_click, fz.xiaomi_basic, fz.xiaomi_operation_mode_basic, fz.legacy.QBKG12LM_click,
512
512
  fz.xiaomi_power],
513
513
  exposes: [
514
514
  e.switch().withEndpoint('left'),
@@ -538,7 +538,7 @@ module.exports = [
538
538
  vendor: 'Xiaomi',
539
539
  description: 'Aqara D1 double key wireless wall switch',
540
540
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
541
- fromZigbee: [fz.xiaomi_battery, fz.legacy.xiaomi_on_off_action, fz.legacy.xiaomi_multistate_action],
541
+ fromZigbee: [fz.xiaomi_basic, fz.legacy.xiaomi_on_off_action, fz.legacy.xiaomi_multistate_action],
542
542
  toZigbee: [],
543
543
  endpoint: (device) => {
544
544
  return {left: 1, right: 2, both: 3};
@@ -681,7 +681,7 @@ module.exports = [
681
681
  model: 'QBKG23LM',
682
682
  vendor: 'Xiaomi',
683
683
  description: 'Aqara D1 1 gang smart wall switch (with neutral wire)',
684
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_switch_basic, fz.xiaomi_multistate_action],
684
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_basic, fz.xiaomi_multistate_action],
685
685
  toZigbee: [tz.on_off, tz.xiaomi_power, tz.xiaomi_switch_operation_mode_basic],
686
686
  endpoint: (device) => {
687
687
  return {'system': 1};
@@ -815,7 +815,7 @@ module.exports = [
815
815
  vendor: 'Xiaomi',
816
816
  description: 'MiJia temperature & humidity sensor',
817
817
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
818
- fromZigbee: [fz.xiaomi_battery, fz.WSDCGQ01LM_WSDCGQ11LM_interval, fz.xiaomi_temperature, fz.humidity],
818
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_temperature, fz.humidity],
819
819
  toZigbee: [],
820
820
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
821
821
  },
@@ -825,7 +825,7 @@ module.exports = [
825
825
  vendor: 'Xiaomi',
826
826
  description: 'Aqara temperature, humidity and pressure sensor',
827
827
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
828
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_temperature, fz.humidity, fz.pressure, fz.WSDCGQ01LM_WSDCGQ11LM_interval],
828
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_temperature, fz.humidity, fz.pressure],
829
829
  toZigbee: [],
830
830
  exposes: [e.battery(), e.temperature(), e.humidity(), e.pressure(), e.battery_voltage()],
831
831
  configure: async (device, coordinatorEndpoint, logger) => {
@@ -838,7 +838,7 @@ module.exports = [
838
838
  model: 'WSDCGQ12LM',
839
839
  vendor: 'Xiaomi',
840
840
  description: 'Aqara T1 temperature, humidity and pressure sensor',
841
- fromZigbee: [fz.xiaomi_battery, fz.temperature, fz.humidity, fz.pressure],
841
+ fromZigbee: [fz.xiaomi_basic, fz.temperature, fz.humidity, fz.pressure],
842
842
  toZigbee: [],
843
843
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
844
844
  configure: async (device, coordinatorEndpoint, logger) => {
@@ -854,7 +854,7 @@ module.exports = [
854
854
  vendor: 'Xiaomi',
855
855
  description: 'MiJia human body movement sensor',
856
856
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
857
- fromZigbee: [fz.xiaomi_battery, fz.occupancy_with_timeout],
857
+ fromZigbee: [fz.xiaomi_basic, fz.occupancy_with_timeout],
858
858
  toZigbee: [],
859
859
  exposes: [e.battery(), e.occupancy(), e.battery_voltage()],
860
860
  },
@@ -864,7 +864,7 @@ module.exports = [
864
864
  vendor: 'Xiaomi',
865
865
  description: 'Aqara human body movement and illuminance sensor',
866
866
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
867
- fromZigbee: [fz.xiaomi_battery, fz.occupancy_with_timeout, fz.RTCGQ11LM_illuminance, fz.RTCGQ11LM_interval],
867
+ fromZigbee: [fz.xiaomi_basic, fz.occupancy_with_timeout, fz.RTCGQ11LM_illuminance],
868
868
  toZigbee: [],
869
869
  exposes: [e.battery(), e.occupancy(), e.temperature(), e.battery_voltage(), e.illuminance_lux().withProperty('illuminance'),
870
870
  e.illuminance().withUnit('lx').withDescription('Measured illuminance in lux')],
@@ -941,7 +941,7 @@ module.exports = [
941
941
  vendor: 'Xiaomi',
942
942
  description: 'MiJia door & window contact sensor',
943
943
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
944
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_contact],
944
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_contact],
945
945
  toZigbee: [],
946
946
  exposes: [e.battery(), e.contact(), e.battery_voltage()],
947
947
  },
@@ -951,7 +951,7 @@ module.exports = [
951
951
  vendor: 'Xiaomi',
952
952
  description: 'Aqara door & window contact sensor',
953
953
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
954
- fromZigbee: [fz.xiaomi_battery, fz.xiaomi_contact, fz.xiaomi_contact_interval],
954
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_contact],
955
955
  toZigbee: [],
956
956
  exposes: [e.battery(), e.contact(), e.temperature(), e.battery_voltage()],
957
957
  configure: async (device) => {
@@ -965,7 +965,7 @@ module.exports = [
965
965
  vendor: 'Xiaomi',
966
966
  description: 'Aqara water leak sensor',
967
967
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
968
- fromZigbee: [fz.xiaomi_battery, fz.ias_water_leak_alarm_1, fz.SJCGQ11LM_temperature],
968
+ fromZigbee: [fz.xiaomi_basic, fz.ias_water_leak_alarm_1],
969
969
  toZigbee: [],
970
970
  exposes: [e.battery(), e.water_leak(), e.battery_low(), e.battery_voltage(), e.temperature()],
971
971
  },
@@ -975,7 +975,7 @@ module.exports = [
975
975
  vendor: 'Xiaomi',
976
976
  description: 'Aqara T1 water leak sensor',
977
977
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
978
- fromZigbee: [fz.xiaomi_battery, fz.ias_water_leak_alarm_1],
978
+ fromZigbee: [fz.xiaomi_basic, fz.ias_water_leak_alarm_1],
979
979
  toZigbee: [],
980
980
  exposes: [e.battery(), e.water_leak(), e.battery_low(), e.tamper(), e.battery_voltage()],
981
981
  ota: ota.zigbeeOTA,
@@ -986,7 +986,7 @@ module.exports = [
986
986
  vendor: 'Xiaomi',
987
987
  description: 'Mi/Aqara smart home cube',
988
988
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
989
- fromZigbee: [fz.xiaomi_battery, fz.MFKZQ01LM_action_multistate, fz.MFKZQ01LM_action_analog],
989
+ fromZigbee: [fz.xiaomi_basic, fz.MFKZQ01LM_action_multistate, fz.MFKZQ01LM_action_analog],
990
990
  exposes: [e.battery(), e.battery_voltage(), e.angle('action_angle'),
991
991
  e.cube_side('action_from_side'), e.cube_side('action_side'), e.cube_side('action_to_side'),
992
992
  e.action(['shake', 'wakeup', 'fall', 'tap', 'slide', 'flip180', 'flip90', 'rotate_left', 'rotate_right'])],
@@ -997,7 +997,7 @@ module.exports = [
997
997
  model: 'ZNCZ02LM',
998
998
  description: 'Mi power plug ZigBee',
999
999
  vendor: 'Xiaomi',
1000
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_switch_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1000
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1001
1001
  toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_power],
1002
1002
  exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature(), e.power_outage_memory()],
1003
1003
  ota: ota.zigbeeOTA,
@@ -1007,7 +1007,7 @@ module.exports = [
1007
1007
  model: 'ZNCZ03LM',
1008
1008
  description: 'Mi power plug ZigBee TW',
1009
1009
  vendor: 'Xiaomi',
1010
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_switch_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1010
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1011
1011
  toZigbee: [tz.on_off, tz.xiaomi_power],
1012
1012
  exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature().withAccess(ea.STATE),
1013
1013
  e.voltage().withAccess(ea.STATE)],
@@ -1035,7 +1035,7 @@ module.exports = [
1035
1035
  model: 'ZNCZ12LM',
1036
1036
  description: 'Mi power plug ZigBee US',
1037
1037
  vendor: 'Xiaomi',
1038
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_switch_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1038
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_basic, fz.ignore_occupancy_report, fz.ignore_illuminance_report],
1039
1039
  toZigbee: [tz.on_off, tz.xiaomi_power],
1040
1040
  exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature().withAccess(ea.STATE),
1041
1041
  e.voltage().withAccess(ea.STATE)],
@@ -1045,7 +1045,7 @@ module.exports = [
1045
1045
  model: 'SP-EUC01',
1046
1046
  description: 'Aqara EU smart plug',
1047
1047
  vendor: 'Xiaomi',
1048
- fromZigbee: [fz.on_off, fz.xiaomi_switch_basic, fz.electrical_measurement, fz.metering,
1048
+ fromZigbee: [fz.on_off, fz.xiaomi_basic, fz.electrical_measurement, fz.metering,
1049
1049
  fz.aqara_opple, fz.xiaomi_power, fz.device_temperature],
1050
1050
  toZigbee: [tz.on_off],
1051
1051
  configure: async (device, coordinatorEndpoint, logger) => {
@@ -1105,7 +1105,7 @@ module.exports = [
1105
1105
  model: 'ZNCZ11LM',
1106
1106
  vendor: 'Xiaomi',
1107
1107
  description: 'Aqara power plug ZigBee',
1108
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.ignore_occupancy_report, fz.xiaomi_switch_basic],
1108
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.ignore_occupancy_report, fz.xiaomi_basic],
1109
1109
  toZigbee: [tz.on_off, tz.xiaomi_power, tz.xiaomi_led_disabled_night,
1110
1110
  tz.xiaomi_switch_power_outage_memory, tz.xiaomi_auto_off],
1111
1111
  exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature(), e.voltage().withAccess(ea.STATE),
@@ -1132,7 +1132,7 @@ module.exports = [
1132
1132
  model: 'QBCZ11LM',
1133
1133
  description: 'Aqara socket Zigbee',
1134
1134
  vendor: 'Xiaomi',
1135
- fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_switch_basic],
1135
+ fromZigbee: [fz.on_off, fz.xiaomi_power, fz.xiaomi_basic],
1136
1136
  toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_power],
1137
1137
  exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature().withAccess(ea.STATE),
1138
1138
  e.voltage().withAccess(ea.STATE), e.power_outage_memory()],
@@ -1144,7 +1144,7 @@ module.exports = [
1144
1144
  description: 'MiJia Honeywell smoke detector',
1145
1145
  vendor: 'Xiaomi',
1146
1146
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
1147
- fromZigbee: [fz.xiaomi_battery, fz.JTYJGD01LMBW_smoke, fz.JTYJGD01LMBW_smoke_density],
1147
+ fromZigbee: [fz.xiaomi_basic, fz.JTYJGD01LMBW_smoke],
1148
1148
  toZigbee: [tz.JTQJBF01LMBW_JTYJGD01LMBW_sensitivity, tz.JTQJBF01LMBW_JTYJGD01LMBW_selfest],
1149
1149
  exposes: [
1150
1150
  e.smoke(), e.battery_low(), e.tamper(), e.battery(), exposes.enum('sensitivity', ea.STATE_SET, ['low', 'medium', 'high']),
@@ -1214,7 +1214,7 @@ module.exports = [
1214
1214
  vendor: 'Xiaomi',
1215
1215
  description: 'Aqara vibration sensor',
1216
1216
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
1217
- fromZigbee: [fz.xiaomi_battery, fz.DJT11LM_vibration],
1217
+ fromZigbee: [fz.xiaomi_basic, fz.DJT11LM_vibration],
1218
1218
  toZigbee: [tz.DJT11LM_vibration_sensitivity],
1219
1219
  exposes: [
1220
1220
  e.battery(), e.vibration(), e.action(['vibration', 'tilt', 'drop']),
@@ -1286,8 +1286,10 @@ module.exports = [
1286
1286
  vendor: 'Xiaomi',
1287
1287
  fromZigbee: [fz.xiaomi_curtain_acn002_position, fz.xiaomi_curtain_acn002_status, fz.cover_position_tilt, fz.ignore_basic_report,
1288
1288
  fz.aqara_opple],
1289
- toZigbee: [tz.xiaomi_curtain_position_state],
1290
- exposes: [e.cover_position().setAccess('state', ea.ALL), e.battery(),
1289
+ toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_acn002_battery, tz.xiaomi_curtain_acn002_charging_status],
1290
+ exposes: [e.cover_position().setAccess('state', ea.ALL), e.battery().withAccess(ea.STATE_GET),
1291
+ exposes.binary('charging_status', ea.STATE_GET, true, false)
1292
+ .withDescription('The current charging status.'),
1291
1293
  exposes.enum('motor_state', ea.STATE, ['declining', 'rising', 'pause', 'blocked'])
1292
1294
  .withDescription('The current state of the motor.'),
1293
1295
  exposes.binary('running', ea.STATE, true, false)
@@ -1295,6 +1297,8 @@ module.exports = [
1295
1297
  configure: async (device, coordinatorEndpoint, logger) => {
1296
1298
  device.powerSource = 'Battery';
1297
1299
  device.save();
1300
+ const endpoint = device.getEndpoint(1);
1301
+ await endpoint.read('aqaraOpple', [0x040a], {manufacturerCode: 0x115f});
1298
1302
  },
1299
1303
  ota: ota.zigbeeOTA,
1300
1304
  },
@@ -1303,14 +1307,15 @@ module.exports = [
1303
1307
  model: 'LLKZMK11LM',
1304
1308
  vendor: 'Xiaomi',
1305
1309
  description: 'Aqara wireless relay controller',
1306
- fromZigbee: [fz.xiaomi_switch_basic, fz.xiaomi_power, fz.ignore_multistate_report, fz.on_off, fz.xiaomi_basic_raw],
1310
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_power, fz.ignore_multistate_report, fz.on_off, fz.xiaomi_basic_raw],
1307
1311
  meta: {multiEndpoint: true},
1308
- toZigbee: [tz.on_off, tz.LLKZMK11LM_interlock, tz.xiaomi_power],
1312
+ toZigbee: [tz.on_off, tz.LLKZMK11LM_interlock, tz.xiaomi_power, tz.xiaomi_switch_power_outage_memory],
1309
1313
  endpoint: (device) => {
1310
1314
  return {'l1': 1, 'l2': 2};
1311
1315
  },
1312
1316
  exposes: [e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature(), e.voltage(), e.current(),
1313
1317
  e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.power_outage_count(false),
1318
+ e.power_outage_memory(),
1314
1319
  exposes.binary('interlock', ea.STATE_SET, true, false)
1315
1320
  .withDescription('Enabling prevents both relais being on at the same time'),
1316
1321
  ],
@@ -1321,7 +1326,7 @@ module.exports = [
1321
1326
  model: 'ZNMS12LM',
1322
1327
  description: 'Aqara S2 lock',
1323
1328
  vendor: 'Xiaomi',
1324
- fromZigbee: [fz.ZNMS12LM_ZNMS13LM_closuresDoorLock_report, fz.ZNMS12LM_low_battery, fz.xiaomi_battery],
1329
+ fromZigbee: [fz.xiaomi_basic, fz.ZNMS12LM_ZNMS13LM_closuresDoorLock_report, fz.ZNMS12LM_low_battery],
1325
1330
  toZigbee: [],
1326
1331
  exposes: [
1327
1332
  e.battery(), e.battery_voltage(), e.battery_low(), exposes.binary('state', ea.STATE, 'UNLOCK', 'LOCK'),
@@ -1869,7 +1874,7 @@ module.exports = [
1869
1874
  exposes.numeric('action_rotation_percent_speed', ea.STATE).withUnit('%').withDescription('Rotation percent speed'),
1870
1875
  exposes.numeric('action_rotation_time', ea.STATE).withUnit('ms').withDescription('Rotation time'),
1871
1876
  ],
1872
- fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_battery, fz.aqara_opple, fz.aqara_knob_rotation],
1877
+ fromZigbee: [fz.xiaomi_on_off_action, fz.xiaomi_multistate_action, fz.xiaomi_basic, fz.aqara_opple, fz.aqara_knob_rotation],
1873
1878
  toZigbee: [tz.aqara_opple_operation_mode],
1874
1879
  onEvent: preventReset,
1875
1880
  configure: async (device, coordinatorEndpoint, logger) => {
package/lib/tuya.js CHANGED
@@ -258,6 +258,7 @@ const dataPoints = {
258
258
  scheduleWorkday: 112,
259
259
  scheduleHoliday: 113,
260
260
  awayTemp: 114,
261
+ windowOpen: 115,
261
262
  autoLock: 116,
262
263
  awayDays: 117,
263
264
  // Manufacturer specific
package/lib/xiaomi.js CHANGED
@@ -129,7 +129,11 @@ const buffer2DataObject = (meta, model, buffer) => {
129
129
  }
130
130
  }
131
131
 
132
- if (meta.logger) meta.logger.debug(`${model.zigbeeModel}: Processed buffer into data ${JSON.stringify(dataObject)}`);
132
+ if (meta.logger) {
133
+ meta.logger.debug(`${model.zigbeeModel}: Processed buffer into data ${JSON.stringify(dataObject,
134
+ (key, value) => typeof value === 'bigint' ? value.toString() : value)}`);
135
+ }
136
+
133
137
 
134
138
  return dataObject;
135
139
  };
@@ -144,7 +148,9 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
144
148
  break;
145
149
  case '1':
146
150
  payload.voltage = value;
147
- payload.battery = batteryVoltageToPercentage(value, '3V_2100');
151
+ if (model.meta && model.meta.battery && model.meta.battery.voltageToPercentage) {
152
+ payload.battery = batteryVoltageToPercentage(value, model.meta.battery.voltageToPercentage);
153
+ }
148
154
  break;
149
155
  case '2':
150
156
  if (['JT-BZ-01AQ/A'].includes(model.model)) {
@@ -167,6 +173,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
167
173
  case '10':
168
174
  payload.switch_type = {1: 'toggle', 2: 'momentary'}[value];
169
175
  break;
176
+ case '11':
177
+ payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
178
+ // DEPRECATED: remove illuminance_lux here.
179
+ payload.illuminance_lux = calibrateAndPrecisionRoundOptions(value, options, 'illuminance_lux');
180
+ break;
170
181
  case '100':
171
182
  if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'LLKZMK11LM', 'QBKG12LM', 'QBKG03LM'].includes(model.model)) {
172
183
  let mapping;
@@ -186,6 +197,22 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
186
197
  } else if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
187
198
  // We don't know what the value means for these devices.
188
199
  // https://github.com/Koenkk/zigbee2mqtt/issues/11126
200
+ } else if (['WSDCGQ01LM', 'WSDCGQ11LM'].includes(model.model)) {
201
+ // https://github.com/Koenkk/zigbee2mqtt/issues/798
202
+ // Sometimes the sensor publishes non-realistic vales, filter these
203
+ const temperature = parseFloat(value) / 100.0;
204
+ if (temperature > -65 && temperature < 65) {
205
+ payload.temperature = calibrateAndPrecisionRoundOptions(temperature, options, 'temperature');
206
+ }
207
+ } else if (['RTCGQ11LM'].includes(model.model)) {
208
+ // It contains the occupancy, but in z2m we use a custom timer to do it, so we ignore it
209
+ // payload.occupancy = value === 1;
210
+ } else if (['MCCGQ11LM'].includes(model.model)) {
211
+ payload.contact = value === 0;
212
+ } else if (['SJCGQ11LM'].includes(model.model)) {
213
+ payload.water_leak = value === 1;
214
+ } else if (['JTYJ-GD-01LM/BW'].includes(model.model)) {
215
+ payload.smoke_density = value;
189
216
  } else {
190
217
  payload.state = value === 1 ? 'ON' : 'OFF';
191
218
  }
@@ -211,6 +238,13 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
211
238
  payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
212
239
  } else if (['RTCGQ12LM'].includes(model.model)) {
213
240
  payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
241
+ } else if (['WSDCGQ01LM', 'WSDCGQ11LM'].includes(model.model)) {
242
+ // https://github.com/Koenkk/zigbee2mqtt/issues/798
243
+ // Sometimes the sensor publishes non-realistic vales, filter these
244
+ const humidity = parseFloat(value) / 100.0;
245
+ if (humidity >= 0 && humidity <= 100) {
246
+ payload.humidity = calibrateAndPrecisionRoundOptions(humidity, options, 'humidity');
247
+ }
214
248
  } else if (['ZNJLBL01LM'].includes(model.model)) {
215
249
  payload.battery = value;
216
250
  } else if (['RTCZCGQ11LM'].includes(model.model)) {
@@ -220,6 +254,8 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
220
254
  case '102':
221
255
  if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
222
256
  payload.state_right = value === 1 ? 'ON' : 'OFF';
257
+ } else if (['WSDCGQ01LM', 'WSDCGQ11LM'].includes(model.model)) {
258
+ payload.pressure = calibrateAndPrecisionRoundOptions(value, options, 'pressure');
223
259
  } else if (['RTCZCGQ11LM'].includes(model.model)) {
224
260
  if (meta.device.applicationVersion < 50) {
225
261
  payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
@@ -257,7 +293,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
257
293
  }
258
294
  break;
259
295
  case '152':
260
- payload.power = precisionRound(value, 2); // 0x98
296
+ if (['DJT11LM'].includes(model.model)) {
297
+ // We don't know what implies for this device, it contains values like 30, 50,... that don't seem to change
298
+ } else {
299
+ payload.power = precisionRound(value, 2); // 0x98
300
+ }
261
301
  break;
262
302
  case '159':
263
303
  payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value]; // JT-BZ-01AQ/A
@@ -368,6 +408,16 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
368
408
  case '550':
369
409
  payload.button_switch_mode = value === 1 ? 'relay_and_usb' : 'relay';
370
410
  break;
411
+ case '1033':
412
+ if (['ZNJLBL01LM'].includes(model.model)) {
413
+ payload.charging_status = value === 1;
414
+ }
415
+ break;
416
+ case '1034':
417
+ if (['ZNJLBL01LM'].includes(model.model)) {
418
+ payload.battery = value;
419
+ }
420
+ break;
371
421
  case '1289':
372
422
  payload.dimmer_mode = {3: 'rgbw', 1: 'dual_ct'}[value];
373
423
  break;
@@ -377,6 +427,15 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
377
427
  payload = {...payload, ...payload65281};
378
428
  }
379
429
  break;
430
+ case '65282':
431
+ // This is a a complete structure with attributes, at this moment we only extract voltage
432
+ // Other elements like value[0].elmVal contain the "state" (for example contact for door sensor)
433
+ // but it seems to be always 1 for a occupancy sensor, so we ignore them at this moment
434
+ payload.voltage = value[1].elmVal;
435
+ if (model.meta && model.meta.battery && model.meta.battery.voltageToPercentage) {
436
+ payload.battery = batteryVoltageToPercentage(payload.voltage, model.meta.battery.voltageToPercentage);
437
+ }
438
+ break;
380
439
  case 'mode':
381
440
  payload.operation_mode = ['command', 'event'][value];
382
441
  break;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.450",
3
+ "version": "14.0.453",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "zigbee-herdsman-converters",
9
- "version": "14.0.450",
9
+ "version": "14.0.453",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "axios": "^0.26.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.450",
3
+ "version": "14.0.453",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [