zigbee-herdsman-converters 14.0.251 → 14.0.255

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.
@@ -2177,6 +2177,30 @@ const converters = {
2177
2177
  return result;
2178
2178
  },
2179
2179
  },
2180
+ neo_nas_pd07: {
2181
+ cluster: 'manuSpecificTuya',
2182
+ type: ['commandSetDataResponse', 'commandGetData'],
2183
+ convert: (model, msg, publish, options, meta) => {
2184
+ const dp = msg.data.dp;
2185
+ if (dp === 101) return {occupancy: msg.data.data[0] > 0};
2186
+ else if (dp === 102) {
2187
+ const value = msg.data.data[0];
2188
+ return {
2189
+ power_type: {0: 'battery_full', 1: 'battery_high', 2: 'battery_medium', 3: 'battery_low', 4: 'usb'}[value],
2190
+ battery_low: value === 3,
2191
+ };
2192
+ } else if (dp === 103) {
2193
+ return {tamper: msg.data.data[0] > 0 ? true : false};
2194
+ } else if (dp === 104) {
2195
+ const temperature = parseFloat(msg.data.data[3]) / 10.0;
2196
+ return {temperature: calibrateAndPrecisionRoundOptions(temperature, options, 'temperature')};
2197
+ } else if (dp === 105) {
2198
+ return {humidity: calibrateAndPrecisionRoundOptions(msg.data.data[3], options, 'humidity')};
2199
+ } else {
2200
+ meta.logger.warn(`zigbee-herdsman-converters:NEO-PD07: NOT RECOGNIZED DP #${dp} with data ${JSON.stringify(msg.data)}`);
2201
+ }
2202
+ },
2203
+ },
2180
2204
  neo_t_h_alarm: {
2181
2205
  cluster: 'manuSpecificTuya',
2182
2206
  type: ['commandSetDataResponse', 'commandGetData'],
@@ -1233,7 +1233,13 @@ const converters = {
1233
1233
  thermostat_occupied_heating_setpoint: {
1234
1234
  key: ['occupied_heating_setpoint'],
1235
1235
  convertSet: async (entity, key, value, meta) => {
1236
- const occupiedHeatingSetpoint = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1236
+ let result;
1237
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1238
+ result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
1239
+ } else {
1240
+ result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1241
+ }
1242
+ const occupiedHeatingSetpoint = result;
1237
1243
  await entity.write('hvacThermostat', {occupiedHeatingSetpoint});
1238
1244
  },
1239
1245
  convertGet: async (entity, key, meta) => {
@@ -1243,7 +1249,13 @@ const converters = {
1243
1249
  thermostat_unoccupied_heating_setpoint: {
1244
1250
  key: ['unoccupied_heating_setpoint'],
1245
1251
  convertSet: async (entity, key, value, meta) => {
1246
- const unoccupiedHeatingSetpoint = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1252
+ let result;
1253
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1254
+ result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
1255
+ } else {
1256
+ result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1257
+ }
1258
+ const unoccupiedHeatingSetpoint = result;
1247
1259
  await entity.write('hvacThermostat', {unoccupiedHeatingSetpoint});
1248
1260
  },
1249
1261
  convertGet: async (entity, key, meta) => {
@@ -1253,7 +1265,13 @@ const converters = {
1253
1265
  thermostat_occupied_cooling_setpoint: {
1254
1266
  key: ['occupied_cooling_setpoint'],
1255
1267
  convertSet: async (entity, key, value, meta) => {
1256
- const occupiedCoolingSetpoint = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1268
+ let result;
1269
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1270
+ result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
1271
+ } else {
1272
+ result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1273
+ }
1274
+ const occupiedCoolingSetpoint = result;
1257
1275
  await entity.write('hvacThermostat', {occupiedCoolingSetpoint});
1258
1276
  },
1259
1277
  convertGet: async (entity, key, meta) => {
@@ -1263,7 +1281,13 @@ const converters = {
1263
1281
  thermostat_unoccupied_cooling_setpoint: {
1264
1282
  key: ['unoccupied_cooling_setpoint'],
1265
1283
  convertSet: async (entity, key, value, meta) => {
1266
- const unoccupiedCoolingSetpoint = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1284
+ let result;
1285
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1286
+ result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
1287
+ } else {
1288
+ result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
1289
+ }
1290
+ const unoccupiedCoolingSetpoint = result;
1267
1291
  await entity.write('hvacThermostat', {unoccupiedCoolingSetpoint});
1268
1292
  },
1269
1293
  convertGet: async (entity, key, meta) => {
@@ -1989,7 +2013,7 @@ const converters = {
1989
2013
  xiaomi_led_disabled_night: {
1990
2014
  key: ['led_disabled_night'],
1991
2015
  convertSet: async (entity, key, value, meta) => {
1992
- if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ15LM', 'QBCZ14LM'].includes(meta.mapped.model)) {
2016
+ if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG25LM'].includes(meta.mapped.model)) {
1993
2017
  await entity.write('aqaraOpple', {0x0203: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
1994
2018
  } else if (['ZNCZ11LM'].includes(meta.mapped.model)) {
1995
2019
  const payload = value ?
@@ -2003,7 +2027,7 @@ const converters = {
2003
2027
  return {state: {led_disabled_night: value}};
2004
2028
  },
2005
2029
  convertGet: async (entity, key, meta) => {
2006
- if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ15LM', 'QBCZ14LM'].includes(meta.mapped.model)) {
2030
+ if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ15LM', 'QBCZ14LM', 'QBKG25LM'].includes(meta.mapped.model)) {
2007
2031
  await entity.read('aqaraOpple', [0x0203], manufacturerOptions.xiaomi);
2008
2032
  } else {
2009
2033
  throw new Error('Not supported');
@@ -146,15 +146,16 @@ module.exports = [
146
146
  vendor: 'Centralite',
147
147
  description: '3-Series pearl touch thermostat,',
148
148
  fromZigbee: [fz.battery, fz.legacy.thermostat_att_report, fz.fan, fz.ignore_time_read],
149
- toZigbee: [tz.factory_reset, tz.thermostat_local_temperature, tz.thermostat_local_temperature_calibration, tz.thermostat_occupancy,
150
- tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_cooling_setpoint, tz.thermostat_unoccupied_heating_setpoint,
151
- tz.thermostat_unoccupied_cooling_setpoint, tz.thermostat_setpoint_raise_lower, tz.thermostat_remote_sensing,
152
- tz.thermostat_control_sequence_of_operation, tz.thermostat_system_mode, tz.thermostat_weekly_schedule,
153
- tz.thermostat_clear_weekly_schedule, tz.thermostat_relay_status_log, tz.fan_mode, tz.thermostat_running_state],
149
+ toZigbee: [tz.factory_reset, tz.thermostat_local_temperature, tz.thermostat_local_temperature_calibration,
150
+ tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_cooling_setpoint,
151
+ tz.thermostat_setpoint_raise_lower, tz.thermostat_remote_sensing,
152
+ tz.thermostat_control_sequence_of_operation, tz.thermostat_system_mode,
153
+ tz.thermostat_relay_status_log, tz.fan_mode, tz.thermostat_running_state],
154
154
  exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 1).withLocalTemperature()
155
- .withSystemMode(['off', 'heat', 'cool']).withRunningState(['idle', 'heat', 'cool']).withFanMode(['auto', 'on'])
156
- .withSetpoint('occupied_cooling_setpoint', 10, 30, 1).withLocalTemperatureCalibration().withPiHeatingDemand()],
157
- meta: {battery: {voltageToPercentage: '3V_2100'}},
155
+ .withSystemMode(['off', 'heat', 'cool', 'emergency_heating'])
156
+ .withRunningState(['idle', 'heat', 'cool', 'fan_only']).withFanMode(['auto', 'on'])
157
+ .withSetpoint('occupied_cooling_setpoint', 10, 30, 1).withLocalTemperatureCalibration()],
158
+ meta: {battery: {voltageToPercentage: '3V_1500_2800'}},
158
159
  configure: async (device, coordinatorEndpoint, logger) => {
159
160
  const endpoint = device.getEndpoint(1);
160
161
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'hvacThermostat', 'hvacFanCtrl']);
@@ -88,4 +88,16 @@ module.exports = [
88
88
  await reporting.onOff(endpoint);
89
89
  },
90
90
  },
91
+ {
92
+ zigbeeModel: ['43094'],
93
+ model: '43094',
94
+ vendor: 'Enbrighten',
95
+ description: 'Zigbee in-wall smart switch ZB4102',
96
+ extend: extend.switch(),
97
+ configure: async (device, coordinatorEndpoint, logger) => {
98
+ const endpoint = device.getEndpoint(1);
99
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
100
+ await reporting.onOff(endpoint);
101
+ },
102
+ },
91
103
  ];
@@ -0,0 +1,11 @@
1
+ const extend = require('../lib/extend');
2
+
3
+ module.exports = [
4
+ {
5
+ zigbeeModel: ['A10'],
6
+ model: 'GD-ZCRGB012',
7
+ vendor: 'GIDERWEL',
8
+ description: 'Smart Zigbee RGB LED strip controller',
9
+ extend: extend.light_onoff_brightness_color({supportsHS: false}),
10
+ },
11
+ ];
package/devices/ikea.js CHANGED
@@ -97,6 +97,13 @@ module.exports = [
97
97
  description: 'TRADFRI LED globe-bulb E27 470 lumen, dimmable, white spectrum, opal white',
98
98
  extend: tradfriExtend.light_onoff_brightness_colortemp(),
99
99
  },
100
+ {
101
+ zigbeeModel: ['TRADFRIbulbE27WSglobeopal1055lm'],
102
+ model: 'LED2003G10',
103
+ vendor: 'IKEA',
104
+ description: 'TRADFRI LED bulb E27 1055 lumen, dimmable, white spectrum, opal white',
105
+ extend: tradfriExtend.light_onoff_brightness_colortemp(),
106
+ },
100
107
  {
101
108
  zigbeeModel: ['TRADFRI bulb E27 opal 470lm', 'TRADFRI bulb E27 W opal 470lm', 'TRADFRIbulbT120E27WSopal470lm'],
102
109
  model: 'LED1937T5_E27',
@@ -227,6 +234,13 @@ module.exports = [
227
234
  description: 'TRADFRI LED bulb E26/E27 806 lumen, dimmable, white spectrum, clear',
228
235
  extend: tradfriExtend.light_onoff_brightness_colortemp(),
229
236
  },
237
+ {
238
+ zigbeeModel: ['TRADFRIbulbE14WSglobeopal470lm'],
239
+ model: 'LED2002G5',
240
+ vendor: 'IKEA',
241
+ description: 'TRADFRI LED bulb E14 470 lumen, dimmable, white spectrum, clear',
242
+ extend: tradfriExtend.light_onoff_brightness_colortemp(),
243
+ },
230
244
  {
231
245
  zigbeeModel: ['LEPTITER Recessed spot light'],
232
246
  model: 'T1820',
@@ -82,8 +82,7 @@ module.exports = [
82
82
  extend: extend.light_onoff_brightness(),
83
83
  },
84
84
  {
85
- fingerprint: [{modelID: 'TS110F', manufacturerName: '_TYZB01_qezuin6k'},
86
- {modelID: 'TS110E', manufacturerName: '_TZ3210_ngqk6jia'}],
85
+ fingerprint: [{modelID: 'TS110F', manufacturerName: '_TYZB01_qezuin6k'}],
87
86
  model: 'QS-Zigbee-D02-TRIAC-LN',
88
87
  vendor: 'Lonsonho',
89
88
  description: '1 gang smart dimmer switch module with neutral',
package/devices/neo.js CHANGED
@@ -3,6 +3,7 @@ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/lega
3
3
  const tz = require('../converters/toZigbee');
4
4
  const e = exposes.presets;
5
5
  const ea = exposes.access;
6
+ const tuya = require('../lib/tuya');
6
7
 
7
8
  module.exports = [
8
9
  {
@@ -27,4 +28,15 @@ module.exports = [
27
28
  exposes.enum('power_type', ea.STATE, ['battery_full', 'battery_high', 'battery_medium', 'battery_low', 'usb']),
28
29
  ],
29
30
  },
31
+ {
32
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_7hfcudw5'}],
33
+ model: 'NAS-PD07',
34
+ vendor: 'Neo',
35
+ description: 'Motion, temperature & humidity sensor',
36
+ fromZigbee: [fz.neo_nas_pd07],
37
+ toZigbee: [],
38
+ onEvent: tuya.setTime,
39
+ exposes: [e.occupancy(), e.humidity(), e.temperature(), e.tamper(),
40
+ exposes.enum('power_type', ea.STATE, ['battery_full', 'battery_high', 'battery_medium', 'battery_low', 'usb'])],
41
+ },
30
42
  ];
@@ -519,6 +519,15 @@ module.exports = [
519
519
  extend: hueExtend.light_onoff_brightness_colortemp(),
520
520
  ota: ota.zigbeeOTA,
521
521
  },
522
+ {
523
+ zigbeeModel: ['LTA008'],
524
+ model: '9290022267A',
525
+ vendor: 'Philips',
526
+ description: 'Hue white ambiance E27 with Bluetooth',
527
+ meta: {turnsOffAtBrightness1: true},
528
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 434]}),
529
+ ota: ota.zigbeeOTA,
530
+ },
522
531
  {
523
532
  zigbeeModel: ['LCP003'],
524
533
  model: '4090631P7',
@@ -1065,10 +1074,9 @@ module.exports = [
1065
1074
  description: 'Hue white ambiance Aurelle square panel light',
1066
1075
  meta: {turnsOffAtBrightness1: true},
1067
1076
  extend: hueExtend.light_onoff_brightness_colortemp(),
1068
- ota: ota.zigbeeOTA,
1069
1077
  },
1070
1078
  {
1071
- zigbeeModel: ['3216131P6'],
1079
+ zigbeeModel: ['3216131P6', 'LTC005'],
1072
1080
  model: '3216131P6',
1073
1081
  vendor: 'Philips',
1074
1082
  description: 'Hue white ambiance Aurelle square panel light',
@@ -1994,4 +2002,13 @@ module.exports = [
1994
2002
  extend: hueExtend.light_onoff_brightness(),
1995
2003
  ota: ota.zigbeeOTA,
1996
2004
  },
2005
+ {
2006
+ zigbeeModel: ['1746630P7'],
2007
+ model: '1746630P7',
2008
+ vendor: 'Philips',
2009
+ description: 'Hue White and Colour Ambiance Amarant linear outdoor light',
2010
+ meta: {turnsOffAtBrightness1: true},
2011
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2012
+ ota: ota.zigbeeOTA,
2013
+ },
1997
2014
  ];
package/devices/tuya.js CHANGED
@@ -398,6 +398,7 @@ module.exports = [
398
398
  vendor: 'TuYa',
399
399
  description: 'Led strip controller',
400
400
  extend: extend.light_onoff_brightness_color(),
401
+ meta: {applyRedFix: true},
401
402
  },
402
403
  {
403
404
  zigbeeModel: ['TS0503A'],
@@ -764,7 +765,8 @@ module.exports = [
764
765
  {modelID: 'TS011F', manufacturerName: '_TZ3000_ew3ldmgx'},
765
766
  {modelID: 'TS011F', manufacturerName: '_TZ3000_ps3dmato'},
766
767
  {modelID: 'TS011F', manufacturerName: '_TZ3000_mraovvmm'},
767
- {modelID: 'TS011F', manufacturerName: '_TZ3000_jvzvulen'}],
768
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_jvzvulen'},
769
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'}],
768
770
  model: 'TS011F_plug',
769
771
  description: 'Smart plug (with power monitoring)',
770
772
  vendor: 'TuYa',
package/devices/xiaomi.js CHANGED
@@ -544,14 +544,14 @@ module.exports = [
544
544
  model: 'QBKG25LM',
545
545
  vendor: 'Xiaomi',
546
546
  description: 'Aqara D1 3 gang smart wall switch (no neutral wire)',
547
- fromZigbee: [fz.on_off, fz.legacy.QBKG25LM_click, fz.xiaomi_operation_mode_opple],
548
- toZigbee: [tz.on_off, tz.xiaomi_switch_operation_mode_opple, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_switch_do_not_disturb],
547
+ fromZigbee: [fz.on_off, fz.legacy.QBKG25LM_click, fz.xiaomi_operation_mode_opple, fz.xiaomi_switch_opple_basic],
548
+ toZigbee: [tz.on_off, tz.xiaomi_switch_operation_mode_opple, tz.xiaomi_switch_power_outage_memory, tz.xiaomi_led_disabled_night],
549
549
  meta: {multiEndpoint: true},
550
550
  endpoint: (device) => {
551
551
  return {'left': 1, 'center': 2, 'right': 3};
552
552
  },
553
553
  exposes: [
554
- e.switch().withEndpoint('left'), e.power_outage_memory(), e.switch().withEndpoint('center'),
554
+ e.switch().withEndpoint('left'), e.switch().withEndpoint('center'), e.switch().withEndpoint('right'),
555
555
  exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled'])
556
556
  .withDescription('Decoupled mode for left button')
557
557
  .withEndpoint('left'),
@@ -561,7 +561,8 @@ module.exports = [
561
561
  exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled'])
562
562
  .withDescription('Decoupled mode for right button')
563
563
  .withEndpoint('right'),
564
- e.switch().withEndpoint('right'), e.action([
564
+ e.power_outage_memory(), e.led_disabled_night(), e.temperature().withAccess(ea.STATE),
565
+ e.action([
565
566
  'left_single', 'left_double', 'left_triple', 'left_hold', 'left_release',
566
567
  'center_single', 'center_double', 'center_triple', 'center_hold', 'center_release',
567
568
  'right_single', 'right_double', 'right_triple', 'right_hold', 'right_release']),
package/lib/constants.js CHANGED
@@ -65,6 +65,7 @@ const thermostatRunningStates = {
65
65
  12: 'cool',
66
66
  14: 'cool',
67
67
  15: 'cool',
68
+ 22: 'cool',
68
69
  };
69
70
 
70
71
  const fanMode = {
package/lib/exposes.js CHANGED
@@ -361,7 +361,7 @@ class Climate extends Base {
361
361
 
362
362
  withSystemMode(modes, access=a.ALL) {
363
363
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
364
- const allowed = ['off', 'heat', 'cool', 'auto', 'dry', 'fan_only', 'sleep'];
364
+ const allowed = ['off', 'heat', 'cool', 'auto', 'dry', 'fan_only', 'sleep', 'emergency_heating'];
365
365
  modes.forEach((m) => assert(allowed.includes(m)));
366
366
  this.features.push(new Enum('system_mode', access, modes).withDescription('Mode of this device'));
367
367
  return this;
@@ -369,7 +369,7 @@ class Climate extends Base {
369
369
 
370
370
  withRunningState(modes, access=a.STATE_GET) {
371
371
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
372
- const allowed = ['idle', 'heat', 'cool'];
372
+ const allowed = ['idle', 'heat', 'cool', 'fan_only'];
373
373
  modes.forEach((m) => assert(allowed.includes(m)));
374
374
  this.features.push(new Enum('running_state', access, modes).withDescription('The current running state'));
375
375
  return this;
package/lib/utils.js CHANGED
@@ -347,6 +347,12 @@ function validateValue(value, allowed) {
347
347
  }
348
348
  }
349
349
 
350
+ function normalizeCelsiusVersionOfFahrenheit(value) {
351
+ const fahrenheit = (value * 1.8) + 32;
352
+ const roundedFahrenheit = (Math.round((fahrenheit * 2).toFixed(1)) / 2).toFixed(1);
353
+ return ((roundedFahrenheit - 32)/1.8).toFixed(2);
354
+ }
355
+
350
356
  module.exports = {
351
357
  getOptions,
352
358
  isLegacyEnabled,
@@ -374,4 +380,5 @@ module.exports = {
374
380
  sleep,
375
381
  toSnakeCase,
376
382
  toCamelCase,
383
+ normalizeCelsiusVersionOfFahrenheit,
377
384
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.251",
3
+ "version": "14.0.255",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.251",
3
+ "version": "14.0.255",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [