zigbee-herdsman-converters 14.0.444 → 14.0.447

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.
@@ -428,7 +428,7 @@ const converters = {
428
428
  convert: (model, msg, publish, options, meta) => {
429
429
  if (msg.data.hasOwnProperty('occupancy')) {
430
430
  const payload = {occupancy: (msg.data.occupancy % 2) > 0};
431
- utils.noOccupancySince(msg.endpoint, payload, options, publish, payload.occupancy ? 'stop' : 'start');
431
+ utils.noOccupancySince(msg.endpoint, options, publish, payload.occupancy ? 'stop' : 'start');
432
432
  return payload;
433
433
  }
434
434
  },
@@ -464,7 +464,7 @@ const converters = {
464
464
  }
465
465
 
466
466
  const payload = {occupancy: true};
467
- utils.noOccupancySince(msg.endpoint, payload, options, publish, 'start');
467
+ utils.noOccupancySince(msg.endpoint, options, publish, 'start');
468
468
  return payload;
469
469
  },
470
470
  },
@@ -2790,6 +2790,33 @@ const converters = {
2790
2790
  }
2791
2791
  },
2792
2792
  },
2793
+ livolo_new_switch_state_4gang: {
2794
+ cluster: 'genPowerCfg',
2795
+ type: ['raw'],
2796
+ convert: (model, msg, publish, options, meta) => {
2797
+ const stateHeader = Buffer.from([122, 209]);
2798
+ if (msg.data.indexOf(stateHeader) === 0) {
2799
+ if (msg.data[10] === 7) {
2800
+ const status = msg.data[14];
2801
+ return {
2802
+ state_left: status & 1 ? 'ON' : 'OFF',
2803
+ state_right: status & 2 ? 'ON' : 'OFF',
2804
+ state_bottom_left: status & 4 ? 'ON' : 'OFF',
2805
+ state_bottom_right: status & 8 ? 'ON' : 'OFF',
2806
+ };
2807
+ }
2808
+ if (msg.data[10] === 13) {
2809
+ const status = msg.data[13];
2810
+ return {
2811
+ state_left: status & 1 ? 'ON' : 'OFF',
2812
+ state_right: status & 2 ? 'ON' : 'OFF',
2813
+ state_bottom_left: status & 4 ? 'ON' : 'OFF',
2814
+ state_bottom_right: status & 8 ? 'ON' : 'OFF',
2815
+ };
2816
+ }
2817
+ }
2818
+ },
2819
+ },
2793
2820
  livolo_curtain_switch_state: {
2794
2821
  cluster: 'genPowerCfg',
2795
2822
  type: ['raw'],
@@ -2949,7 +2976,8 @@ const converters = {
2949
2976
  meta.device.modelID = 'TI0001-socket';
2950
2977
  meta.device.save();
2951
2978
  }
2952
- if (msg.data.includes(Buffer.from([19, 1, 0]), 13)) {
2979
+ // No need to detect this switches, will be done by universal procedure
2980
+ /* if (msg.data.includes(Buffer.from([19, 1, 0]), 13)) {
2953
2981
  // new switch, hack
2954
2982
  meta.device.modelID = 'TI0001-switch';
2955
2983
  meta.device.save();
@@ -2958,7 +2986,7 @@ const converters = {
2958
2986
  // new switch, hack
2959
2987
  meta.device.modelID = 'TI0001-switch-2gang';
2960
2988
  meta.device.save();
2961
- }
2989
+ }*/
2962
2990
  if (msg.data.includes(Buffer.from([19, 5, 0]), 13)) {
2963
2991
  if (meta.logger) meta.logger.debug('Detected Livolo Curtain Switch');
2964
2992
  // curtain switch, hack
@@ -5231,40 +5259,8 @@ const converters = {
5231
5259
  type: ['attributeReport', 'readResponse'],
5232
5260
  options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
5233
5261
  convert: (model, msg, publish, options, meta) => {
5234
- if (msg.data['65281']) {
5235
- const data = msg.data['65281'];
5236
- const payload = {};
5237
-
5238
- if (data.hasOwnProperty('100')) {
5239
- if (['QBKG03LM', 'QBKG12LM', 'LLKZMK11LM'].includes(model.model)) {
5240
- const mapping = model.model === 'LLKZMK11LM' ? ['l1', 'l2'] : ['left', 'right'];
5241
- payload[`state_${mapping[0]}`] = data['100'] === 1 ? 'ON' : 'OFF';
5242
- payload[`state_${mapping[1]}`] = data['101'] === 1 ? 'ON' : 'OFF';
5243
- } else {
5244
- payload.state = data['100'] === 1 ? 'ON' : 'OFF';
5245
- }
5246
- }
5247
-
5248
- if (data.hasOwnProperty('152')) {
5249
- payload.power = precisionRound(data['152'], 2);
5250
- }
5251
-
5252
- if (data.hasOwnProperty('149')) {
5253
- // Consumption is deprecated
5254
- payload.consumption = precisionRound(data['149'], 2);
5255
- payload.energy = precisionRound(data['149'], 2);
5256
- }
5257
-
5258
- if (data.hasOwnProperty('3')) {
5259
- payload.temperature = calibrateAndPrecisionRoundOptions(data['3'], options, 'temperature');
5260
- }
5261
-
5262
- if (data.hasOwnProperty('150')) {
5263
- payload.voltage = precisionRound(data['150'] * 0.1, 1);
5264
- }
5265
-
5266
- return payload;
5267
- }
5262
+ const payload = xiaomi.numericAttributes2Payload(msg, meta, model, options, msg.data);
5263
+ return payload;
5268
5264
  },
5269
5265
  },
5270
5266
  xiaomi_basic_raw: {
@@ -7730,6 +7726,8 @@ const converters = {
7730
7726
  case tuya.dataPoints.trsIlluminanceLux:
7731
7727
  result = {illuminance_lux: value};
7732
7728
  break;
7729
+ case tuya.dataPoints.trsDetectionData: // Ignore this, function of this DP is unknown at the moment!
7730
+ break;
7733
7731
  default:
7734
7732
  meta.logger.warn(`fromZigbee.tuya_radar_sensor: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
7735
7733
  }
@@ -1599,13 +1599,23 @@ const converters = {
1599
1599
  }
1600
1600
 
1601
1601
  const state = value.toLowerCase();
1602
+ let oldstate = 1;
1603
+ if (state === 'on') {
1604
+ oldstate = 108;
1605
+ }
1606
+ let channel = 1.0;
1602
1607
  const postfix = meta.endpoint_name || 'left';
1603
1608
  await entity.command('genOnOff', 'toggle', {}, {transactionSequenceNumber: 0});
1604
1609
  const payloadOn = {0x0001: {value: Buffer.from([1, 0, 0, 0, 0, 0, 0, 0]), type: 1}};
1605
1610
  const payloadOff = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 1}};
1606
1611
  const payloadOnRight = {0x0001: {value: Buffer.from([2, 0, 0, 0, 0, 0, 0, 0]), type: 2}};
1607
1612
  const payloadOffRight = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 2}};
1613
+ const payloadOnBottomLeft = {0x0001: {value: Buffer.from([4, 0, 0, 0, 0, 0, 0, 0]), type: 4}};
1614
+ const payloadOffBottomLeft = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 4}};
1615
+ const payloadOnBottomRight = {0x0001: {value: Buffer.from([8, 0, 0, 0, 0, 0, 0, 0]), type: 136}};
1616
+ const payloadOffBottomRight = {0x0001: {value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 136}};
1608
1617
  if (postfix === 'left') {
1618
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', {level: oldstate, transtime: channel});
1609
1619
  await entity.write('genPowerCfg', (state === 'on') ? payloadOn : payloadOff,
1610
1620
  {
1611
1621
  manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
@@ -1613,12 +1623,28 @@ const converters = {
1613
1623
  });
1614
1624
  return {state: {state_left: value.toUpperCase()}, readAfterWriteTime: 250};
1615
1625
  } else if (postfix === 'right') {
1626
+ channel = 2.0;
1627
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', {level: oldstate, transtime: channel});
1616
1628
  await entity.write('genPowerCfg', (state === 'on') ? payloadOnRight : payloadOffRight,
1617
1629
  {
1618
1630
  manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
1619
1631
  reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
1620
1632
  });
1621
1633
  return {state: {state_right: value.toUpperCase()}, readAfterWriteTime: 250};
1634
+ } else if (postfix === 'bottom_right') {
1635
+ await entity.write('genPowerCfg', (state === 'on') ? payloadOnBottomRight : payloadOffBottomRight,
1636
+ {
1637
+ manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
1638
+ reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
1639
+ });
1640
+ return {state: {state_bottom_right: value.toUpperCase()}, readAfterWriteTime: 250};
1641
+ } else if (postfix === 'bottom_left') {
1642
+ await entity.write('genPowerCfg', (state === 'on') ? payloadOnBottomLeft : payloadOffBottomLeft,
1643
+ {
1644
+ manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
1645
+ reservedBits: 3, direction: 1, transactionSequenceNumber: 0xe9,
1646
+ });
1647
+ return {state: {state_bottom_left: value.toUpperCase()}, readAfterWriteTime: 250};
1622
1648
  }
1623
1649
  return {state: {state: value.toUpperCase()}, readAfterWriteTime: 250};
1624
1650
  },
@@ -2005,7 +2031,7 @@ const converters = {
2005
2031
  await entity.read('genBasic', [0x0033], manufacturerOptions.hue);
2006
2032
  },
2007
2033
  },
2008
- RTCGQ13LM_motion_sensitivity: {
2034
+ aqara_motion_sensitivity: {
2009
2035
  key: ['motion_sensitivity'],
2010
2036
  convertSet: async (entity, key, value, meta) => {
2011
2037
  const lookup = {'low': 1, 'medium': 2, 'high': 3};
@@ -2048,6 +2074,12 @@ const converters = {
2048
2074
  await entity.read('aqaraOpple', [0x0146], manufacturerOptions.xiaomi);
2049
2075
  },
2050
2076
  },
2077
+ RTCZCGQ11LM_reset_nopresence_status: {
2078
+ key: ['reset_nopresence_status'],
2079
+ convertSet: async (entity, key, value, meta) => {
2080
+ await entity.write('aqaraOpple', {0x0157: {value: 1, type: 0x20}}, manufacturerOptions.xiaomi);
2081
+ },
2082
+ },
2051
2083
  ZigUP_lock: {
2052
2084
  key: ['led'],
2053
2085
  convertSet: async (entity, key, value, meta) => {
@@ -13,7 +13,7 @@ const tzLocal = {
13
13
  convertSet: async (entity, key, value, meta) => {
14
14
  const state = value.toLowerCase();
15
15
  utils.validateValue(state, ['toggle', 'off', 'on']);
16
- const endpoint = meta.mapped.model === 'AU-A1ZBDSS' ? meta.device.getEndpoint(3) : meta.device.getEndpoint(2);
16
+ const endpoint = meta.device.getEndpoint(3);
17
17
  await endpoint.command('genOnOff', state, {});
18
18
  return {state: {backlight_led: state.toUpperCase()}};
19
19
  },
@@ -184,8 +184,9 @@ module.exports = [
184
184
  fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
185
185
  exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('right'),
186
186
  e.power().withEndpoint('left'), e.power().withEndpoint('right'),
187
- exposes.binary('backlight_led', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable or disable the blue backlight LED')],
188
- toZigbee: [tz.on_off, tzLocal.aOneBacklight],
187
+ exposes.numeric('brightness', ea.ALL).withValueMin(0).withValueMax(254)
188
+ .withDescription('Brightness of this backlight LED')],
189
+ toZigbee: [tz.light_onoff_brightness],
189
190
  meta: {multiEndpoint: true},
190
191
  endpoint: (device) => {
191
192
  return {'left': 1, 'right': 2};
package/devices/lidl.js CHANGED
@@ -446,6 +446,8 @@ module.exports = [
446
446
  extend: extend.switch(),
447
447
  meta: {multiEndpoint: true},
448
448
  configure: async (device, coordinatorEndpoint, logger) => {
449
+ const endpoint = device.getEndpoint(1);
450
+ await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
449
451
  for (const ID of [1, 2, 3]) {
450
452
  await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ['genOnOff']);
451
453
  }
package/devices/livolo.js CHANGED
@@ -20,13 +20,18 @@ module.exports = [
20
20
  {
21
21
  zigbeeModel: ['TI0001 '],
22
22
  model: 'TI0001',
23
- description: 'Zigbee switch (1 and 2 gang)',
23
+ description: 'Zigbee switch (1, 2, 3, 4 gang)',
24
24
  vendor: 'Livolo',
25
- exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('right')],
26
- fromZigbee: [fz.livolo_switch_state, fz.livolo_switch_state_raw],
27
- toZigbee: [tz.livolo_switch_on_off],
25
+ exposes: [
26
+ e.switch().withEndpoint('left'),
27
+ e.switch().withEndpoint('right'),
28
+ e.switch().withEndpoint('bottom_left'),
29
+ e.switch().withEndpoint('bottom_right'),
30
+ ],
31
+ fromZigbee: [fz.livolo_switch_state, fz.livolo_switch_state_raw, fz.livolo_new_switch_state_4gang],
32
+ toZigbee: [tz.livolo_socket_switch_on_off],
28
33
  endpoint: (device) => {
29
- return {'left': 6, 'right': 6};
34
+ return {'left': 6, 'right': 6, 'bottom_left': 6, 'bottom_right': 6};
30
35
  },
31
36
  configure: poll,
32
37
  onEvent: async (type, data, device) => {
@@ -41,6 +46,18 @@ module.exports = [
41
46
  globalStore.putValue(device, 'interval', interval);
42
47
  }
43
48
  }
49
+ if (data.cluster === 'genPowerCfg' && data.type === 'raw') {
50
+ const dp = data.data[10];
51
+ if (data.data[0] === 0x7a && data.data[1] === 0xd1) {
52
+ const endpoint = device.getEndpoint(6);
53
+ if (dp === 0x01) {
54
+ const options = {manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
55
+ reservedBits: 3, direction: 1, writeUndiv: true};
56
+ const payload = {0x2002: {value: [0, 0, 0, 0, 0, 0, 0], type: 0x0e}};
57
+ await endpoint.readResponse('genPowerCfg', 0xe9, payload, options);
58
+ }
59
+ }
60
+ }
44
61
  },
45
62
  },
46
63
  {
@@ -197,6 +197,18 @@ module.exports = [
197
197
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
198
198
  },
199
199
  },
200
+ {
201
+ fingerprint: [{modelID: 'TS130F', manufacturerName: '_TZ3000_zirycpws'}],
202
+ model: 'QS-Zigbee-C03',
203
+ vendor: 'Lonsonho',
204
+ description: 'Curtain/blind motor controller',
205
+ fromZigbee: [fz.cover_position_tilt, fz.tuya_cover_options],
206
+ toZigbee: [tz.cover_state, tz.cover_position_tilt, tz.tuya_cover_calibration, tz.tuya_cover_reversal],
207
+ meta: {coverInverted: true},
208
+ exposes: [e.cover_position(), exposes.enum('moving', ea.STATE, ['UP', 'STOP', 'DOWN']),
209
+ exposes.binary('calibration', ea.ALL, 'ON', 'OFF'), exposes.binary('motor_reversal', ea.ALL, 'ON', 'OFF'),
210
+ exposes.numeric('calibration_time', ea.STATE).withUnit('S').withDescription('Calibration time')],
211
+ },
200
212
  {
201
213
  fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_zxbtub8r'}],
202
214
  model: 'TS110E_1gang',
@@ -2239,6 +2239,13 @@ module.exports = [
2239
2239
  meta: {turnsOffAtBrightness1: true},
2240
2240
  extend: hueExtend.light_onoff_brightness(),
2241
2241
  },
2242
+ {
2243
+ zigbeeModel: ['929003055201'],
2244
+ model: '929003055201',
2245
+ vendor: 'Philips',
2246
+ description: 'Hue Being',
2247
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2248
+ },
2242
2249
  {
2243
2250
  zigbeeModel: ['1743630P7', '1743630V7'],
2244
2251
  model: '17436/30/P7',
@@ -2785,4 +2792,13 @@ module.exports = [
2785
2792
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2786
2793
  ota: ota.zigbeeOTA,
2787
2794
  },
2795
+ {
2796
+ zigbeeModel: ['LWS002'],
2797
+ model: '046677562229',
2798
+ vendor: 'Philips',
2799
+ description: 'Hue White PAR20 with Bluetooth',
2800
+ meta: {turnsOffAtBrightness1: true},
2801
+ extend: hueExtend.light_onoff_brightness(),
2802
+ ota: ota.zigbeeOTA,
2803
+ },
2788
2804
  ];
@@ -3,6 +3,7 @@ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/lega
3
3
  const tz = require('../converters/toZigbee');
4
4
  const e = exposes.presets;
5
5
  const ea = exposes.access;
6
+ const reporting = require('../lib/reporting');
6
7
 
7
8
  module.exports = [
8
9
  {
@@ -19,8 +20,14 @@ module.exports = [
19
20
  model: 'HDM40PV620',
20
21
  vendor: 'Qmotion',
21
22
  description: 'Motorized roller blind',
22
- fromZigbee: [fz.identify],
23
+ fromZigbee: [fz.identify, fz.cover_position_tilt, fz.battery],
23
24
  toZigbee: [tz.cover_state, tz.cover_position_tilt],
24
- exposes: [e.cover_position()],
25
+ exposes: [e.cover_position(), e.battery()],
26
+ configure: async (device, coordinatorEndpoint, logger) => {
27
+ const endpoint = device.getEndpoint(1);
28
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'closuresWindowCovering']);
29
+ await reporting.batteryPercentageRemaining(endpoint);
30
+ await reporting.currentPositionLiftPercentage(endpoint);
31
+ },
25
32
  },
26
33
  ];
package/devices/slv.js CHANGED
@@ -17,4 +17,11 @@ module.exports = [
17
17
  toZigbee: [],
18
18
  exposes: [],
19
19
  },
20
+ {
21
+ zigbeeModel: ['ZBT-RGBWLight-AR0844'],
22
+ model: '1001923',
23
+ vendor: 'SLV',
24
+ description: 'VALETO LED GU10 RGBW',
25
+ extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 556]}),
26
+ },
20
27
  ];
package/devices/tuya.js CHANGED
@@ -234,6 +234,7 @@ module.exports = [
234
234
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
235
235
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_k1pe6ibm'},
236
236
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'},
237
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_leyz4rju'},
237
238
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_jd3z4yig'}],
238
239
  model: 'TS0505B',
239
240
  vendor: 'TuYa',
package/devices/woox.js CHANGED
@@ -13,10 +13,10 @@ module.exports = [
13
13
  model: 'R7060',
14
14
  vendor: 'Woox',
15
15
  description: 'Smart garden irrigation control',
16
- fromZigbee: [fz.on_off, fz.ignore_tuya_set_time, fz.ignore_basic_report, fz.woox_R7060],
16
+ fromZigbee: [fz.on_off, fz.ignore_tuya_set_time, fz.ignore_basic_report, fz.woox_R7060, fz.battery],
17
17
  toZigbee: [tz.on_off],
18
18
  onEvent: tuya.onEventSetTime,
19
- exposes: [e.switch()],
19
+ exposes: [e.switch(), e.battery(), e.battery_voltage()],
20
20
  meta: {disableDefaultResponse: true},
21
21
  },
22
22
  {
package/devices/xiaomi.js CHANGED
@@ -893,7 +893,7 @@ module.exports = [
893
893
  vendor: 'Xiaomi',
894
894
  description: 'Aqara high precision motion sensor',
895
895
  fromZigbee: [fz.RTCGQ13LM_occupancy, fz.aqara_opple, fz.battery],
896
- toZigbee: [tz.aqara_detection_interval, tz.RTCGQ13LM_motion_sensitivity],
896
+ toZigbee: [tz.aqara_detection_interval, tz.aqara_motion_sensitivity],
897
897
  exposes: [e.occupancy(), exposes.enum('motion_sensitivity', ea.ALL, ['low', 'medium', 'high']),
898
898
  exposes.numeric('detection_interval', ea.ALL).withValueMin(2).withValueMax(65535).withUnit('s')
899
899
  .withDescription('Time interval for detecting actions'), e.battery()],
@@ -910,9 +910,10 @@ module.exports = [
910
910
  zigbeeModel: ['lumi.motion.ac01'],
911
911
  model: 'RTCZCGQ11LM',
912
912
  vendor: 'Xiaomi',
913
- description: 'Aqara Presence Detector FP1 (regions not supported for now)',
913
+ description: 'Aqara presence detector FP1 (regions not supported for now)',
914
914
  fromZigbee: [fz.aqara_opple],
915
- toZigbee: [tz.RTCZCGQ11LM_presence, tz.RTCZCGQ11LM_monitoring_mode, tz.RTCZCGQ11LM_approach_distance],
915
+ toZigbee: [tz.RTCZCGQ11LM_presence, tz.RTCZCGQ11LM_monitoring_mode, tz.RTCZCGQ11LM_approach_distance,
916
+ tz.aqara_motion_sensitivity, tz.RTCZCGQ11LM_reset_nopresence_status],
916
917
  exposes: [e.presence().withAccess(ea.STATE_GET),
917
918
  exposes.enum('presence_event', ea.STATE, ['enter', 'leave', 'left_enter', 'right_leave', 'right_enter', 'left_leave',
918
919
  'approach', 'away']).withDescription('Presence events: "enter", "leave", "left_enter", "right_leave", ' +
@@ -921,9 +922,14 @@ module.exports = [
921
922
  'without considering right and left sides'),
922
923
  exposes.enum('approach_distance', ea.ALL, ['far', 'medium', 'near']).withDescription('The distance at which the ' +
923
924
  'sensor detects approaching'),
924
- exposes.numeric('power_outage_count', ea.STATE).withDescription('Number of power outages (since last pairing)')],
925
+ exposes.enum('motion_sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('Different sensitivities ' +
926
+ 'means different static human body recognition rate and response speed of occupied'),
927
+ exposes.enum('reset_nopresence_status', ea.SET, ['Reset']).withDescription('Reset the status of no presence'),
928
+ exposes.numeric('power_outage_count', ea.STATE).withDescription('Number of power outages (since last pairing)'),
929
+ e.temperature()],
925
930
  configure: async (device, coordinatorEndpoint, logger) => {
926
931
  const endpoint = device.getEndpoint(1);
932
+ await endpoint.read('aqaraOpple', [0x010c], {manufacturerCode: 0x115f});
927
933
  await endpoint.read('aqaraOpple', [0x0142], {manufacturerCode: 0x115f});
928
934
  await endpoint.read('aqaraOpple', [0x0144], {manufacturerCode: 0x115f});
929
935
  await endpoint.read('aqaraOpple', [0x0146], {manufacturerCode: 0x115f});
@@ -1298,7 +1304,7 @@ module.exports = [
1298
1304
  endpoint: (device) => {
1299
1305
  return {'l1': 1, 'l2': 2};
1300
1306
  },
1301
- exposes: [e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature(), e.voltage().withAccess(ea.STATE),
1307
+ exposes: [e.power().withAccess(ea.STATE_GET), e.energy(), e.temperature(), e.voltage().withAccess(ea.STATE), e.current(),
1302
1308
  e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
1303
1309
  exposes.binary('interlock', ea.STATE_SET, true, false)
1304
1310
  .withDescription('Enabling prevents both relais being on at the same time')],
@@ -125,7 +125,10 @@ module.exports = [
125
125
  },
126
126
  },
127
127
  {
128
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'}],
128
+ fingerprint: [
129
+ {modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'},
130
+ {modelID: 'TS0601', manufacturerName: '_TZE200_gubdgai2'},
131
+ ],
129
132
  model: 'ZM-AM02_cover',
130
133
  vendor: 'Zemismart',
131
134
  description: 'Zigbee/RF curtain converter',
@@ -1,5 +1,4 @@
1
1
  const url = 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json';
2
- const assert = require('assert');
3
2
  const common = require('./common');
4
3
  const axios = common.getAxios();
5
4
  const fs = require('fs');
@@ -110,7 +109,10 @@ async function getImageMeta(current, logger, device) {
110
109
  (!i.minFileVersion || current.fileVersion >= i.minFileVersion) && (!i.maxFileVersion || current.fileVersion <= i.maxFileVersion) &&
111
110
  (!i.modelId || i.modelId === modelId) && (!i.manufacturerName || i.manufacturerName.includes(manufacturerName)));
112
111
 
113
- assert(image !== undefined, `No image available for imageType '${imageType}'`);
112
+ if (!image) {
113
+ throw new Error(`No image available for imageType '${imageType}'`);
114
+ }
115
+
114
116
  return {
115
117
  fileVersion: image.fileVersion,
116
118
  fileSize: image.fileSize,
package/lib/tuya.js CHANGED
@@ -435,6 +435,7 @@ const dataPoints = {
435
435
  trsSensitivity: 2,
436
436
  trsMotionState: 102,
437
437
  trsIlluminanceLux: 103,
438
+ trsDetectionData: 104,
438
439
  trsScene: 112,
439
440
  trsMotionDirection: 114,
440
441
  trsMotionSpeed: 115,
package/lib/utils.js CHANGED
@@ -397,13 +397,12 @@ function extendDevice(deviceConfigs, modelName, adjustments) {
397
397
  return {...baseDevice, ...adjustments};
398
398
  }
399
399
 
400
- function noOccupancySince(endpoint, newPayload, options, publish, action) {
400
+ function noOccupancySince(endpoint, options, publish, action) {
401
401
  if (options && options.no_occupancy_since) {
402
402
  if (action == 'start') {
403
403
  globalStore.getValue(endpoint, 'no_occupancy_since_timers', []).forEach((t) => clearTimeout(t));
404
404
  globalStore.putValue(endpoint, 'no_occupancy_since_timers', []);
405
405
 
406
- newPayload.no_occupancy_since = 0;
407
406
  options.no_occupancy_since.forEach((since) => {
408
407
  const timer = setTimeout(() => {
409
408
  publish({no_occupancy_since: since});
package/lib/xiaomi.js CHANGED
@@ -168,7 +168,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
168
168
  payload.switch_type = {1: 'toggle', 2: 'momentary'}[value];
169
169
  break;
170
170
  case '100':
171
- if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'LLKZMK11LM'].includes(model.model)) {
171
+ if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'LLKZMK11LM', 'QBKG12LM', 'QBKG03LM'].includes(model.model)) {
172
172
  let mapping;
173
173
  switch (model.model) {
174
174
  case 'QBCZ15LM':
@@ -191,7 +191,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
191
191
  }
192
192
  break;
193
193
  case '101':
194
- if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'QBKG25LM', 'QBKG34LM', 'LLKZMK11LM']
194
+ if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'QBKG25LM', 'QBKG34LM', 'LLKZMK11LM', 'QBKG12LM', 'QBKG03LM']
195
195
  .includes(model.model)) {
196
196
  let mapping;
197
197
  switch (model.model) {
@@ -213,19 +213,25 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
213
213
  payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
214
214
  } else if (['ZNJLBL01LM'].includes(model.model)) {
215
215
  payload.battery = value;
216
+ } else if (['RTCZCGQ11LM'].includes(model.model)) {
217
+ payload.presence = {0: false, 1: true, 255: null}[value];
216
218
  }
217
219
  break;
218
220
  case '102':
219
221
  if (['QBKG25LM', 'QBKG34LM'].includes(model.model)) {
220
222
  payload.state_right = value === 1 ? 'ON' : 'OFF';
221
223
  } else if (['RTCZCGQ11LM'].includes(model.model)) {
222
- payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
223
- 5: 'left_leave', 6: 'approach', 7: 'away', 255: null}[value];
224
+ if (meta.device.applicationVersion < 50) {
225
+ payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
226
+ 5: 'left_leave', 6: 'approach', 7: 'away', 255: null}[value];
227
+ } else {
228
+ payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value];
229
+ }
224
230
  }
225
231
  break;
226
232
  case '103':
227
233
  if (['RTCZCGQ11LM'].includes(model.model)) {
228
- payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected';
234
+ payload.monitoring_mode = {0: 'undirected', 1: 'left_right'}[value];
229
235
  }
230
236
  break;
231
237
  case '105':
@@ -244,7 +250,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
244
250
  payload.voltage = precisionRound(value * 0.1, 1); // 0x96
245
251
  break;
246
252
  case '151':
247
- payload.current = precisionRound(value * 0.001, 4); // 0x97
253
+ if (['LLKZMK11LM'].includes(model.model)) {
254
+ payload.current = precisionRound(value, 4);
255
+ } else {
256
+ payload.current = precisionRound(value * 0.001, 4);
257
+ }
248
258
  break;
249
259
  case '152':
250
260
  payload.power = precisionRound(value, 2); // 0x98
@@ -284,7 +294,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
284
294
  payload.detection_interval = value;
285
295
  break;
286
296
  case '268':
287
- if (['RTCGQ13LM'].includes(model.model)) {
297
+ if (['RTCGQ13LM', 'RTCZCGQ11LM'].includes(model.model)) {
288
298
  payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value];
289
299
  } else if (['JT-BZ-01AQ/A'].includes(model.model)) {
290
300
  payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value];
@@ -309,19 +319,25 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
309
319
  payload.gas_density = value; // JT-BZ-01AQ/A
310
320
  break;
311
321
  case '322':
312
- payload.presence = value === 1; // RTCZCGQ11LM
322
+ if (['RTCZCGQ11LM'].includes(model.model)) {
323
+ payload.presence = {0: false, 1: true, 255: null}[value];
324
+ }
313
325
  break;
314
326
  case '323':
315
- payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
316
- 5: 'left_leave', 6: 'approach', 7: 'away'}[value]; // RTCZCGQ11LM
327
+ if (['RTCZCGQ11LM'].includes(model.model)) {
328
+ payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
329
+ 5: 'left_leave', 6: 'approach', 7: 'away'}[value];
330
+ }
317
331
  break;
318
332
  case '324':
319
- // RTCZCGQ11LM
320
- payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected';
333
+ if (['RTCZCGQ11LM'].includes(model.model)) {
334
+ payload.monitoring_mode = {0: 'undirected', 1: 'left_right'}[value];
335
+ }
321
336
  break;
322
337
  case '326':
323
- // RTCZCGQ11LM
324
- payload.approach_distance = {0: 'far', 1: 'medium', 2: 'near'}[value];
338
+ if (['RTCZCGQ11LM'].includes(model.model)) {
339
+ payload.approach_distance = {0: 'far', 1: 'medium', 2: 'near'}[value];
340
+ }
325
341
  break;
326
342
  case '331':
327
343
  payload.linkage_alarm = value === 1; // JT-BZ-01AQ/A
@@ -355,6 +371,12 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
355
371
  case '1289':
356
372
  payload.dimmer_mode = {3: 'rgbw', 1: 'dual_ct'}[value];
357
373
  break;
374
+ case '65281':
375
+ {
376
+ const payload65281 = numericAttributes2Payload(msg, meta, model, options, value);
377
+ payload = {...payload, ...payload65281};
378
+ }
379
+ break;
358
380
  case 'mode':
359
381
  payload.operation_mode = ['command', 'event'][value];
360
382
  break;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.444",
3
+ "version": "14.0.447",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.444",
3
+ "version": "14.0.447",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [