zigbee-herdsman-converters 14.0.535 → 14.0.538

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.
@@ -5267,7 +5267,7 @@ const converters = {
5267
5267
  const value = tuya.getDataValue(dpValue);
5268
5268
  const state = value ? 'ON' : 'OFF';
5269
5269
  if (multiEndpoint) {
5270
- const lookup = {1: 'l1', 2: 'l2', 3: 'l3', 4: 'l4'};
5270
+ const lookup = {1: 'l1', 2: 'l2', 3: 'l3', 4: 'l4', 5: 'l5', 6: 'l6'};
5271
5271
  const endpoint = lookup[dp];
5272
5272
  if (endpoint in model.endpoint(msg.device)) {
5273
5273
  return {[`state_${endpoint}`]: state};
@@ -3842,7 +3842,7 @@ const converters = {
3842
3842
  tuya_switch_state: {
3843
3843
  key: ['state'],
3844
3844
  convertSet: async (entity, key, value, meta) => {
3845
- const lookup = {l1: 1, l2: 2, l3: 3, l4: 4};
3845
+ const lookup = {l1: 1, l2: 2, l3: 3, l4: 4, l5: 5, l6: 6};
3846
3846
  const multiEndpoint = utils.getMetaValue(entity, meta.mapped, 'multiEndpoint', 'allEqual', false);
3847
3847
  const keyid = multiEndpoint ? lookup[meta.endpoint_name] : 1;
3848
3848
  await tuya.sendDataPointBool(entity, keyid, value === 'ON');
@@ -8,6 +8,32 @@ const e = exposes.presets;
8
8
  const ea = exposes.access;
9
9
  const constants = require('../lib/constants');
10
10
 
11
+ const fzLocal = {
12
+ thermostat_3156105: {
13
+ cluster: 'hvacThermostat',
14
+ type: ['attributeReport', 'readResponse'],
15
+ convert: (model, msg, publish, options, meta) => {
16
+ if (msg.data.hasOwnProperty('runningState')) {
17
+ if (msg.data['runningState'] == 1) {
18
+ msg.data['runningState'] = 0;
19
+ } else if (msg.data['runningState'] == 5) {
20
+ msg.data['runningState'] = 4;
21
+ } else if (msg.data['runningState'] == 7) {
22
+ msg.data['runningState'] = 6;
23
+ } else if (msg.data['runningState'] == 13) {
24
+ msg.data['runningState'] = 9;
25
+ }
26
+ }
27
+ if (msg.data.hasOwnProperty('ctrlSeqeOfOper')) {
28
+ if (msg.data['ctrlSeqeOfOper'] == 6) {
29
+ msg.data['ctrlSeqeOfOper'] = 4;
30
+ }
31
+ }
32
+ return fz.thermostat.convert(model, msg, publish, options, meta);
33
+ },
34
+ },
35
+ };
36
+
11
37
  module.exports = [
12
38
  {
13
39
  zigbeeModel: ['4256251-RZHAC'],
@@ -195,7 +221,7 @@ module.exports = [
195
221
  model: '3156105',
196
222
  vendor: 'Centralite',
197
223
  description: 'HA thermostat',
198
- fromZigbee: [fz.battery, fz.thermostat, fz.fan, fz.ignore_time_read],
224
+ fromZigbee: [fz.battery, fzLocal.thermostat_3156105, fz.fan, fz.ignore_time_read],
199
225
  toZigbee: [tz.factory_reset, tz.thermostat_local_temperature,
200
226
  tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_cooling_setpoint,
201
227
  tz.thermostat_setpoint_raise_lower, tz.thermostat_remote_sensing,
@@ -6,6 +6,37 @@ const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
7
  const ea = exposes.access;
8
8
 
9
+ const tzLocal = {
10
+ node_config: {
11
+ key: ['report_delay'],
12
+ convertSet: async (entity, key, rawValue, meta) => {
13
+ const lookup = {'OFF': 0x00, 'ON': 0x01};
14
+ const value = lookup.hasOwnProperty(rawValue) ? lookup[rawValue] : parseInt(rawValue, 10);
15
+ const payloads = {
16
+ report_delay: ['genPowerCfg', {0x0201: {value, type: 0x21}}],
17
+ };
18
+ await entity.write(payloads[key][0], payloads[key][1]);
19
+ return {
20
+ state: {[key]: rawValue},
21
+ };
22
+ },
23
+ },
24
+ };
25
+
26
+ const fzLocal = {
27
+ node_config: {
28
+ cluster: 'genPowerCfg',
29
+ type: ['attributeReport', 'readResponse'],
30
+ convert: (model, msg, publish, options, meta) => {
31
+ const result = {};
32
+ if (msg.data.hasOwnProperty(0x0201)) {
33
+ result.report_delay = msg.data[0x0201];
34
+ }
35
+ return result;
36
+ },
37
+ },
38
+ };
39
+
9
40
  module.exports = [
10
41
  {
11
42
  zigbeeModel: ['ti.router'],
@@ -257,17 +288,15 @@ module.exports = [
257
288
  model: 'EFEKTA_miniPWS',
258
289
  vendor: 'Custom devices (DiY)',
259
290
  description: '[Mini plant wattering sensor](http://efektalab.com/miniPWS)',
260
- fromZigbee: [fz.soil_moisture, fz.battery],
261
- toZigbee: [tz.factory_reset],
291
+ fromZigbee: [fz.soil_moisture, fz.battery, fzLocal.node_config],
292
+ toZigbee: [tz.factory_reset, tzLocal.node_config],
262
293
  configure: async (device, coordinatorEndpoint, logger) => {
263
294
  const firstEndpoint = device.getEndpoint(1);
264
295
  await reporting.bind(firstEndpoint, coordinatorEndpoint, ['genPowerCfg', 'msSoilMoisture']);
265
- const overides = {min: 0, max: 21600, change: 0};
266
- await reporting.batteryVoltage(firstEndpoint, overides);
267
- await reporting.batteryPercentageRemaining(firstEndpoint, overides);
268
- await reporting.soil_moisture(firstEndpoint, overides);
269
296
  },
270
- exposes: [e.soil_moisture(), e.battery()],
297
+ exposes: [e.soil_moisture(), e.battery(),
298
+ exposes.numeric('report_delay', ea.STATE_SET).withUnit('min').withDescription('Adjust Report Delay, by default 60 minutes')
299
+ .withValueMin(1).withValueMax(180)],
271
300
  },
272
301
  {
273
302
  zigbeeModel: ['EFEKTA_eON213wz'],
@@ -10,14 +10,15 @@ module.exports = [
10
10
  model: 'V3-BTZB/V3-BTZBE',
11
11
  vendor: 'Danalock',
12
12
  description: 'BT/ZB smartlock',
13
- fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery],
14
- toZigbee: [tz.lock],
13
+ fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event, fz.lock_pin_code_response],
14
+ toZigbee: [tz.lock, tz.pincode_lock, tz.lock_userstatus],
15
+ meta: {pinCodeCount: 20},
15
16
  configure: async (device, coordinatorEndpoint, logger) => {
16
17
  const endpoint = device.getEndpoint(1);
17
18
  await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
18
19
  await reporting.lockState(endpoint);
19
20
  await reporting.batteryPercentageRemaining(endpoint);
20
21
  },
21
- exposes: [e.lock(), e.battery(), e.lock_action(), e.lock_action_source_name(), e.lock_action_source_user()],
22
+ exposes: [e.lock(), e.battery(), e.pincode(), e.lock_action(), e.lock_action_source_name(), e.lock_action_source_user()],
22
23
  },
23
24
  ];
package/devices/ecodim.js CHANGED
@@ -127,7 +127,8 @@ module.exports = [
127
127
  extend: extend.light_onoff_brightness(),
128
128
  },
129
129
  {
130
- fingerprint: [{modelID: 'CCT Light', manufacturerName: 'ZigBee/CCT', manufacturerID: 4137}],
130
+ fingerprint: [{modelID: 'CCT Light', manufacturerName: 'ZigBee/CCT', manufacturerID: 4137},
131
+ {modelID: 'CCT Light', manufacturerName: 'Astuta/ZB-CCT', manufacturerID: 4137}],
131
132
  model: 'ED-10041',
132
133
  vendor: 'EcoDim',
133
134
  description: 'Zigbee LED filament light dimmable E27, edison ST64, flame 2200K',
@@ -267,7 +267,7 @@ module.exports = [
267
267
  vendor: 'Gledopto',
268
268
  ota: ota.zigbeeOTA,
269
269
  description: 'Zigbee LED Controller RGB+CCT (pro)',
270
- whiteLabel: [{vendor: 'Gledopto', model: 'GL-C-001P'}],
270
+ whiteLabel: [{vendor: 'Gledopto', model: 'GL-C-001P'}, {vendor: 'Gledopto', model: 'GL-C-002P'}],
271
271
  extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495], noConfigure: true}),
272
272
  meta: {disableDefaultResponse: true},
273
273
  configure: async (device, coordinatorEndpoint, logger) => {
package/devices/heiman.js CHANGED
@@ -117,6 +117,15 @@ module.exports = [
117
117
  toZigbee: [],
118
118
  exposes: [e.gas(), e.battery_low(), e.tamper()],
119
119
  },
120
+ {
121
+ zigbeeModel: ['RH3070'],
122
+ model: 'HS1CG',
123
+ vendor: 'Heiman',
124
+ description: 'Smart combustible gas sensor',
125
+ fromZigbee: [fz.ias_gas_alarm_1],
126
+ toZigbee: [],
127
+ exposes: [e.gas(), e.battery_low(), e.tamper()],
128
+ },
120
129
  {
121
130
  zigbeeModel: ['GAS_V15'],
122
131
  model: 'HS1CG_M',
package/devices/ikea.js CHANGED
@@ -36,10 +36,10 @@ const bulbOnEvent = async (type, data, device, options, state) => {
36
36
 
37
37
  // NOTE: execute_if_off default is false
38
38
  // we only restore if true, to save unneeded network writes
39
- if (state.color_options !== undefined && state.color_options.execute_if_off === true) {
39
+ if (state !== undefined && state.color_options !== undefined && state.color_options.execute_if_off === true) {
40
40
  device.endpoints[0].write('lightingColorCtrl', {'options': 1});
41
41
  }
42
- if (state.level_config !== undefined && state.level_config.execute_if_off === true) {
42
+ if (state !== undefined && state.level_config !== undefined && state.level_config.execute_if_off === true) {
43
43
  device.endpoints[0].write('genLevelCtrl', {'options': 1});
44
44
  }
45
45
  }
@@ -155,20 +155,16 @@ module.exports = [
155
155
  exposes: [e.action(['on', 'off', 'brightness_step_up', 'brightness_step_down', 'brightness_move_up', 'brightness_move_down',
156
156
  'brightness_stop', 'color_temperature_move'])],
157
157
  toZigbee: [],
158
+ configure: async (device, coordinatorEndpoint, logger) => {
159
+ device.powerSource = 'Battery';
160
+ device.save();
161
+ },
158
162
  },
159
163
  {
160
- zigbeeModel: ['tint-ColorTemperature'],
161
- model: '404037',
162
- vendor: 'Müller Licht',
163
- description: 'Tint retro filament LED-bulb E27, Edison bulb gold, white+ambiance (1800-6500K), dimmable, 5,5W',
164
- extend: extend.light_onoff_brightness_colortemp(),
165
- toZigbee: extend.light_onoff_brightness_colortemp().toZigbee.concat([tz.tint_scene]),
166
- },
167
- {
168
- zigbeeModel: ['tint-ColorTemperature2'],
169
- model: '404038',
164
+ zigbeeModel: ['tint-ColorTemperature', 'tint-ColorTemperature2'],
165
+ model: '404037/404038',
170
166
  vendor: 'Müller Licht',
171
- description: 'Tint retro filament LED-bulb E27, Globe bulb gold, white+ambiance (1800-6500K), dimmable, 5,5W',
167
+ description: 'CCT LED-bulb',
172
168
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
173
169
  toZigbee: extend.light_onoff_brightness_colortemp().toZigbee.concat([tz.tint_scene]),
174
170
  },
package/devices/niko.js CHANGED
@@ -219,4 +219,13 @@ module.exports = [
219
219
  exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l2'),
220
220
  ],
221
221
  },
222
+ {
223
+ zigbeeModel: ['Connectable dimmer,3-200W,2-wire'],
224
+ model: '552-72201',
225
+ vendor: 'Niko',
226
+ description: 'Connectable dimmer',
227
+ fromZigbee: [fz.on_off, fz.brightness, fz.level_config, fz.command_move, fz.command_stop],
228
+ toZigbee: [tz.light_onoff_brightness, tz.level_config],
229
+ exposes: [e.light_brightness().withLevelConfig()],
230
+ },
222
231
  ];
@@ -26,15 +26,19 @@ module.exports = [
26
26
  model: 'SZ-ESW01-AU',
27
27
  vendor: 'Sercomm',
28
28
  description: 'Telstra smart plug',
29
- exposes: [e.switch(), e.power()],
30
- fromZigbee: [fz.on_off, fz.metering],
29
+ exposes: [e.switch(), e.power(), e.energy(), e.current(), e.voltage()],
30
+ fromZigbee: [fz.on_off, fz.metering, fz.electrical_measurement],
31
31
  toZigbee: [tz.on_off],
32
32
  configure: async (device, coordinatorEndpoint, logger) => {
33
33
  const endpoint = device.getEndpoint(1);
34
- await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
34
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering', 'haElectricalMeasurement']);
35
35
  await reporting.onOff(endpoint);
36
36
  await reporting.instantaneousDemand(endpoint);
37
+ await reporting.currentSummDelivered(endpoint);
37
38
  endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 1000000, multiplier: 1});
39
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
40
+ await reporting.rmsVoltage(endpoint);
41
+ await reporting.rmsCurrent(endpoint);
38
42
  },
39
43
  },
40
44
  {
package/devices/tuya.js CHANGED
@@ -43,6 +43,87 @@ const tzLocal = {
43
43
  }
44
44
  },
45
45
  },
46
+ power_on_behavior: {
47
+ key: ['power_on_behavior'],
48
+ convertSet: async (entity, key, value, meta) => {
49
+ value = value.toLowerCase();
50
+ const lookup = {'off': 0, 'on': 1, 'previous': 2};
51
+ utils.validateValue(value, Object.keys(lookup));
52
+ const pState = lookup[value];
53
+ await entity.write('manuSpecificTuya_3', {'powerOnBehavior': pState}, {disableDefaultResponse: true});
54
+ return {state: {power_on_behavior: value}};
55
+ },
56
+ convertGet: async (entity, key, meta) => {
57
+ await entity.read('manuSpecificTuya_3', ['powerOnBehavior']);
58
+ },
59
+ },
60
+ zb_sm_cover: {
61
+ key: ['state', 'position', 'reverse_direction', 'top_limit', 'bottom_limit', 'favorite_position', 'goto_positon', 'report'],
62
+ convertSet: async (entity, key, value, meta) => {
63
+ switch (key) {
64
+ case 'position': {
65
+ const invert = (meta.state) ? !meta.state.invert_cover : false;
66
+ value = invert ? 100 - value : value;
67
+ if (value >= 0 && value <= 100) {
68
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.coverPosition, value);
69
+ } else {
70
+ throw new Error('TuYa_cover_control: Curtain motor position is out of range');
71
+ }
72
+ break;
73
+ }
74
+ case 'state': {
75
+ const stateEnums = tuya.getCoverStateEnums(meta.device.manufacturerName);
76
+ meta.logger.debug(`TuYa_cover_control: Using state enums for ${meta.device.manufacturerName}:
77
+ ${JSON.stringify(stateEnums)}`);
78
+
79
+ value = value.toLowerCase();
80
+ switch (value) {
81
+ case 'close':
82
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.state, stateEnums.close);
83
+ break;
84
+ case 'open':
85
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.state, stateEnums.open);
86
+ break;
87
+ case 'stop':
88
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.state, stateEnums.stop);
89
+ break;
90
+ default:
91
+ throw new Error('TuYa_cover_control: Invalid command received');
92
+ }
93
+ break;
94
+ }
95
+ case 'reverse_direction': {
96
+ meta.logger.info(`Motor direction ${(value) ? 'reverse' : 'forward'}`);
97
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.motorDirection, (value) ? 1 : 0);
98
+ break;
99
+ }
100
+ case 'top_limit': {
101
+ await tuya.sendDataPointEnum(entity, 104, {'SET': 0, 'CLEAR': 1}[value]);
102
+ break;
103
+ }
104
+ case 'bottom_limit': {
105
+ await tuya.sendDataPointEnum(entity, 103, {'SET': 0, 'CLEAR': 1}[value]);
106
+ break;
107
+ }
108
+ case 'favorite_position': {
109
+ await tuya.sendDataPointValue(entity, 115, value);
110
+ break;
111
+ }
112
+ case 'goto_positon': {
113
+ if (value == 'FAVORITE') {
114
+ value = (meta.state) ? meta.state.favorite_position : null;
115
+ } else {
116
+ value = parseInt(value);
117
+ }
118
+ return tz.tuya_cover_control.convertSet(entity, 'position', value, meta);
119
+ }
120
+ case 'report': {
121
+ await tuya.sendDataPointBool(entity, 116, 0);
122
+ break;
123
+ }
124
+ }
125
+ },
126
+ },
46
127
  };
47
128
 
48
129
  const fzLocal = {
@@ -99,6 +180,84 @@ const fzLocal = {
99
180
  }
100
181
  },
101
182
  },
183
+ power_on_behavior: {
184
+ cluster: 'manuSpecificTuya_3',
185
+ type: ['attributeReport', 'readResponse'],
186
+ convert: (model, msg, publish, options, meta) => {
187
+ const attribute = 'powerOnBehavior';
188
+ const lookup = {0: 'off', 1: 'on', 2: 'previous'};
189
+
190
+ if (msg.data.hasOwnProperty(attribute)) {
191
+ const property = utils.postfixWithEndpointName('power_on_behavior', msg, model);
192
+ return {[property]: lookup[msg.data[attribute]]};
193
+ }
194
+ },
195
+ },
196
+ zb_sm_cover: {
197
+ cluster: 'manuSpecificTuya',
198
+ type: ['commandDataReport', 'commandDataResponse'],
199
+ convert: (model, msg, publish, options, meta) => {
200
+ const result = {};
201
+ for (const dpValue of msg.data.dpValues) {
202
+ const dp = dpValue.dp;
203
+ const value = tuya.getDataValue(dpValue);
204
+
205
+ switch (dp) {
206
+ case tuya.dataPoints.coverPosition: // Started moving to position (triggered from Zigbee)
207
+ case tuya.dataPoints.coverArrived: { // Arrived at position
208
+ const invert = (meta.state) ? !meta.state.invert_cover : false;
209
+ const position = invert ? 100 - (value & 0xFF) : (value & 0xFF);
210
+ if (position > 0 && position <= 100) {
211
+ result.position = position;
212
+ result.state = 'OPEN';
213
+ } else if (position == 0) { // Report fully closed
214
+ result.position = position;
215
+ result.state = 'CLOSE';
216
+ }
217
+ break;
218
+ }
219
+ case 1: // report state
220
+ result.state = {0: 'OPEN', 1: 'STOP', 2: 'CLOSE'}[value];
221
+ break;
222
+ case tuya.dataPoints.motorDirection: // reverse direction
223
+ result.reverse_direction = (value == 1);
224
+ break;
225
+ case 10: // cycle time
226
+ result.cycle_time = value;
227
+ break;
228
+ case 101: // model
229
+ result.motor_type = {0: '', 1: 'AM0/6-28R-Sm', 2: 'AM0/10-19R-Sm',
230
+ 3: 'AM1/10-13R-Sm', 4: 'AM1/20-13R-Sm', 5: 'AM1/30-13R-Sm'}[value];
231
+ break;
232
+ case 102: // cycles
233
+ result.cycle_count = value;
234
+ break;
235
+ case 103: // set or clear bottom limit
236
+ result.bottom_limit = {0: 'SET', 1: 'CLEAR'}[value];
237
+ break;
238
+ case 104: // set or clear top limit
239
+ result.top_limit = {0: 'SET', 1: 'CLEAR'}[value];
240
+ break;
241
+ case 109: // active power
242
+ result.active_power = value;
243
+ break;
244
+ case 115: // favorite_position
245
+ result.favorite_position = (value != 101) ? value : null;
246
+ break;
247
+ case 116: // report confirmation
248
+ break;
249
+ case 121: // running state
250
+ result.running_state = {0: 'OPENING', 1: 'STOPPED', 2: 'CLOSING'}[value];
251
+ result.running = (value !== 1) ? true : false;
252
+ break;
253
+ default: // Unknown code
254
+ meta.logger.warn(`zb_sm_tuya_cover: Unhandled DP #${dp} for ${meta.device.manufacturerName}:
255
+ ${JSON.stringify(dpValue)}`);
256
+ }
257
+ }
258
+ return result;
259
+ },
260
+ },
102
261
  };
