zigbee-herdsman-converters 14.0.465 → 14.0.468

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.
@@ -3820,7 +3820,12 @@ const converters = {
3820
3820
  return {deadzone_temperature: value};
3821
3821
  case tuya.dataPoints.moesLocalTemp:
3822
3822
  temperature = value & 1<<15 ? value - (1<<16) + 1 : value;
3823
- return {local_temperature: parseFloat((temperature / 10).toFixed(1))};
3823
+ if (meta.device.manufacturerName === '_TZE200_ye5jkfsb') {
3824
+ // https://github.com/Koenkk/zigbee2mqtt/issues/11980
3825
+ temperature = temperature / 10;
3826
+ }
3827
+
3828
+ return {local_temperature: parseFloat(temperature.toFixed(1))};
3824
3829
  case tuya.dataPoints.moesTempCalibration:
3825
3830
  temperature = value;
3826
3831
  // for negative values produce complimentary hex (equivalent to negative values)
@@ -4193,6 +4198,7 @@ const converters = {
4193
4198
  const dpValue = tuya.firstDpValue(msg, meta, 'tuya_air_quality');
4194
4199
  const dp = dpValue.dp;
4195
4200
  const value = tuya.getDataValue(dpValue);
4201
+ const swapPM25CO2 = ['_TZE200_ryfmq5rl', '_TZE200_dwcarsat'];
4196
4202
  switch (dp) {
4197
4203
  case tuya.dataPoints.tuyaSabTemp:
4198
4204
  return {temperature: calibrateAndPrecisionRoundOptions(value / 10, options, 'temperature')};
@@ -4200,14 +4206,14 @@ const converters = {
4200
4206
  return {humidity: calibrateAndPrecisionRoundOptions(value / 10, options, 'humidity')};
4201
4207
  // DP22: Smart Air Box: Formaldehyd, Smart Air Housekeeper: co2
4202
4208
  case tuya.dataPoints.tuyaSabFormaldehyd:
4203
- if (meta.device.manufacturerName === '_TZE200_dwcarsat') {
4209
+ if (swapPM25CO2.includes(meta.device.manufacturerName)) {
4204
4210
  return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
4205
4211
  } else {
4206
4212
  return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd')};
4207
4213
  }
4208
4214
  // DP2: Smart Air Box: co2, Smart Air Housekeeper: MP25
4209
4215
  case tuya.dataPoints.tuyaSabCO2:
4210
- if (meta.device.manufacturerName === '_TZE200_dwcarsat') {
4216
+ if (swapPM25CO2.includes(meta.device.manufacturerName)) {
4211
4217
  return {pm25: calibrateAndPrecisionRoundOptions(value, options, 'pm25')};
4212
4218
  } else {
4213
4219
  return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
@@ -4580,10 +4586,33 @@ const converters = {
4580
4586
  } else if (meta.device.manufacturerName === '_TZE200_swaamsoy') {
4581
4587
  // https://github.com/Koenkk/zigbee-herdsman-converters/pull/3004
4582
4588
  if (dpValue.dp === 2) {
4589
+ if (value < 10) {
4590
+ tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
4591
+ }
4583
4592
  return {brightness: mapNumberRange(value, 10, 1000, 0, 254)};
4584
4593
  }
4585
- } else { // TODO: Unknown dp, assumed value type
4586
- return {brightness: mapNumberRange(value, 10, 1000, 0, 254), level: value};
4594
+ } else if (meta.device.manufacturerName === '_TZE200_3p5ydos3') {
4595
+ if (dpValue.dp === tuya.dataPoints.eardaDimmerLevel) {
4596
+ return {brightness: mapNumberRange(value, 0, 1000, 0, 254)};
4597
+ } else if (dpValue.dp === tuya.dataPoints.dimmerMinLevel) {
4598
+ return {min_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
4599
+ } else if (dpValue.dp === tuya.dataPoints.dimmerMaxLevel) {
4600
+ return {max_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
4601
+ } else {
4602
+ tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
4603
+ }
4604
+ } else {
4605
+ if (dpValue.dp !== tuya.dataPoints.dimmerLevel) {
4606
+ tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
4607
+ }
4608
+ if (dpValue.datatype !== tuya.dataTypes.value) {
4609
+ tuya.logUnexpectedDataType('tuya_dimmer', msg, dpValue, meta);
4610
+ } else {
4611
+ if (value < 10) {
4612
+ tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
4613
+ }
4614
+ return {brightness: mapNumberRange(value, 10, 1000, 0, 254), level: value};
4615
+ }
4587
4616
  }
4588
4617
  },
4589
4618
  },
@@ -4593,14 +4622,6 @@ const converters = {
4593
4622
  convert: (model, msg, publis, options, meta) => {
4594
4623
  // Don't use in production!
4595
4624
  // Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
4596
- const getType = (datatype) => {
4597
- const entry = Object.entries(tuya.dataTypes).find(([typeName, typeId]) => typeId === datatype);
4598
- return (entry ? entry[0] : 'unknown');
4599
- };
4600
- const getAllDpIds = (dp) => {
4601
- const entries = Object.entries(tuya.dataPoints).filter(([dpName, dpId]) => dpId === dp);
4602
- return entries.map(([dpName, dpId]) => dpName);
4603
- };
4604
4625
  const getHex = (value) => {
4605
4626
  let hex = value.toString(16);
4606
4627
  if (hex.length < 2) {
@@ -4611,11 +4632,7 @@ const converters = {
4611
4632
  const now = Date.now().toString();
4612
4633
  let dataStr = '';
4613
4634
  for (const [i, dpValue] of msg.data.dpValues.entries()) {
4614
- const value = tuya.getDataValue(dpValue);
4615
- meta.logger.info(`zigbee-herdsman-converters:tuya_data_point_dump: Received DP #${
4616
- dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
4617
- getType(dpValue.datatype)}', value='${value}', known DP# usage: ${JSON.stringify(getAllDpIds(dpValue.dp))}`);
4618
-
4635
+ tuya.logDataPoint('tuya_data_point_dump', msg, dpValue, meta);
4619
4636
  dataStr +=
4620
4637
  now + ' ' +
4621
4638
  meta.device.ieeeAddr + ' ' +
@@ -2584,14 +2584,14 @@ const converters = {
2584
2584
  await entity.write('ssIasZone', {0xFFF1: {value: 0x03010000, type: 0x23}}, options);
2585
2585
  },
2586
2586
  },
2587
- JTBZ01AQA_gas: {
2588
- key: ['gas'],
2587
+ aqara_alarm: {
2588
+ key: ['gas', 'smoke'],
2589
2589
  convertGet: async (entity, key, meta) => {
2590
2590
  await entity.read('aqaraOpple', [0x013a], manufacturerOptions.xiaomi);
2591
2591
  },
2592
2592
  },
2593
- JTBZ01AQA_gas_density: {
2594
- key: ['gas_density'],
2593
+ aqara_density: {
2594
+ key: ['gas_density', 'smoke_density'],
2595
2595
  convertGet: async (entity, key, meta) => {
2596
2596
  await entity.read('aqaraOpple', [0x013b], manufacturerOptions.xiaomi);
2597
2597
  },
@@ -2608,26 +2608,39 @@ const converters = {
2608
2608
  await entity.read('aqaraOpple', [0x010c], manufacturerOptions.xiaomi);
2609
2609
  },
2610
2610
  },
2611
- JTBZ01AQA_selftest: {
2611
+ aqara_selftest: {
2612
2612
  key: ['selftest'],
2613
2613
  convertSet: async (entity, key, value, meta) => {
2614
2614
  await entity.write('aqaraOpple', {0x0127: {value: true, type: 0x10}}, manufacturerOptions.xiaomi);
2615
2615
  },
2616
2616
  },
2617
- JTBZ01AQA_mute_buzzer: {
2617
+ aqara_mute_buzzer: {
2618
2618
  key: ['mute_buzzer'],
2619
2619
  convertSet: async (entity, key, value, meta) => {
2620
- await entity.write('aqaraOpple', {0x013f: {value: 15360, type: 0x23}}, manufacturerOptions.xiaomi);
2620
+ let attribute = 0x013f;
2621
+ if (['JY-GZ-01AQ'].includes(meta.mapped.model)) attribute = 0x013e;
2622
+ await entity.write('aqaraOpple', {[`${attribute}`]: {value: 15360, type: 0x23}}, manufacturerOptions.xiaomi);
2621
2623
  await entity.write('aqaraOpple', {0x0126: {value: 1, type: 0x20}}, manufacturerOptions.xiaomi);
2622
2624
  },
2623
2625
  },
2624
- JTBZ01AQA_mute: {
2626
+ aqara_mute: {
2625
2627
  key: ['mute'],
2626
2628
  convertGet: async (entity, key, meta) => {
2627
2629
  await entity.read('aqaraOpple', [0x0126], manufacturerOptions.xiaomi);
2628
2630
  },
2629
2631
  },
2630
- JTBZ01AQA_linkage_alarm: {
2632
+ JYGZ01AQ_heartbeat_indicator: {
2633
+ key: ['heartbeat_indicator'],
2634
+ convertSet: async (entity, key, value, meta) => {
2635
+ const lookup = {true: 1, false: 0};
2636
+ await entity.write('aqaraOpple', {0x013c: {value: lookup[value], type: 0x20}}, manufacturerOptions.xiaomi);
2637
+ return {state: {heartbeat_indicator: value}};
2638
+ },
2639
+ convertGet: async (entity, key, meta) => {
2640
+ await entity.read('aqaraOpple', [0x013c], manufacturerOptions.xiaomi);
2641
+ },
2642
+ },
2643
+ aqara_linkage_alarm: {
2631
2644
  key: ['linkage_alarm'],
2632
2645
  convertSet: async (entity, key, value, meta) => {
2633
2646
  const lookup = {true: 1, false: 0};
@@ -3516,7 +3529,7 @@ const converters = {
3516
3529
  },
3517
3530
  },
3518
3531
  tuya_dimmer_level: {
3519
- key: ['brightness_min', 'brightness', 'brightness_percent', 'level'],
3532
+ key: ['brightness_min', 'min_brightness', 'max_brightness', 'brightness', 'brightness_percent', 'level'],
3520
3533
  convertSet: async (entity, key, value, meta) => {
3521
3534
  // upscale to 1000
3522
3535
  let newValue;
@@ -3531,6 +3544,20 @@ const converters = {
3531
3544
  } else {
3532
3545
  throw new Error('Dimmer brightness_min is out of range 0..100');
3533
3546
  }
3547
+ } else if (key === 'min_brightness') {
3548
+ if (value >= 1 && value <= 255) {
3549
+ newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
3550
+ dp = tuya.dataPoints.dimmerMinLevel;
3551
+ } else {
3552
+ throw new Error('Dimmer min_brightness is out of range 1..255');
3553
+ }
3554
+ } else if (key === 'max_brightness') {
3555
+ if (value >= 1 && value <= 255) {
3556
+ newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
3557
+ dp = tuya.dataPoints.dimmerMaxLevel;
3558
+ } else {
3559
+ throw new Error('Dimmer min_brightness is out of range 1..255');
3560
+ }
3534
3561
  } else if (key === 'level') {
3535
3562
  if (value >= 0 && value <= 1000) {
3536
3563
  newValue = Math.round(Number(value));
@@ -3543,11 +3570,11 @@ const converters = {
3543
3570
  } else {
3544
3571
  throw new Error('Dimmer brightness_percent is out of range 0..100');
3545
3572
  }
3546
- } else {
3547
- if (value >= 0 && value <= 255) {
3548
- newValue = utils.mapNumberRange(value, 0, 255, 0, 1000);
3573
+ } else { // brightness
3574
+ if (value >= 0 && value <= 254) {
3575
+ newValue = utils.mapNumberRange(value, 0, 254, 0, 1000);
3549
3576
  } else {
3550
- throw new Error('Dimmer brightness is out of range 0..255');
3577
+ throw new Error('Dimmer brightness is out of range 0..254');
3551
3578
  }
3552
3579
  }
3553
3580
  // Always use same transid as tuya_dimmer_state (https://github.com/Koenkk/zigbee2mqtt/issues/6366)
package/devices/datek.js CHANGED
@@ -41,39 +41,45 @@ module.exports = [
41
41
  configure: async (device, coordinatorEndpoint, logger) => {
42
42
  const endpoint = device.getEndpoint(1);
43
43
  await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering', 'msTemperatureMeasurement']);
44
- await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
45
44
  await reporting.readMeteringMultiplierDivisor(endpoint);
45
+ try {
46
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
47
+ } catch (error) {
48
+ /* fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/11867 */
49
+ }
46
50
  const payload = [{
47
51
  attribute: 'rmsVoltagePhB',
48
- minimumReportInterval: 10,
52
+ minimumReportInterval: 60,
49
53
  maximumReportInterval: 3600,
50
54
  reportableChange: 0,
51
55
  },
52
56
  {
53
57
  attribute: 'rmsVoltagePhC',
54
- minimumReportInterval: 10,
58
+ minimumReportInterval: 60,
55
59
  maximumReportInterval: 3600,
56
60
  reportableChange: 0,
57
61
  },
58
62
  {
59
63
  attribute: 'rmsCurrentPhB',
60
- minimumReportInterval: 10,
64
+ minimumReportInterval: 60,
61
65
  maximumReportInterval: 3600,
62
66
  reportableChange: 0,
63
67
  },
64
68
  {
65
69
  attribute: 'rmsCurrentPhC',
66
- minimumReportInterval: 10,
70
+ minimumReportInterval: 60,
67
71
  maximumReportInterval: 3600,
68
72
  reportableChange: 0,
69
73
  }];
70
74
  await endpoint.configureReporting('haElectricalMeasurement', payload);
71
- await reporting.rmsVoltage(endpoint, {min: 10, max: 3600, change: 0});
72
- await reporting.rmsCurrent(endpoint, {min: 10, max: 3600, change: 0});
73
- await reporting.instantaneousDemand(endpoint, {min: 10, max: 3600, change: 0});
74
- await reporting.currentSummDelivered(endpoint, {min: 10, max: 3600, change: [1, 1]});
75
+ await reporting.rmsVoltage(endpoint, {min: 60, max: 3600, change: 0});
76
+ await reporting.rmsCurrent(endpoint, {min: 60, max: 3600, change: 0});
77
+ await reporting.instantaneousDemand(endpoint, {min: 60, max: 3600, change: 0});
78
+ await reporting.currentSummDelivered(endpoint, {min: 60, max: 3600, change: [1, 1]});
75
79
  await reporting.currentSummReceived(endpoint);
76
- await reporting.temperature(endpoint);
80
+ await reporting.temperature(endpoint, {min: 60, max: 3600, change: 0});
81
+ device.powerSource = 'DC source';
82
+ device.save();
77
83
  },
78
84
  exposes: [e.power(), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(),
79
85
  e.voltage_phase_c(), e.temperature()],
@@ -341,4 +341,22 @@ module.exports = [
341
341
  return {left: 2, right: 1};
342
342
  },
343
343
  },
344
+ {
345
+ zigbeeModel: [' Mobile outlet\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
346
+ '\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
347
+ model: 'WNRR15/WNRR20',
348
+ vendor: 'Legrand',
349
+ ota: ota.zigbeeOTA,
350
+ description: 'Outlet with power consumption monitoring',
351
+ fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
352
+ toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_identify],
353
+ exposes: [e.switch(), e.action(['identify']), e.power()],
354
+ configure: async (device, coordinatorEndpoint, logger) => {
355
+ const endpoint = device.getEndpoint(1);
356
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'haElectricalMeasurement']);
357
+ await reporting.onOff(endpoint);
358
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
359
+ await reporting.activePower(endpoint);
360
+ },
361
+ },
344
362
  ];
package/devices/lidl.js CHANGED
@@ -507,6 +507,17 @@ module.exports = [
507
507
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
508
508
  },
509
509
  },
510
+ {
511
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_z1vlyufu'}],
512
+ model: '14158704L',
513
+ vendor: 'Lidl',
514
+ description: 'Livarno Home LED floor lamp, RGBW',
515
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
516
+ meta: {applyRedFix: true, enhancedHue: false},
517
+ configure: async (device, coordinatorEndpoint, logger) => {
518
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
519
+ },
520
+ },
510
521
  {
511
522
  fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_quqaeew6'}],
512
523
  model: 'HG07834A',
package/devices/moes.js CHANGED
@@ -99,6 +99,7 @@ module.exports = [
99
99
  {
100
100
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_aoclfnxz'},
101
101
  {modelID: 'TS0601', manufacturerName: '_TZE200_ztvwu4nk'},
102
+ {modelID: 'TS0601', manufacturerName: '_TZE200_ye5jkfsb'},
102
103
  {modelID: 'TS0601', manufacturerName: '_TZE200_u9bfwha0'}],
103
104
  model: 'BHT-002-GCLZB',
104
105
  vendor: 'Moes',
package/devices/niko.js CHANGED
@@ -5,6 +5,60 @@ const reporting = require('../lib/reporting');
5
5
  const e = exposes.presets;
6
6
  const ea = exposes.access;
7
7
 
8
+ const fzLocal = {
9
+ fz: {
10
+ switch_operation_mode: {
11
+ cluster: 'manuSpecificNikoSwitchSetup',
12
+ type: ['attributeReport', 'readResponse'],
13
+ convert: (model, msg, publish, options, meta) => {
14
+ const state = {};
15
+ if (msg.data.hasOwnProperty('operationMode')) {
16
+ const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
17
+ const operationModeMap = {0x02: 'control_relay', 0x01: 'decoupled', 0x00: 'unknown'};
18
+ state[operationModeProperty] = operationModeMap[msg.data.operationMode];
19
+ }
20
+ return state;
21
+ },
22
+ },
23
+ switch_action: {
24
+ cluster: 'manuSpecificNikoSwitch',
25
+ type: ['attributeReport', 'readResponse'],
26
+ convert: (model, msg, publish, options, meta) => {
27
+ const state = {};
28
+
29
+ if (msg.data.hasOwnProperty('action')) {
30
+ // NOTE: a single press = two seperate values reported, 16 followed by 64
31
+ // a hold/release cyle = three seperate values, 16, 32, and 48
32
+ const actionProperty = `action${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
33
+ const actionMap = {16: null, 64: 'single', 32: 'hold', 48: 'release'};
34
+ state[actionProperty] = actionMap[msg.data.action];
35
+ }
36
+ return state;
37
+ },
38
+ },
39
+ },
40
+ tz: {
41
+ switch_operation_mode: {
42
+ key: ['operation_mode'],
43
+ convertSet: async (entity, key, value, meta) => {
44
+ // WARN: while we can technically write 0x00 to the operationMode attribute
45
+ // this seems to brick the device and it will need to be rejoined
46
+ const operationModeLookup = {control_relay: 0x02, decoupled: 0x01};
47
+ if (!operationModeLookup.hasOwnProperty(value)) {
48
+ throw new Error(`operation_mode was called with an invalid value (${value})`);
49
+ } else {
50
+ const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
51
+ await entity.write('manuSpecificNikoSwitchSetup', {'operationMode': operationModeLookup[value]});
52
+ return {state: {[operationModeProperty]: value.toLowerCase()}};
53
+ }
54
+ },
55
+ convertGet: async (entity, key, meta) => {
56
+ await entity.read('manuSpecificNikoSwitchSetup', ['operationMode']);
57
+ },
58
+ },
59
+ },
60
+ };
61
+
8
62
  module.exports = [
9
63
  {
10
64
  zigbeeModel: ['Connected socket outlet'],
@@ -80,15 +134,18 @@ module.exports = [
80
134
  model: '552-721X1',
81
135
  vendor: 'Niko',
82
136
  description: 'Single connectable switch',
83
- fromZigbee: [fz.on_off],
84
- toZigbee: [tz.on_off],
137
+ fromZigbee: [fz.on_off, fzLocal.fz.switch_operation_mode, fzLocal.fz.switch_action],
138
+ toZigbee: [tz.on_off, fzLocal.tz.switch_operation_mode],
85
139
  configure: async (device, coordinatorEndpoint, logger) => {
86
140
  const endpoint = device.getEndpoint(1);
87
141
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
88
142
  await reporting.onOff(endpoint);
143
+ await endpoint.read('manuSpecificNikoSwitchSetup', ['operationMode']);
89
144
  },
90
145
  exposes: [
91
146
  e.switch(),
147
+ e.action(['single', 'hold', 'release']),
148
+ exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']),
92
149
  ],
93
150
  },
94
151
  {
@@ -96,8 +153,8 @@ module.exports = [
96
153
  model: '552-721X2',
97
154
  vendor: 'Niko',
98
155
  description: 'Double connectable switch',
99
- fromZigbee: [fz.on_off],
100
- toZigbee: [tz.on_off],
156
+ fromZigbee: [fz.on_off, fzLocal.fz.switch_operation_mode, fzLocal.fz.switch_action],
157
+ toZigbee: [tz.on_off, fzLocal.tz.switch_operation_mode],
101
158
  endpoint: (device) => {
102
159
  return {'l1': 1, 'l2': 2};
103
160
  },
@@ -109,9 +166,15 @@ module.exports = [
109
166
  await reporting.bind(ep2, coordinatorEndpoint, ['genOnOff']);
110
167
  await reporting.onOff(ep1);
111
168
  await reporting.onOff(ep2);
169
+ await ep1.read('manuSpecificNikoSwitchSetup', ['operationMode']);
170
+ await ep2.read('manuSpecificNikoSwitchSetup', ['operationMode']);
112
171
  },
113
172
  exposes: [
114
173
  e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
174
+ e.action(['single', 'hold', 'release']).withEndpoint('l1'),
175
+ e.action(['single', 'hold', 'release']).withEndpoint('l2'),
176
+ exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l1'),
177
+ exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l2'),
115
178
  ],
116
179
  },
117
180
  ];
package/devices/orvibo.js CHANGED
@@ -10,7 +10,7 @@ module.exports = [
10
10
  zigbeeModel: ['ORVIBO Socket'],
11
11
  model: 'OR-ZB-S010-3C',
12
12
  vendor: 'ORVIBO',
13
- description: 'Smart Socket',
13
+ description: 'Smart socket',
14
14
  extend: extend.switch(),
15
15
  },
16
16
  {
@@ -43,7 +43,7 @@ module.exports = [
43
43
  },
44
44
  {
45
45
  zigbeeModel: ['NLG-RGBW light'],
46
- model: 'NLG-RGBW light',
46
+ model: 'NLG-RGBW__light',
47
47
  vendor: 'Paul Neuhaus',
48
48
  description: 'Various RGBW lights (e.g. 100.111.57)',
49
49
  extend: extend.light_onoff_brightness_colortemp_color(),
@@ -2714,6 +2714,15 @@ module.exports = [
2714
2714
  meta: {turnsOffAtBrightness1: true},
2715
2715
  ota: ota.zigbeeOTA,
2716
2716
  },
2717
+ {
2718
+ zigbeeModel: ['5060930P7_01', '5060930P7_02', '5060930P7_03', '5060930P7_04'],
2719
+ model: '5060930P7',
2720
+ vendor: 'Philips',
2721
+ description: 'Hue White & Color Ambiance Centris ceiling light (3 spots)',
2722
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2723
+ meta: {turnsOffAtBrightness1: true},
2724
+ ota: ota.zigbeeOTA,
2725
+ },
2717
2726
  {
2718
2727
  zigbeeModel: ['5060931P7_01', '5060931P7_02', '5060931P7_03', '5060931P7_04'],
2719
2728
  model: '5060931P7',
@@ -10,6 +10,9 @@ module.exports = [
10
10
  vendor: 'Spotmau',
11
11
  description: 'Smart wall switch - 1 gang',
12
12
  extend: extend.switch(),
13
+ endpoint: (device) => {
14
+ return {default: 16};
15
+ },
13
16
  configure: async (device, coordinatorEndpoint, logger) => {
14
17
  await reporting.bind(device.getEndpoint(16), coordinatorEndpoint, ['genOnOff', 'genBasic']);
15
18
  },
package/devices/tuya.js CHANGED
@@ -450,7 +450,9 @@ module.exports = [
450
450
  const endpoint = device.getEndpoint(1);
451
451
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
452
452
  },
453
- exposes: [e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET)],
453
+ exposes: [e.light_brightness().withMinBrightness().withMaxBrightness().setAccess(
454
+ 'state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).setAccess(
455
+ 'min_brightness', ea.STATE_SET).setAccess('max_brightness', ea.STATE_SET)],
454
456
  whiteLabel: [
455
457
  {vendor: 'Larkkey', model: 'ZSTY-SM-1DMZG-EU'},
456
458
  {vendor: 'Earda', model: 'EDM-1ZAA-EU'},
@@ -703,10 +705,7 @@ module.exports = [
703
705
  extend: extend.light_onoff_brightness_colortemp_color(),
704
706
  },
705
707
  {
706
- fingerprint: [
707
- {type: 'EndDevice', manufacturerID: 4098, endpoints: [{ID: 1, inputClusters: [], outputClusters: []}]},
708
- {manufacturerName: '_TZ2000_a476raq2'},
709
- ],
708
+ fingerprint: [{manufacturerName: '_TZ2000_a476raq2'}],
710
709
  zigbeeModel: ['TS0201', 'SNTZ003'],
711
710
  model: 'TS0201',
712
711
  vendor: 'TuYa',
@@ -715,6 +714,10 @@ module.exports = [
715
714
  fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
716
715
  toZigbee: [],
717
716
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
717
+ configure: async (device, coordinatorEndpoint, logger) => {
718
+ const endpoint = device.getEndpoint(1);
719
+ await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
720
+ },
718
721
  },
719
722
  {
720
723
  fingerprint: [{modelID: 'TS0201', manufacturerName: '_TZ3000_bguser20'}],
@@ -1045,6 +1048,7 @@ module.exports = [
1045
1048
  {modelID: 'TS0601', manufacturerName: '_TZE200_3i3exuay'},
1046
1049
  {modelID: 'TS0601', manufacturerName: '_TZE200_tvrvdj6o'},
1047
1050
  {modelID: 'zo2pocs\u0000', manufacturerName: '_TYST11_fzo2pocs'},
1051
+ {modelID: 'TS0601', manufacturerName: '_TZE200_cf1sl3tj'},
1048
1052
  // Roller blinds:
1049
1053
  {modelID: 'TS0601', manufacturerName: '_TZE200_sbordckq'},
1050
1054
  {modelID: 'TS0601', manufacturerName: '_TZE200_fctwhugx'},
@@ -1073,6 +1077,7 @@ module.exports = [
1073
1077
  {vendor: 'TuYa', model: 'ZD82TN', description: 'Curtain motor'},
1074
1078
  {vendor: 'Moes', model: 'AM43-0.45/40-ES-EB'},
1075
1079
  {vendor: 'Larkkey', model: 'ZSTY-SM-1SRZG-EU'},
1080
+ {vendor: 'Zemismart', model: 'ZM85EL-2Z', description: 'Roman Rod I type curtains track'},
1076
1081
  {vendor: 'Zemismart', model: 'ZM25TQ', description: 'Tubular motor'},
1077
1082
  {vendor: 'Zemismart', model: 'AM43', description: 'Roller blind motor'},
1078
1083
  {vendor: 'Zemismart', model: 'M2805EGBZTN', description: 'Tubular motor'},
@@ -1100,6 +1105,7 @@ module.exports = [
1100
1105
  {modelID: 'TS0601', manufacturerName: '_TZE200_9sfg7gm0'}, // HomeCloud
1101
1106
  {modelID: 'TS0601', manufacturerName: '_TZE200_2atgpdho'}, // HY367
1102
1107
  {modelID: 'TS0601', manufacturerName: '_TZE200_cpmgn2cf'},
1108
+ {modelID: 'TS0601', manufacturerName: '_TZE200_4eeyebrt'}, // Immax 07732B
1103
1109
  ],
1104
1110
  model: 'TS0601_thermostat',
1105
1111
  vendor: 'TuYa',
@@ -1109,6 +1115,7 @@ module.exports = [
1109
1115
  {vendor: 'Moes', model: 'HY369RT'},
1110
1116
  {vendor: 'SHOJZJ', model: '378RT'},
1111
1117
  {vendor: 'Silvercrest', model: 'TVR01'},
1118
+ {vendor: 'Immax', model: '07732B'},
1112
1119
  ],
1113
1120
  meta: {tuyaThermostatPreset: tuya.thermostatPresets, tuyaThermostatSystemMode: tuya.thermostatSystemModes3},
1114
1121
  ota: ota.zigbeeOTA,
@@ -1702,7 +1709,7 @@ module.exports = [
1702
1709
  },
1703
1710
  },
1704
1711
  {
1705
- zigbeeModel: ['HY0017', '005f0c3'],
1712
+ zigbeeModel: ['HY0017', '005f0c3b'],
1706
1713
  model: 'U86KCJ-ZP',
1707
1714
  vendor: 'TuYa',
1708
1715
  description: 'Smart 6 key scene wall switch',
@@ -2176,7 +2183,8 @@ module.exports = [
2176
2183
  exposes: [e.illuminance_lux(), e.brightness_state()],
2177
2184
  },
2178
2185
  {
2179
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'}],
2186
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'},
2187
+ {modelID: 'TS0601', manufacturerName: '_TZE200_pay2byax'}],
2180
2188
  model: 'TM001-ZA/TM081',
2181
2189
  vendor: 'TuYa',
2182
2190
  description: 'Door and window sensor',
package/devices/xiaomi.js CHANGED
@@ -1170,9 +1170,9 @@ module.exports = [
1170
1170
  vendor: 'Xiaomi',
1171
1171
  description: 'Aqara smart natural gas detector',
1172
1172
  fromZigbee: [fz.aqara_opple],
1173
- toZigbee: [tz.JTBZ01AQA_gas, tz.JTBZ01AQA_gas_density, tz.JTBZ01AQA_gas_sensitivity, tz.JTBZ01AQA_selftest,
1174
- tz.JTBZ01AQA_mute_buzzer, tz.JTBZ01AQA_mute, tz.JTBZ01AQA_linkage_alarm, tz.JTBZ01AQA_state, tz.aqara_power_outage_count],
1175
- exposes: [e.gas().withAccess(ea.STATE_GET), e.power_outage_count().withAccess(ea.STATE_GET),
1173
+ toZigbee: [tz.aqara_alarm, tz.aqara_density, tz.JTBZ01AQA_gas_sensitivity, tz.aqara_selftest, tz.aqara_mute_buzzer,
1174
+ tz.aqara_mute, tz.aqara_linkage_alarm, tz.JTBZ01AQA_state, tz.aqara_power_outage_count],
1175
+ exposes: [e.gas().withAccess(ea.STATE_GET),
1176
1176
  exposes.numeric('gas_density', ea.STATE_GET).withUnit('%LEL').withDescription('Value of gas concentration'),
1177
1177
  exposes.enum('gas_sensitivity', ea.ALL, ['10%LEL', '15%LEL']).withDescription('Gas concentration value at which ' +
1178
1178
  'an alarm is triggered ("10%LEL" is more sensitive than "15%LEL")'),
@@ -1186,7 +1186,7 @@ module.exports = [
1186
1186
  'is detected, other detectors with this option enabled will also sound the alarm buzzer'),
1187
1187
  exposes.binary('state', ea.STATE_GET, 'preparation', 'work').withDescription('"Preparation" or "work" ' +
1188
1188
  '(measurement of the gas concentration value and triggering of an alarm are only performed in the "work" state)'),
1189
- ],
1189
+ e.power_outage_count().withAccess(ea.STATE_GET)],
1190
1190
  configure: async (device, coordinatorEndpoint, logger) => {
1191
1191
  const endpoint = device.getEndpoint(1);
1192
1192
  await endpoint.read('aqaraOpple', [0x013a], {manufacturerCode: 0x115f});
@@ -1199,6 +1199,40 @@ module.exports = [
1199
1199
  },
1200
1200
  ota: ota.zigbeeOTA,
1201
1201
  },
1202
+ {
1203
+ zigbeeModel: ['lumi.sensor_smoke.acn03'],
1204
+ model: 'JY-GZ-01AQ',
1205
+ vendor: 'Xiaomi',
1206
+ description: 'Aqara smart smoke detector',
1207
+ fromZigbee: [fz.aqara_opple, fz.battery],
1208
+ toZigbee: [tz.aqara_alarm, tz.aqara_density, tz.aqara_selftest, tz.aqara_mute_buzzer, tz.aqara_mute,
1209
+ tz.JYGZ01AQ_heartbeat_indicator, tz.aqara_linkage_alarm],
1210
+ exposes: [e.smoke().withAccess(ea.STATE_GET),
1211
+ exposes.numeric('smoke_density', ea.STATE_GET).withDescription('Value of smoke concentration'),
1212
+ exposes.numeric('smoke_density_dbm', ea.STATE).withUnit('dB/m').withDescription('Value of smoke concentration in dB/m'),
1213
+ exposes.enum('selftest', ea.SET, ['Test']).withDescription('Starts the self-test process (checking the indicator ' +
1214
+ 'light and buzzer work properly)'),
1215
+ exposes.binary('test', ea.STATE, true, false).withDescription('Self-test in progress'),
1216
+ exposes.enum('mute_buzzer', ea.SET, ['Mute']).withDescription('Mute the buzzer for 80 seconds (buzzer cannot be ' +
1217
+ 'pre-muted, because this function only works when the alarm is triggered)'),
1218
+ exposes.binary('mute', ea.STATE_GET, true, false).withDescription('Buzzer muted'),
1219
+ exposes.binary('heartbeat_indicator', ea.ALL, true, false).withDescription('When this option is enabled then in ' +
1220
+ 'the normal monitoring state, the green indicator light flashes every 60 seconds'),
1221
+ exposes.binary('linkage_alarm', ea.ALL, true, false).withDescription('When this option is enabled and a smoke ' +
1222
+ 'is detected, other detectors with this option enabled will also sound the alarm buzzer'),
1223
+ e.temperature(), e.battery()],
1224
+ meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
1225
+ configure: async (device, coordinatorEndpoint, logger) => {
1226
+ const endpoint = device.getEndpoint(1);
1227
+ await endpoint.read('genPowerCfg', ['batteryVoltage']);
1228
+ await endpoint.read('aqaraOpple', [0x013a], {manufacturerCode: 0x115f});
1229
+ await endpoint.read('aqaraOpple', [0x013b], {manufacturerCode: 0x115f});
1230
+ await endpoint.read('aqaraOpple', [0x013c], {manufacturerCode: 0x115f});
1231
+ await endpoint.read('aqaraOpple', [0x0126], {manufacturerCode: 0x115f});
1232
+ await endpoint.read('aqaraOpple', [0x014b], {manufacturerCode: 0x115f});
1233
+ },
1234
+ ota: ota.zigbeeOTA,
1235
+ },
1202
1236
  {
1203
1237
  zigbeeModel: ['lumi.lock.v1'],
1204
1238
  model: 'A6121',
package/lib/exposes.js CHANGED
@@ -218,6 +218,12 @@ class Light extends Base {
218
218
  return this;
219
219
  }
220
220
 
221
+ withMaxBrightness() {
222
+ assert(!this.endpoint, 'Cannot add feature after adding endpoint');
223
+ this.features.push(new Numeric('max_brightness', access.ALL).withValueMin(1).withValueMax(255).withDescription('Maximum light brightness'));
224
+ return this;
225
+ }
226
+
221
227
  withLevelConfig() {
222
228
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
223
229
  const levelConfig = new Composite('level_config', 'level_config')
package/lib/tuya.js CHANGED
@@ -58,6 +58,61 @@ function getDataValue(dpValue) {
58
58
  }
59
59
  }
60
60
 
61
+ function getTypeName(dpValue) {
62
+ const entry = Object.entries(dataTypes).find(([typeName, typeId]) => typeId === dpValue.datatype);
63
+ return (entry ? entry[0] : 'unknown');
64
+ }
65
+
66
+ function getDataPointNames(dpValue) {
67
+ const entries = Object.entries(dataPoints).filter(([dpName, dpId]) => dpId === dpValue.dp);
68
+ return entries.map(([dpName, dpId]) => dpName);
69
+ }
70
+
71
+ function logDataPoint(where, msg, dpValue, meta) {
72
+ meta.logger.info(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
73
+ dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
74
+ msg.type}', datatype='${getTypeName(dpValue)}', value='${
75
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
76
+ }
77
+
78
+ function logUnexpectedDataPoint(where, msg, dpValue, meta) {
79
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received unexpected Tuya DataPoint #${
80
+ dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
81
+ msg.type}', datatype='${getTypeName(dpValue)}', value='${
82
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
83
+ }
84
+
85
+ function logUnexpectedDataType(where, msg, dpValue, meta, expectedDataType) {
86
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
87
+ dpValue.dp} with unexpected datatype from ${meta.device.ieeeAddr} with raw data '${
88
+ JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
89
+ getTypeName(dpValue)}' (instead of '${expectedDataType}'), value='${
90
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
91
+ }
92
+
93
+ function logUnexpectedDataValue(where, msg, dpValue, meta, valueKind, expectedMinValue=null, expectedMaxValue=null) {
94
+ if (expectedMinValue === null) {
95
+ if (expectedMaxValue === null) {
96
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
97
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr}`);
98
+ } else {
99
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
100
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
101
+ } which is higher than the expected maximum of ${expectedMaxValue}`);
102
+ }
103
+ } else {
104
+ if (expectedMaxValue === null) {
105
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
106
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
107
+ } which is lower than the expected minimum of ${expectedMinValue}`);
108
+ } else {
109
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
110
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
111
+ } which is outside the expected range from ${expectedMinValue} to ${expectedMaxValue}`);
112
+ }
113
+ }
114
+ }
115
+
61
116
  function convertDecimalValueTo4ByteHexArray(value) {
62
117
  const hexValue = Number(value).toString(16).padStart(8, '0');
63
118
  const chunk1 = hexValue.substr(0, 2);
@@ -229,11 +284,13 @@ const dataPoints = {
229
284
  heatingSetpoint: 2,
230
285
  coverPosition: 2,
231
286
  dimmerLevel: 3,
287
+ dimmerMinLevel: 3,
232
288
  localTemp: 3,
233
289
  coverArrived: 3,
234
290
  occupancy: 3,
235
291
  mode: 4,
236
292
  fanMode: 5,
293
+ dimmerMaxLevel: 5,
237
294
  motorDirection: 5,
238
295
  config: 5,
239
296
  childLock: 7,
@@ -873,6 +930,12 @@ module.exports = {
873
930
  sendDataPointStringBuffer,
874
931
  firstDpValue,
875
932
  getDataValue,
933
+ getTypeName,
934
+ getDataPointNames,
935
+ logDataPoint,
936
+ logUnexpectedDataPoint,
937
+ logUnexpectedDataType,
938
+ logUnexpectedDataValue,
876
939
  dataTypes,
877
940
  dataPoints,
878
941
  dpValueFromIntValue,
package/lib/xiaomi.js CHANGED
@@ -174,9 +174,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
174
174
  payload.switch_type = {1: 'toggle', 2: 'momentary'}[value];
175
175
  break;
176
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');
177
+ if (!['JT-BZ-01AQ/A'].includes(model.model)) {
178
+ payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
179
+ // DEPRECATED: remove illuminance_lux here.
180
+ payload.illuminance_lux = calibrateAndPrecisionRoundOptions(value, options, 'illuminance_lux');
181
+ }
180
182
  break;
181
183
  case '100':
182
184
  if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'LLKZMK11LM', 'QBKG12LM', 'QBKG03LM'].includes(model.model)) {
@@ -300,25 +302,52 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
300
302
  }
301
303
  break;
302
304
  case '159':
303
- payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value]; // JT-BZ-01AQ/A
305
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
306
+ payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value];
307
+ }
304
308
  break;
305
309
  case '160':
306
- payload.gas = value === 1; // JT-BZ-01AQ/A
310
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
311
+ payload.gas = value === 1;
312
+ } else if (['JY-GZ-01AQ'].includes(model.model)) {
313
+ payload.smoke = value === 1;
314
+ }
307
315
  break;
308
316
  case '161':
309
- payload.gas_density = value; // JT-BZ-01AQ/A
317
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
318
+ payload.gas_density = value;
319
+ } else if (['JY-GZ-01AQ'].includes(model.model)) {
320
+ payload.smoke_density = value;
321
+ payload.smoke_density_dbm = {0: 0, 1: 0.085, 2: 0.088, 3: 0.093, 4: 0.095, 5: 0.100, 6: 0.105, 7: 0.110,
322
+ 8: 0.115, 9: 0.120, 10: 0.125}[value];
323
+ }
310
324
  break;
311
325
  case '162':
312
- payload.test = value === 1; // JT-BZ-01AQ/A
326
+ if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
327
+ payload.test = value === 1;
328
+ }
313
329
  break;
314
330
  case '163':
315
- payload.mute = value === 1; // JT-BZ-01AQ/A
331
+ if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
332
+ payload.mute = value === 1;
333
+ }
316
334
  break;
317
335
  case '164':
318
- payload.state = value === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
336
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
337
+ payload.state = {0: 'work', 1: 'preparation'}[value];
338
+ } else if (['JY-GZ-01AQ'].includes(model.model)) {
339
+ payload.heartbeat_indicator = value === 1;
340
+ }
341
+ break;
342
+ case '165':
343
+ if (['JY-GZ-01AQ'].includes(model.model)) {
344
+ payload.linkage_alarm = value === 1;
345
+ }
319
346
  break;
320
347
  case '166':
321
- payload.linkage_alarm = value === 1; // JT-BZ-01AQ/A
348
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
349
+ payload.linkage_alarm = value === 1;
350
+ }
322
351
  break;
323
352
  case '240':
324
353
  payload.flip_indicator_light = value === 1 ? 'ON' : 'OFF';
@@ -344,19 +373,40 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
344
373
  payload.click_mode = {1: 'fast', 2: 'multi'}[value];
345
374
  break;
346
375
  case '294':
347
- payload.mute = value === 1; // JT-BZ-01AQ/A
376
+ if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
377
+ payload.mute = value === 1;
378
+ }
348
379
  break;
349
380
  case '295':
350
- payload.test = value === 1; // JT-BZ-01AQ/A
381
+ if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
382
+ payload.test = value === 1;
383
+ }
351
384
  break;
352
385
  case '313':
353
- payload.state = value === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
386
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
387
+ payload.state = {0: 'work', 1: 'preparation'}[value];
388
+ }
354
389
  break;
355
390
  case '314':
356
- payload.gas = value === 1; // JT-BZ-01AQ/A
391
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
392
+ payload.gas = value === 1;
393
+ } else if (['JY-GZ-01AQ'].includes(model.model)) {
394
+ payload.smoke = value === 1;
395
+ }
357
396
  break;
358
397
  case '315':
359
- payload.gas_density = value; // JT-BZ-01AQ/A
398
+ if (['JT-BZ-01AQ/A'].includes(model.model)) {
399
+ payload.gas_density = value;
400
+ } else if (['JY-GZ-01AQ'].includes(model.model)) {
401
+ payload.smoke_density = value;
402
+ payload.smoke_density_dbm = {0: 0, 1: 0.085, 2: 0.088, 3: 0.093, 4: 0.095, 5: 0.100, 6: 0.105, 7: 0.110,
403
+ 8: 0.115, 9: 0.120, 10: 0.125}[value];
404
+ }
405
+ break;
406
+ case '316':
407
+ if (['JY-GZ-01AQ'].includes(model.model)) {
408
+ payload.heartbeat_indicator = value === 1;
409
+ }
360
410
  break;
361
411
  case '322':
362
412
  if (['RTCZCGQ11LM'].includes(model.model)) {
@@ -380,7 +430,9 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
380
430
  }
381
431
  break;
382
432
  case '331':
383
- payload.linkage_alarm = value === 1; // JT-BZ-01AQ/A
433
+ if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
434
+ payload.linkage_alarm = value === 1;
435
+ }
384
436
  break;
385
437
  case '512':
386
438
  if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.465",
3
+ "version": "14.0.468",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "zigbee-herdsman-converters",
9
- "version": "14.0.465",
9
+ "version": "14.0.468",
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.465",
3
+ "version": "14.0.468",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [