zigbee-herdsman-converters 14.0.528 → 14.0.531

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.
@@ -5702,7 +5702,10 @@ const converters = {
5702
5702
  globalStore.putValue(msg.endpoint, 'occupancy_timer', timer);
5703
5703
  }
5704
5704
 
5705
- const illuminance = msg.data['illuminance'] - 65536;
5705
+ // Sometimes RTCGQ14LM reports high illuminance values in the dark
5706
+ // https://github.com/Koenkk/zigbee2mqtt/issues/12596
5707
+ const illuminance = msg.data['illuminance'] > 130536 ? 0 : msg.data['illuminance'] - 65536;
5708
+
5706
5709
  const payload = {occupancy: true, illuminance: calibrateAndPrecisionRoundOptions(illuminance, options, 'illuminance')};
5707
5710
  utils.noOccupancySince(msg.endpoint, options, publish, 'start');
5708
5711
  return payload;
@@ -130,14 +130,6 @@ module.exports = [
130
130
  maximumReportInterval: constants.repInterval.MAX,
131
131
  reportableChange: 1,
132
132
  }], options);
133
-
134
- await endpoint.configureReporting('hvacThermostat', [{
135
- attribute: 'danfossPreheatStatus',
136
- minimumReportInterval: constants.repInterval.MINUTE,
137
- maximumReportInterval: constants.repInterval.MAX,
138
- reportableChange: 1,
139
- }], options);
140
-
141
133
  await endpoint.configureReporting('hvacThermostat', [{
142
134
  attribute: 'danfossAdaptionRunStatus',
143
135
  minimumReportInterval: constants.repInterval.MINUTE,
@@ -145,6 +137,17 @@ module.exports = [
145
137
  reportableChange: 1,
146
138
  }], options);
147
139
 
140
+ try {
141
+ await endpoint.configureReporting('hvacThermostat', [{
142
+ attribute: 'danfossPreheatStatus',
143
+ minimumReportInterval: constants.repInterval.MINUTE,
144
+ maximumReportInterval: constants.repInterval.MAX,
145
+ reportableChange: 1,
146
+ }], options);
147
+ } catch (e) {
148
+ /* not supported by all */
149
+ }
150
+
148
151
  try {
149
152
  await endpoint.read('hvacThermostat', [
150
153
  'danfossWindowOpenFeatureEnable',
@@ -5,11 +5,18 @@ const e = exposes.presets;
5
5
  const fz = require('../converters/fromZigbee');
6
6
 
7
7
  module.exports = [
8
+ {
9
+ zigbeeModel: ['ZG50CC-CCT-DRIVER'],
10
+ model: 'ZG50CC-CCT-DRIVER',
11
+ vendor: 'Envilar',
12
+ description: 'Zigbee LED driver',
13
+ extend: extend.light_onoff_brightness(),
14
+ },
8
15
  {
9
16
  zigbeeModel: ['ZGR904-S'],
10
17
  model: 'ZGR904-S',
11
18
  vendor: 'Envilar',
12
- description: 'Envilar touchlink remote',
19
+ description: 'Touchlink remote',
13
20
  meta: {battery: {dontDividePercentage: true}},
14
21
  fromZigbee: [fz.command_recall, fz.command_on, fz.command_off, fz.command_move, fz.command_stop, fz.battery],
15
22
  toZigbee: [],
package/devices/icasa.js CHANGED
@@ -70,7 +70,6 @@ module.exports = [
70
70
  model: 'ICZB-KPD18S',
71
71
  vendor: 'iCasa',
72
72
  description: 'Zigbee 3.0 Keypad Pulse 8S',
73
- meta: {battery: {dontDividePercentage: true}},
74
73
  fromZigbee: [fz.command_recall, fz.legacy.scenes_recall_click, fz.command_on, fz.legacy.genOnOff_cmdOn, fz.command_off,
75
74
  fz.legacy.genOnOff_cmdOff, fz.battery, fz.legacy.cmd_move_with_onoff, fz.legacy.cmd_stop_with_onoff],
76
75
  exposes: [e.battery(), e.action(['on', 'recall_*', 'off', 'brightness_stop', 'brightness_move_up', 'brightness_move_down'])],
@@ -189,10 +189,26 @@ module.exports = [
189
189
  zigbeeModel: ['ZGRC-TEUR-001'],
190
190
  model: '511.544',
191
191
  vendor: 'Iluminize',
192
- description: 'Zigbee 3.0 wall dimmer RGBW 4 zone',
192
+ description: 'Zigbee 3.0 wall dimmer RGBW 4 zones',
193
193
  fromZigbee: [fz.command_move_to_color, fz.command_move_hue, fz.command_on, fz.command_off, fz.command_move],
194
194
  toZigbee: [],
195
195
  exposes: [e.action(['recall_*', 'on', 'off', 'color_move', 'color_temperature_move',
196
196
  'hue_move', 'brightness_step_down', 'brightness_step_up', 'brightness_move_down', 'brightness_move_up', 'brightness_stop'])],
197
197
  },
198
+ {
199
+ zigbeeModel: ['ZGRC-TEUR-003'],
200
+ model: '511.524',
201
+ vendor: 'Iluminize',
202
+ description: 'Zigbee 3.0 wall dimmer CCT 4 zones',
203
+ fromZigbee: [fz.command_on, fz.command_off, fz.command_recall,
204
+ fz.command_move_to_color_temp, fz.command_step, fz.command_move, fz.command_stop],
205
+ toZigbee: [],
206
+ meta: {multiEndpoint: true},
207
+ exposes: [e.action([
208
+ 'recall_*', 'on', 'off',
209
+ 'brightness_step_down', 'brightness_step_up',
210
+ 'brightness_move_down', 'brightness_move_up', 'brightness_stop',
211
+ 'color_move', 'color_temperature_move', 'hue_move',
212
+ 'color_loop_set', 'enhanced_move_to_hue_and_saturation', 'hue_stop'])],
213
+ },
198
214
  ];
@@ -8,9 +8,9 @@ const e = exposes.presets;
8
8
  module.exports = [
9
9
  {
10
10
  zigbeeModel: ['tint-ExtendedColor'],
11
- model: '404036',
11
+ model: '404036/45327',
12
12
  vendor: 'Müller Licht',
13
- description: 'Tint LED-globeform white+color',
13
+ description: 'Tint LED white+color',
14
14
  extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 556]}),
15
15
  toZigbee: extend.light_onoff_brightness_colortemp_color().toZigbee.concat([tz.tint_scene]),
16
16
  },
@@ -164,6 +164,14 @@ module.exports = [
164
164
  extend: extend.light_onoff_brightness_colortemp(),
165
165
  toZigbee: extend.light_onoff_brightness_colortemp().toZigbee.concat([tz.tint_scene]),
166
166
  },
167
+ {
168
+ zigbeeModel: ['tint-ColorTemperature2'],
169
+ model: '404038',
170
+ vendor: 'Müller Licht',
171
+ description: 'Tint retro filament LED-bulb E27, Globe bulb gold, white+ambiance (1800-6500K), dimmable, 5,5W',
172
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
173
+ toZigbee: extend.light_onoff_brightness_colortemp().toZigbee.concat([tz.tint_scene]),
174
+ },
167
175
  {
168
176
  fingerprint: [{
169
177
  // Identify through fingerprint as modelID is the same as Sunricher ZG192910-4
@@ -1,7 +1,188 @@
1
1
  const fz = require('../converters/fromZigbee');
2
+ const tz = require('../converters/toZigbee');
2
3
  const exposes = require('../lib/exposes');
3
4
  const reporting = require('../lib/reporting');
5
+ const utils = require('../lib/utils');
4
6
  const e = exposes.presets;
7
+ const ea = exposes.access;
8
+
9
+ const switchTypeValues = [
10
+ 'maintained_state',
11
+ 'maintained_toggle',
12
+ 'momentary_state',
13
+ 'momentary_press',
14
+ 'momentary_release',
15
+ ];
16
+
17
+ const defaultOnOffStateValues = [
18
+ 'on',
19
+ 'off',
20
+ 'previous',
21
+ ];
22
+
23
+ const fzPerenio = {
24
+ diagnostic: {
25
+ cluster: 'haDiagnostic',
26
+ type: ['attributeReport', 'readResponse'],
27
+ convert: (model, msg, publish, options, meta) => {
28
+ const result = {};
29
+ if (msg.data.hasOwnProperty('lastMessageLqi')) {
30
+ result['last_message_lqi'] = msg.data['lastMessageLqi'];
31
+ }
32
+ if (msg.data.hasOwnProperty('lastMessageRssi')) {
33
+ result['last_message_rssi'] = msg.data['lastMessageRssi'];
34
+ }
35
+ return result;
36
+ },
37
+ },
38
+ switch_type: {
39
+ cluster: 'genMultistateValue',
40
+ type: ['attributeReport', 'readResponse'],
41
+ convert: (model, msg, publish, options, meta) => {
42
+ const result = {};
43
+ const switchTypeLookup = {
44
+ 0x0001: 'momentary_state',
45
+ 0x0010: 'maintained_state',
46
+ 0x00CC: 'maintained_toggle',
47
+ 0x00CD: 'momentary_release',
48
+ 0x00DC: 'momentary_press',
49
+ };
50
+ if (msg.data.hasOwnProperty('presentValue')) {
51
+ const property = utils.postfixWithEndpointName('switch_type', msg, model);
52
+ result[property] = switchTypeLookup[msg.data['presentValue']];
53
+ }
54
+ return result;
55
+ },
56
+ },
57
+ smart_plug: {
58
+ cluster: '64635',
59
+ type: ['attributeReport', 'readResponse'],
60
+ convert: (model, msg, publish, options, meta) => {
61
+ const result = {};
62
+ if (msg.data.hasOwnProperty(3)) {
63
+ result['rms_voltage'] = msg.data[3];
64
+ }
65
+ if (msg.data.hasOwnProperty(10)) {
66
+ result['active_power'] = msg.data[10];
67
+ }
68
+ if (msg.data.hasOwnProperty(14)) {
69
+ result['consumed_energy'] = msg.data[14];
70
+ }
71
+ if (msg.data.hasOwnProperty(24)) {
72
+ result['rssi'] = msg.data[24];
73
+ }
74
+ const powerOnStateLookup = {
75
+ 0: 'off',
76
+ 1: 'on',
77
+ 2: 'previous',
78
+ };
79
+ if (msg.data.hasOwnProperty(0)) {
80
+ result['default_on_off_state'] = powerOnStateLookup[msg.data[0]];
81
+ }
82
+ if (msg.data.hasOwnProperty(1)) {
83
+ if (msg.data[1] == 0) {
84
+ result['alarm_voltage_min'] = false;
85
+ result['alarm_voltage_max'] = false;
86
+ result['alarm_power_max'] = false;
87
+ } else {
88
+ if (msg.data[1] & 1) {
89
+ result['alarm_voltage_min'] = true;
90
+ }
91
+ if (msg.data[1] & 2) {
92
+ result['alarm_voltage_max'] = true;
93
+ }
94
+ if (msg.data[1] & 4) {
95
+ result['alarm_power_max'] = true;
96
+ }
97
+ }
98
+ }
99
+ return result;
100
+ },
101
+ },
102
+ };
103
+
104
+ const tzPerenio = {
105
+ switch_type: {
106
+ key: ['switch_type'],
107
+ convertSet: async (entity, key, value, meta) => {
108
+ const switchTypeLookup = {
109
+ 'momentary_state': 0x0001,
110
+ 'maintained_state': 0x0010,
111
+ 'maintained_toggle': 0x00CC,
112
+ 'momentary_release': 0x00CD,
113
+ 'momentary_press': 0x00DC,
114
+ };
115
+ await entity.write('genMultistateValue', {presentValue: switchTypeLookup[value]}, utils.getOptions(meta.mapped, entity));
116
+ return {state: {switch_type: value}};
117
+ },
118
+ convertGet: async (entity, key, meta) => {
119
+ await entity.read('genMultistateValue', ['presentValue']);
120
+ },
121
+ },
122
+ default_state: {
123
+ key: ['default_on_off_state'],
124
+ convertSet: async (entity, key, val, meta) => {
125
+ const powerOnStateLookup = {
126
+ 'off': 0,
127
+ 'on': 1,
128
+ 'previous': 2,
129
+ };
130
+ await entity.write(64635, {0: {value: powerOnStateLookup[val], type: 0x20}}, {manufacturerCode: 0x007B});
131
+ return {state: {default_on_off_state: val}};
132
+ },
133
+ convertGet: async (entity, key, meta) => {
134
+ await entity.read(64635, [0]);
135
+ },
136
+ },
137
+ alarms_reset: {
138
+ key: ['alarm_voltage_min', 'alarm_voltage_max', 'alarm_power_max'],
139
+ convertSet: async (entity, key, val, meta) => {
140
+ await entity.write(64635, {1: {value: 0, type: 0x20}}, {manufacturerCode: 0x007B});
141
+ return {state: {alarm_voltage_min: false, alarm_voltage_max: false, alarm_power_max: false}};
142
+ },
143
+ convertGet: async (entity, key, meta) => {
144
+ await entity.read(64635, [1]);
145
+ },
146
+ },
147
+ on_off_mod: {
148
+ key: ['state', 'on_time', 'off_wait_time'],
149
+ convertSet: async (entity, key, value, meta) => {
150
+ const state = meta.message.hasOwnProperty('state') ? meta.message.state.toLowerCase() : null;
151
+ utils.validateValue(state, ['toggle', 'off', 'on']);
152
+ const alarmVoltageMin = meta.state[`alarm_voltage_min${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
153
+ const alarmVoltageMax = meta.state[`alarm_voltage_max${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
154
+ const alarmPowerMax = meta.state[`alarm_power_max${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
155
+ if (alarmVoltageMin || alarmVoltageMax || alarmPowerMax) {
156
+ return {state: {state: 'OFF'}};
157
+ }
158
+ if (state === 'on' && (meta.message.hasOwnProperty('on_time') || meta.message.hasOwnProperty('off_wait_time'))) {
159
+ const onTime = meta.message.hasOwnProperty('on_time') ? meta.message.on_time : 0;
160
+ const offWaitTime = meta.message.hasOwnProperty('off_wait_time') ? meta.message.off_wait_time : 0;
161
+
162
+ if (typeof onTime !== 'number') {
163
+ throw Error('The on_time value must be a number!');
164
+ }
165
+ if (typeof offWaitTime !== 'number') {
166
+ throw Error('The off_wait_time value must be a number!');
167
+ }
168
+
169
+ const payload = {ctrlbits: 0, ontime: Math.round(onTime * 10), offwaittime: Math.round(offWaitTime * 10)};
170
+ await entity.command('genOnOff', 'onWithTimedOff', payload, utils.getOptions(meta.mapped, entity));
171
+ } else {
172
+ await entity.command('genOnOff', state, {}, utils.getOptions(meta.mapped, entity));
173
+ if (state === 'toggle') {
174
+ const currentState = meta.state[`state${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
175
+ return currentState ? {state: {state: currentState === 'OFF' ? 'ON' : 'OFF'}} : {};
176
+ } else {
177
+ return {state: {state: state.toUpperCase()}};
178
+ }
179
+ }
180
+ },
181
+ convertGet: async (entity, key, meta) => {
182
+ await entity.read('genOnOff', ['onOff']);
183
+ },
184
+ },
185
+ };
5
186
 
6
187
  module.exports = [
7
188
  {
@@ -47,4 +228,97 @@ module.exports = [
47
228
  await reporting.batteryPercentageRemaining(endpoint);
48
229
  },
49
230
  },
231
+ {
232
+ zigbeeModel: ['PEHWE20', 'PEHWE2X'],
233
+ model: 'PEHWE20',
234
+ vendor: 'Perenio',
235
+ description: 'Two channel single wire mini-relay',
236
+ fromZigbee: [fz.on_off, fz.power_on_behavior, fzPerenio.diagnostic, fzPerenio.switch_type],
237
+ toZigbee: [tz.on_off, tz.power_on_behavior, tzPerenio.switch_type],
238
+ endpoint: (device) => {
239
+ return {l1: 1, l2: 2};
240
+ },
241
+ meta: {multiEndpoint: true},
242
+ configure: async (device, coordinatorEndpoint, logger) => {
243
+ const endpoint1 = device.getEndpoint(1);
244
+ const endpoint2 = device.getEndpoint(2);
245
+ const endpoint10 = device.getEndpoint(10);
246
+ await reporting.bind(endpoint1, coordinatorEndpoint, ['genOnOff']);
247
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
248
+ await reporting.bind(endpoint10, coordinatorEndpoint, ['haDiagnostic']);
249
+ const payload = [{
250
+ attribute: 'onOff',
251
+ minimumReportInterval: 0,
252
+ maximumReportInterval: 3600,
253
+ reportableChange: 0,
254
+ }];
255
+ const payloadDiagnostic = [{
256
+ attribute: 'lastMessageLqi',
257
+ minimumReportInterval: 5,
258
+ maximumReportInterval: 60,
259
+ reportableChange: 0,
260
+ }, {
261
+ attribute: 'lastMessageRssi',
262
+ minimumReportInterval: 5,
263
+ maximumReportInterval: 60,
264
+ reportableChange: 0,
265
+ }];
266
+ await endpoint1.configureReporting('genOnOff', payload);
267
+ await endpoint2.configureReporting('genOnOff', payload);
268
+ await endpoint10.configureReporting('haDiagnostic', payloadDiagnostic);
269
+ await endpoint1.read('genOnOff', ['onOff', 'startUpOnOff']);
270
+ await endpoint2.read('genOnOff', ['onOff', 'startUpOnOff']);
271
+ await endpoint1.read('genMultistateValue', ['presentValue']);
272
+ await endpoint2.read('genMultistateValue', ['presentValue']);
273
+ await endpoint10.read('haDiagnostic', ['lastMessageLqi', 'lastMessageRssi']);
274
+ },
275
+ exposes: [
276
+ e.switch().withEndpoint('l1'),
277
+ e.power_on_behavior().withEndpoint('l1'),
278
+ exposes.enum('switch_type', ea.ALL, switchTypeValues).withEndpoint('l1'),
279
+ e.switch().withEndpoint('l2'),
280
+ e.power_on_behavior().withEndpoint('l2'),
281
+ exposes.enum('switch_type', ea.ALL, switchTypeValues).withEndpoint('l2'),
282
+ exposes.numeric('last_message_lqi', ea.STATE).withUnit('lqi')
283
+ .withDescription('LQI seen by the device').withValueMin(0).withValueMax(255),
284
+ exposes.numeric('last_message_rssi', ea.STATE).withUnit('dB')
285
+ .withDescription('RSSI seen by the device').withValueMin(-128).withValueMax(127),
286
+ ],
287
+ },
288
+ {
289
+ zigbeeModel: ['PEHPL0X'],
290
+ model: 'PEHPL0X',
291
+ vendor: 'Perenio',
292
+ description: 'Power link',
293
+ fromZigbee: [fz.on_off, fzPerenio.smart_plug],
294
+ toZigbee: [tzPerenio.on_off_mod, tzPerenio.default_state, tzPerenio.alarms_reset],
295
+ configure: async (device, coordinatorEndpoint, logger) => {
296
+ const endpoint = device.getEndpoint(1);
297
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 64635]);
298
+ const payload = [{
299
+ attribute: 'onOff',
300
+ minimumReportInterval: 1,
301
+ maximumReportInterval: 3600,
302
+ reportableChange: 0,
303
+ }];
304
+ await endpoint.configureReporting('genOnOff', payload);
305
+ await endpoint.read(64635, [0, 1]);
306
+ },
307
+ exposes: [
308
+ e.switch(),
309
+ exposes.enum('default_on_off_state', ea.ALL, defaultOnOffStateValues),
310
+ exposes.numeric('rms_voltage', ea.STATE).withUnit('V').withDescription('RMS voltage'),
311
+ exposes.numeric('active_power', ea.STATE).withUnit('W').withDescription('Active power'),
312
+ exposes.numeric('consumed_energy', ea.STATE).withUnit('W*h').withDescription('Consumed energy'),
313
+ exposes.binary('alarm_voltage_min', ea.ALL, true, false)
314
+ .withDescription('Indicates if the alarm is triggered on the voltage drop below the limit, allows to reset alarms'),
315
+ exposes.binary('alarm_voltage_max', ea.ALL, true, false)
316
+ .withDescription('Indicates if the alarm is triggered on the voltage rise above the limit, allows to reset alarms'),
317
+ exposes.binary('alarm_power_max', ea.ALL, true, false)
318
+ .withDescription('Indicates if the alarm is triggered on the active power rise above the limit, allows to reset alarms'),
319
+ exposes.numeric('rssi', ea.STATE).withUnit('dB')
320
+ .withDescription('RSSI seen by the device').withValueMin(-128).withValueMax(127),
321
+ ],
322
+ },
50
323
  ];
324
+
@@ -1247,6 +1247,15 @@ module.exports = [
1247
1247
  extend: hueExtend.light_onoff_brightness_colortemp(),
1248
1248
  ota: ota.zigbeeOTA,
1249
1249
  },
1250
+ {
1251
+ zigbeeModel: ['4503748C6'],
1252
+ model: '4503748C6',
1253
+ vendor: 'Philips',
1254
+ description: 'Hue white ambiance Muscari ceiling light',
1255
+ meta: {turnsOffAtBrightness1: true},
1256
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
1257
+ ota: ota.zigbeeOTA,
1258
+ },
1250
1259
  {
1251
1260
  zigbeeModel: ['LTD003'],
1252
1261
  model: '4503848C5',
package/devices/siglis.js CHANGED
@@ -4,6 +4,7 @@ const exposes = require('../lib/exposes');
4
4
  const reporting = require('../lib/reporting');
5
5
  const e = exposes.presets;
6
6
 
7
+
7
8
  const siglisManufacturerCode = 0x129C;
8
9
  const zigfredEndpoint = 5;
9
10
 
@@ -42,6 +43,27 @@ const zifgredFromZigbee = {
42
43
  },
43
44
  };
44
45
 
46
+ const coverAndLightToZigbee = {
47
+ key: ['state', 'brightness', 'brightness_percent', 'on_time'],
48
+ options: [exposes.options.transition()],
49
+ convertSet: async (entity, key, value, meta) => {
50
+ const isCover = (typeof value === 'string' && ['open', 'close', 'stop'].includes(value.toLowerCase()));
51
+ if (isCover) {
52
+ return tz.cover_state.convertSet(entity, key, value, meta);
53
+ } else {
54
+ return tz.light_onoff_brightness.convertSet(entity, key, value, meta);
55
+ }
56
+ },
57
+ convertGet: async (entity, key, meta) => {
58
+ if (key === 'brightness') {
59
+ await entity.read('genLevelCtrl', ['currentLevel']);
60
+ } else if (key === 'state') {
61
+ await tz.on_off.convertGet(entity, key, meta);
62
+ }
63
+ },
64
+ };
65
+
66
+
45
67
  module.exports = [
46
68
  {
47
69
  zigbeeModel: ['zigfred uno'],
@@ -92,11 +114,9 @@ module.exports = [
92
114
  const dimmerEp = device.getEndpoint(7);
93
115
 
94
116
  // Bind Control EP (LED)
95
- await reporting.bind(controlEp, coordinatorEndpoint, ['genOnOff']);
96
- await reporting.bind(controlEp, coordinatorEndpoint, ['genLevelCtrl']);
117
+ await reporting.bind(controlEp, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'manuSpecificSiglisZigfred']);
97
118
  await reporting.onOff(controlEp);
98
119
  await reporting.brightness(controlEp);
99
- await reporting.bind(controlEp, coordinatorEndpoint, ['manuSpecificSiglisZigfred']);
100
120
  const payload = [{
101
121
  attribute: 'buttonEvent',
102
122
  minimumReportInterval: 0,
@@ -110,10 +130,121 @@ module.exports = [
110
130
  await reporting.onOff(relayEp);
111
131
 
112
132
  // Bind Dimmer EP
113
- await reporting.bind(dimmerEp, coordinatorEndpoint, ['genOnOff']);
114
- await reporting.bind(dimmerEp, coordinatorEndpoint, ['genLevelCtrl']);
133
+ await reporting.bind(dimmerEp, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
115
134
  await reporting.onOff(dimmerEp);
116
135
  await reporting.brightness(dimmerEp);
117
136
  },
118
137
  },
138
+ {
139
+ zigbeeModel: ['zigfred plus'],
140
+ model: 'ZFP-1A-CH',
141
+ vendor: 'Siglis',
142
+ description: 'zigfred plus smart in-wall switch',
143
+ exposes: [
144
+ e.light_brightness_colorxy().withEndpoint('l1'),
145
+ e.light_brightness().withEndpoint('l2'),
146
+ e.light_brightness().withEndpoint('l3'),
147
+ e.light_brightness().withEndpoint('l4'),
148
+ e.light_brightness().withEndpoint('l5'),
149
+ exposes.cover().withState('state', exposes.access.STATE_SET | exposes.access.STATE_GET)
150
+ .withPosition().withTilt().withEndpoint('l6'),
151
+ exposes.cover().withState('state', exposes.access.STATE_SET | exposes.access.STATE_GET)
152
+ .withPosition().withTilt().withEndpoint('l7'),
153
+ e.action([
154
+ 'button_1_single', 'button_1_double', 'button_1_hold', 'button_1_release',
155
+ 'button_2_single', 'button_2_double', 'button_2_hold', 'button_2_release',
156
+ 'button_3_single', 'button_3_double', 'button_3_hold', 'button_3_release',
157
+ 'button_4_single', 'button_4_double', 'button_4_hold', 'button_4_release',
158
+ ])],
159
+ fromZigbee: [
160
+ zifgredFromZigbee,
161
+ fz.color_colortemp,
162
+ fz.on_off,
163
+ fz.brightness,
164
+ fz.level_config,
165
+ fz.power_on_behavior,
166
+ fz.ignore_basic_report,
167
+ fz.cover_position_tilt,
168
+ fz.command_cover_open,
169
+ fz.command_cover_close,
170
+ fz.command_cover_stop,
171
+ ],
172
+ toZigbee: [
173
+ tz.light_color,
174
+ tz.ignore_transition,
175
+ tz.ignore_rate,
176
+ tz.light_brightness_move,
177
+ tz.light_brightness_step,
178
+ tz.level_config,
179
+ tz.power_on_behavior,
180
+ tz.light_hue_saturation_move,
181
+ tz.light_hue_saturation_step,
182
+ tz.light_color_options,
183
+ tz.light_color_mode,
184
+ tz.cover_position_tilt,
185
+ coverAndLightToZigbee,
186
+ ],
187
+ meta: {multiEndpoint: true, coverInverted: true},
188
+ endpoint: (device) => {
189
+ return {
190
+ 'l1': zigfredEndpoint,
191
+ 'l2': 7,
192
+ 'l3': 8,
193
+ 'l4': 9,
194
+ 'l5': 10,
195
+ 'l6': 11,
196
+ 'l7': 12,
197
+ };
198
+ },
199
+ configure: async (device, coordinatorEndpoint, logger) => {
200
+ // Bind Control EP (LED)
201
+ const controlEp = device.getEndpoint(zigfredEndpoint);
202
+ await reporting.bind(controlEp, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'manuSpecificSiglisZigfred']);
203
+ await reporting.onOff(controlEp);
204
+ await reporting.brightness(controlEp);
205
+ const payload = [{
206
+ attribute: 'buttonEvent',
207
+ minimumReportInterval: 0,
208
+ maximumReportInterval: 0,
209
+ reportableChange: 0,
210
+ }];
211
+ await controlEp.configureReporting('manuSpecificSiglisZigfred', payload, {manufacturerCode: siglisManufacturerCode});
212
+
213
+ // Bind Dimmer 1 EP
214
+ const dimmer1Ep = device.getEndpoint(7);
215
+ await reporting.bind(dimmer1Ep, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
216
+ await reporting.onOff(dimmer1Ep);
217
+ await reporting.brightness(dimmer1Ep);
218
+
219
+ // Bind Dimmer 2 EP
220
+ const dimmer2Ep = device.getEndpoint(8);
221
+ await reporting.bind(dimmer2Ep, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
222
+ await reporting.onOff(dimmer2Ep);
223
+ await reporting.brightness(dimmer2Ep);
224
+
225
+ // Bind Dimmer 3 EP
226
+ const dimmer3Ep = device.getEndpoint(9);
227
+ await reporting.bind(dimmer3Ep, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
228
+ await reporting.onOff(dimmer3Ep);
229
+ await reporting.brightness(dimmer3Ep);
230
+
231
+ // Bind Dimmer 4 EP
232
+ const dimmer4Ep = device.getEndpoint(10);
233
+ await reporting.bind(dimmer4Ep, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
234
+ await reporting.onOff(dimmer4Ep);
235
+ await reporting.brightness(dimmer4Ep);
236
+
237
+ // Bind Cover 1 EP
238
+ const cover1Ep = device.getEndpoint(11);
239
+ await reporting.bind(cover1Ep, coordinatorEndpoint, ['closuresWindowCovering']);
240
+ await reporting.currentPositionLiftPercentage(cover1Ep);
241
+ await reporting.currentPositionTiltPercentage(cover1Ep);
242
+
243
+ // Bind Cover 2 EP
244
+ const cover2Ep = device.getEndpoint(12);
245
+ await reporting.bind(cover2Ep, coordinatorEndpoint, ['closuresWindowCovering']);
246
+ await reporting.currentPositionLiftPercentage(cover2Ep);
247
+ await reporting.currentPositionTiltPercentage(cover2Ep);
248
+ },
249
+ },
119
250
  ];
package/devices/tuya.js CHANGED
@@ -86,6 +86,19 @@ const fzLocal = {
86
86
  return result;
87
87
  },
88
88
  },
89
+ ZM35HQ_battery: {
90
+ cluster: 'manuSpecificTuya',
91
+ type: ['commandDataReport'],
92
+ convert: (model, msg, publish, options, meta) => {
93
+ const dpValue = tuya.firstDpValue(msg, meta, 'ZM35HQ');
94
+ const dp = dpValue.dp;
95
+ const value = tuya.getDataValue(dpValue);
96
+ if (dp === 4) return {battery: value};
97
+ else {
98
+ meta.logger.warn(`zigbee-herdsman-converters:ZM35HQ: NOT RECOGNIZED DP #${dp} with data ${JSON.stringify(dpValue)}`);
99
+ }
100
+ },
101
+ },
89
102
  };
90
103
 
91
104
  module.exports = [
@@ -291,6 +304,7 @@ module.exports = [
291
304
  {modelID: 'TS0505B', manufacturerName: '_TZB210_tmi0rihb'},
292
305
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_a4s41wm4'},
293
306
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_qxenlrin'},
307
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_iwbaamgh'},
294
308
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_klv2wul0'}],
295
309
  model: 'TS0505B',
296
310
  vendor: 'TuYa',
@@ -300,7 +314,7 @@ module.exports = [
300
314
  {vendor: 'Aldi', model: 'L122CB63H11A9.0W', description: 'LIGHTWAY smart home LED-lamp - bulb'},
301
315
  {vendor: 'Lidl', model: '14153706L', description: 'Livarno smart LED ceiling light'},
302
316
  ],
303
- extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
317
+ extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500], disableColorTempStartup: true}),
304
318
  meta: {applyRedFix: true, enhancedHue: false},
305
319
  },
306
320
  {
@@ -395,13 +409,17 @@ module.exports = [
395
409
  fingerprint: [{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'}],
396
410
  model: 'ZM-35H-Q',
397
411
  vendor: 'TuYa',
398
- description: 'Motion Sensor',
399
- fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ZM35HQ_attr],
412
+ description: 'Motion sensor',
413
+ fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ZM35HQ_attr, fzLocal.ZM35HQ_battery],
400
414
  toZigbee: [tz.ZM35HQ_attr],
401
415
  exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery(),
402
416
  exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
403
417
  exposes.enum('keep_time', ea.ALL, [30, 60, 120]).withDescription('PIR keep time in seconds'),
404
418
  ],
419
+ configure: async (device, coordinatorEndpoint, logger) => {
420
+ const endpoint = device.getEndpoint(1);
421
+ await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
422
+ },
405
423
  },
406
424
  {
407
425
  fingerprint: [{modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'}],
package/devices/xiaomi.js CHANGED
@@ -1779,19 +1779,19 @@ module.exports = [
1779
1779
  vendor: 'Xiaomi',
1780
1780
  whiteLabel: [{vendor: 'Xiaomi', model: 'AAQS-S01'}],
1781
1781
  description: 'Aqara TVOC air quality monitor',
1782
- fromZigbee: [fz.xiaomi_tvoc, fz.battery, fz.temperature, fz.humidity],
1782
+ fromZigbee: [fz.xiaomi_tvoc, fz.battery, fz.temperature, fz.humidity, fz.aqara_opple],
1783
1783
  toZigbee: [],
1784
1784
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
1785
- exposes: [e.temperature(), e.humidity(), e.voc(), e.battery(), e.battery_voltage()],
1785
+ exposes: [e.temperature(), e.humidity(), e.voc(), e.device_temperature(), e.battery(), e.battery_voltage()],
1786
1786
  configure: async (device, coordinatorEndpoint, logger) => {
1787
1787
  const endpoint = device.getEndpoint(1);
1788
- const binds = ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg', 'genAnalogInput'];
1788
+ const binds = ['msTemperatureMeasurement', 'msRelativeHumidity', 'genAnalogInput'];
1789
1789
  await reporting.bind(endpoint, coordinatorEndpoint, binds);
1790
- await reporting.batteryVoltage(endpoint);
1791
1790
  await reporting.humidity(endpoint);
1792
1791
  await reporting.temperature(endpoint);
1793
1792
  const payload = reporting.payload('presentValue', 10, constants.repInterval.HOUR, 5);
1794
1793
  await endpoint.configureReporting('genAnalogInput', payload);
1794
+ await endpoint.read('genPowerCfg', ['batteryVoltage']);
1795
1795
  },
1796
1796
  ota: ota.zigbeeOTA,
1797
1797
  },
package/lib/xiaomi.js CHANGED
@@ -158,9 +158,10 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
158
158
  }
159
159
  break;
160
160
  case '3':
161
- if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM'].includes(model.model)) {
161
+ if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM', 'MCCGQ14LM'].includes(model.model)) {
162
162
  // The temperature value is constant 25 °C and does not change, so we ignore it
163
163
  // https://github.com/Koenkk/zigbee2mqtt/issues/11126
164
+ // https://github.com/Koenkk/zigbee-herdsman-converters/pull/3585
164
165
  } else {
165
166
  payload.device_temperature = calibrateAndPrecisionRoundOptions(value, options, 'device_temperature'); // 0x03
166
167
  }
@@ -207,7 +208,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
207
208
  // We don't know what the value means for these devices.
208
209
  // https://github.com/Koenkk/zigbee2mqtt/issues/11126
209
210
  // https://github.com/Koenkk/zigbee2mqtt/issues/12279
210
- } else if (['WSDCGQ01LM', 'WSDCGQ11LM', 'WSDCGQ12LM'].includes(model.model)) {
211
+ } else if (['WSDCGQ01LM', 'WSDCGQ11LM', 'WSDCGQ12LM', 'VOCKQJK11LM'].includes(model.model)) {
211
212
  // https://github.com/Koenkk/zigbee2mqtt/issues/798
212
213
  // Sometimes the sensor publishes non-realistic vales, filter these
213
214
  const temperature = parseFloat(value) / 100.0;
@@ -248,8 +249,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
248
249
  }
249
250
  payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
250
251
  } else if (['RTCGQ12LM', 'RTCGQ14LM'].includes(model.model)) {
251
- payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
252
- } else if (['WSDCGQ01LM', 'WSDCGQ11LM', 'WSDCGQ12LM'].includes(model.model)) {
252
+ // Sometimes RTCGQ14LM reports high illuminance values in the dark
253
+ // https://github.com/Koenkk/zigbee2mqtt/issues/12596
254
+ const illuminance = value > 65000 ? 0 : value;
255
+ payload.illuminance = calibrateAndPrecisionRoundOptions(illuminance, options, 'illuminance');
256
+ } else if (['WSDCGQ01LM', 'WSDCGQ11LM', 'WSDCGQ12LM', 'VOCKQJK11LM'].includes(model.model)) {
253
257
  // https://github.com/Koenkk/zigbee2mqtt/issues/798
254
258
  // Sometimes the sensor publishes non-realistic vales, filter these
255
259
  const humidity = parseFloat(value) / 100.0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.528",
3
+ "version": "14.0.531",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -38,7 +38,7 @@
38
38
  "buffer-crc32": "^0.2.13",
39
39
  "https-proxy-agent": "^5.0.1",
40
40
  "tar-stream": "^2.2.0",
41
- "zigbee-herdsman": "^0.14.32"
41
+ "zigbee-herdsman": "^0.14.33"
42
42
  },
43
43
  "devDependencies": {
44
44
  "eslint": "*",