103
262
 
104
263
  module.exports = [
@@ -391,6 +550,7 @@ module.exports = [
391
550
  {modelID: 'TS0202', manufacturerName: '_TZ3000_otvn3lne'},
392
551
  {modelID: 'TS0202', manufacturerName: '_TZ3000_tiwq83wk'},
393
552
  {modelID: 'TS0202', manufacturerName: '_TZ3000_ykwcwxmz'},
553
+ {modelID: 'TS0202', manufacturerName: '_TZ3000_hgu1dlak'},
394
554
  {modelID: 'WHD02', manufacturerName: '_TZ3000_hktqahrq'}],
395
555
  model: 'TS0202',
396
556
  vendor: 'TuYa',
@@ -1128,7 +1288,6 @@ module.exports = [
1128
1288
  // Tubular motors:
1129
1289
  {modelID: 'TS0601', manufacturerName: '_TZE200_5sbebbzs'},
1130
1290
  {modelID: 'TS0601', manufacturerName: '_TZE200_zuz7f94z'},
1131
- {modelID: 'TS0601', manufacturerName: '_TZE200_zyrdrmno'},
1132
1291
  {modelID: 'TS0601', manufacturerName: '_TZE200_68nvbio9'},
1133
1292
  ],
1134
1293
  model: 'TS0601_cover',
@@ -1800,9 +1959,11 @@ module.exports = [
1800
1959
  model: 'TS0004',
1801
1960
  vendor: 'TuYa',
1802
1961
  description: 'Smart light switch - 4 gang with neutral wire',
1803
- extend: extend.switch(),
1804
- exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
1805
- e.switch().withEndpoint('l4')],
1962
+ fromZigbee: [fz.on_off, fzLocal.power_on_behavior, fz.ignore_basic_report],
1963
+ toZigbee: [tz.on_off, tzLocal.power_on_behavior],
1964
+ exposes: [e.switch().withEndpoint('l1'), e.power_on_behavior().withEndpoint('l1'), e.switch().withEndpoint('l2'),
1965
+ e.power_on_behavior().withEndpoint('l2'), e.switch().withEndpoint('l3'), e.power_on_behavior().withEndpoint('l3'),
1966
+ e.switch().withEndpoint('l4'), e.power_on_behavior().withEndpoint('l4')],
1806
1967
  endpoint: (device) => {
1807
1968
  return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4};
1808
1969
  },
@@ -2426,4 +2587,28 @@ module.exports = [
2426
2587
  await reporting.batteryPercentageRemaining(endpoint);
2427
2588
  },
2428
2589
  },
2590
+ {
2591
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_zyrdrmno'}],
2592
+ model: 'ZB-Sm',
2593
+ vendor: 'TuYa',
2594
+ description: 'Tubular motor',
2595
+ fromZigbee: [fzLocal.zb_sm_cover, fz.ignore_basic_report],
2596
+ toZigbee: [tzLocal.zb_sm_cover],
2597
+ onEvent: tuya.onEventSetTime,
2598
+ exposes: [
2599
+ e.cover_position().setAccess('position', ea.STATE_SET),
2600
+ exposes.enum('goto_positon', ea.SET, ['25', '50', '75', 'FAVORITE']),
2601
+ exposes.enum('running_state', ea.STATE, ['OPENING', 'CLOSING', 'STOPPED']),
2602
+ exposes.numeric('active_power', ea.STATE).withDescription('Active power').withUnit('mWt'),
2603
+ exposes.numeric('cycle_count', ea.STATE).withDescription('Cycle count'),
2604
+ exposes.numeric('cycle_time', ea.STATE).withDescription('Cycle time').withUnit('ms'),
2605
+ exposes.enum('top_limit', ea.STATE_SET, ['SET', 'CLEAR']).withDescription('Setup or clear top limit'),
2606
+ exposes.enum('bottom_limit', ea.STATE_SET, ['SET', 'CLEAR']).withDescription('Setup or clear bottom limit'),
2607
+ exposes.numeric('favorite_position', ea.STATE_SET).withValueMin(0).withValueMax(100)
2608
+ .withDescription('Favorite position of this cover'),
2609
+ exposes.binary(`reverse_direction`, ea.STATE_SET, true, false).withDescription(`Inverts the cover direction`),
2610
+ exposes.text('motor_type', ea.STATE),
2611
+ exposes.enum('report', ea.SET, ['REPORT']),
2612
+ ],
2613
+ },
2429
2614
  ];
package/devices/xiaomi.js CHANGED
@@ -1538,14 +1538,14 @@ module.exports = [
1538
1538
  model: 'GZCGQ01LM',
1539
1539
  vendor: 'Xiaomi',
1540
1540
  description: 'MiJia light intensity sensor',
1541
- fromZigbee: [fz.battery, fz.illuminance],
1541
+ fromZigbee: [fz.battery, fz.illuminance, fz.aqara_opple],
1542
1542
  toZigbee: [],
1543
1543
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
1544
1544
  configure: async (device, coordinatorEndpoint, logger) => {
1545
1545
  const endpoint = device.getEndpoint(1);
1546
- await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'msIlluminanceMeasurement']);
1547
- await reporting.batteryVoltage(endpoint);
1546
+ await reporting.bind(endpoint, coordinatorEndpoint, ['msIlluminanceMeasurement']);
1548
1547
  await reporting.illuminance(endpoint, {min: 15, max: constants.repInterval.HOUR, change: 500});
1548
+ await endpoint.read('genPowerCfg', ['batteryVoltage']);
1549
1549
  },
1550
1550
  exposes: [e.battery(), e.battery_voltage(), e.illuminance(), e.illuminance_lux()],
1551
1551
  },
@@ -189,4 +189,57 @@ module.exports = [
189
189
  toZigbee: [tz.tuya_cover_control, tz.tuya_cover_options, tz.tuya_data_point_test],
190
190
  exposes: [e.cover_position().setAccess('position', ea.STATE_SET)],
191
191
  },
192
+ {
193
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_1n2kyphz'}],
194
+ model: 'TB26-4',
195
+ vendor: 'Zemismart',
196
+ description: '4-gang smart wall switch',
197
+ exposes: [e.switch().withEndpoint('l1').setAccess('state', ea.STATE_SET),
198
+ e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET),
199
+ e.switch().withEndpoint('l3').setAccess('state', ea.STATE_SET),
200
+ e.switch().withEndpoint('l4').setAccess('state', ea.STATE_SET)],
201
+ fromZigbee: [fz.ignore_basic_report, fz.tuya_switch],
202
+ toZigbee: [tz.tuya_switch_state],
203
+ meta: {multiEndpoint: true},
204
+ endpoint: (device) => {
205
+ return {'l1': 1, 'l2': 1, 'l3': 1, 'l4': 1};
206
+ },
207
+ configure: async (device, coordinatorEndpoint, logger) => {
208
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
209
+ if (device.getEndpoint(2)) await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
210
+ if (device.getEndpoint(3)) await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
211
+ if (device.getEndpoint(4)) await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
212
+ device.powerSource = 'Mains (single phase)';
213
+ device.save();
214
+ },
215
+ },
216
+ {
217
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9mahtqtg'}],
218
+ model: 'TB26-6',
219
+ vendor: 'Zemismart',
220
+ description: '6-gang smart wall switch',
221
+ exposes: [e.switch().withEndpoint('l1').setAccess('state', ea.STATE_SET),
222
+ e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET),
223
+ e.switch().withEndpoint('l3').setAccess('state', ea.STATE_SET),
224
+ e.switch().withEndpoint('l4').setAccess('state', ea.STATE_SET),
225
+ e.switch().withEndpoint('l5').setAccess('state', ea.STATE_SET),
226
+ e.switch().withEndpoint('l6').setAccess('state', ea.STATE_SET)],
227
+ fromZigbee: [fz.ignore_basic_report, fz.tuya_switch],
228
+ toZigbee: [tz.tuya_switch_state],
229
+ meta: {multiEndpoint: true},
230
+ endpoint: (device) => {
231
+ return {'l1': 1, 'l2': 1, 'l3': 1, 'l4': 1, 'l5': 1, 'l6': 1};
232
+ },
233
+ configure: async (device, coordinatorEndpoint, logger) => {
234
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
235
+ if (device.getEndpoint(2)) await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
236
+ if (device.getEndpoint(3)) await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
237
+ if (device.getEndpoint(4)) await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
238
+ if (device.getEndpoint(5)) await reporting.bind(device.getEndpoint(5), coordinatorEndpoint, ['genOnOff']);
239
+ if (device.getEndpoint(6)) await reporting.bind(device.getEndpoint(6), coordinatorEndpoint, ['genOnOff']);
240
+ // Reports itself as battery which is not correct: https://github.com/Koenkk/zigbee2mqtt/issues/6190
241
+ device.powerSource = 'Mains (single phase)';
242
+ device.save();
243
+ },
244
+ },
192
245
  ];
package/devices/zen.js CHANGED
@@ -15,7 +15,8 @@ module.exports = [
15
15
  tz.thermostat_unoccupied_heating_setpoint, tz.thermostat_setpoint_raise_lower, tz.thermostat_running_state,
16
16
  tz.thermostat_remote_sensing, tz.thermostat_control_sequence_of_operation, tz.thermostat_system_mode,
17
17
  tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_relay_status_log],
18
- exposes: [exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 0.5).withLocalTemperature()
18
+ exposes: [exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 0.5)
19
+ .withSetpoint('occupied_cooling_setpoint', 10, 31, 0.5).withLocalTemperature()
19
20
  .withSystemMode(['off', 'auto', 'heat', 'cool']).withRunningState(['idle', 'heat', 'cool'])
20
21
  .withLocalTemperatureCalibration(-30, 30, 0.1).withPiHeatingDemand()],
21
22
  configure: async (device, coordinatorEndpoint, logger) => {
package/lib/xiaomi.js CHANGED
@@ -158,7 +158,7 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
158
158
  }
159
159
  break;
160
160
  case '3':
161
- if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM', 'MCCGQ14LM'].includes(model.model)) {
161
+ if (['WXCJKG11LM', 'WXCJKG12LM', 'WXCJKG13LM', 'MCCGQ14LM', 'GZCGQ01LM'].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
164
  // https://github.com/Koenkk/zigbee-herdsman-converters/pull/3585
@@ -225,6 +225,9 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
225
225
  // payload.water_leak = value === 1;
226
226
  } else if (['JTYJ-GD-01LM/BW'].includes(model.model)) {
227
227
  payload.smoke_density = value;
228
+ } else if (['GZCGQ01LM'].includes(model.model)) {
229
+ // DEPRECATED: change illuminance_lux -> illuminance
230
+ payload.illuminance_lux = calibrateAndPrecisionRoundOptions(value, options, 'illuminance_lux');
228
231
  } else {
229
232
  payload.state = value === 1 ? 'ON' : 'OFF';
230
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.535",
3
+ "version": "14.0.538",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [