zigbee-herdsman-converters 14.0.659 → 14.0.661

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.
@@ -22,6 +22,8 @@ const utils = require('../lib/utils');
22
22
  const exposes = require('../lib/exposes');
23
23
  const xiaomi = require('../lib/xiaomi');
24
24
 
25
+ const defaultSimulatedBrightness = 255;
26
+
25
27
  const converters = {
26
28
  // #region Generic/recommended converters
27
29
  fan: {
@@ -1233,9 +1235,12 @@ const converters = {
1233
1235
  addActionGroup(payload, msg, model);
1234
1236
 
1235
1237
  if (options.simulated_brightness) {
1238
+ const currentBrightness = globalStore.getValue(msg.endpoint, 'simulated_brightness_brightness', defaultSimulatedBrightness);
1236
1239
  globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', msg.data.level);
1237
1240
  const property = postfixWithEndpointName('brightness', msg, model, meta);
1238
1241
  payload[property] = msg.data.level;
1242
+ const deltaProperty = postfixWithEndpointName('action_brightness_delta', msg, model, meta);
1243
+ payload[deltaProperty] = msg.data.level - currentBrightness;
1239
1244
  }
1240
1245
 
1241
1246
  return payload;
@@ -1260,14 +1265,15 @@ const converters = {
1260
1265
  globalStore.putValue(msg.endpoint, 'simulated_brightness_direction', direction);
1261
1266
  if (globalStore.getValue(msg.endpoint, 'simulated_brightness_timer') === undefined) {
1262
1267
  const timer = setInterval(() => {
1263
- let brightness = globalStore.getValue(msg.endpoint, 'simulated_brightness_brightness', 255);
1268
+ let brightness = globalStore.getValue(msg.endpoint, 'simulated_brightness_brightness', defaultSimulatedBrightness);
1264
1269
  const delta = globalStore.getValue(msg.endpoint, 'simulated_brightness_direction') === 'up' ?
1265
1270
  deltaOpts : -1 * deltaOpts;
1266
1271
  brightness += delta;
1267
1272
  brightness = numberWithinRange(brightness, 0, 255);
1268
1273
  globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', brightness);
1269
1274
  const property = postfixWithEndpointName('brightness', msg, model, meta);
1270
- publish({[property]: brightness});
1275
+ const deltaProperty = postfixWithEndpointName('action_brightness_delta', msg, model, meta);
1276
+ publish({[property]: brightness, [deltaProperty]: delta});
1271
1277
  }, intervalOpts);
1272
1278
 
1273
1279
  globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', timer);
@@ -1292,13 +1298,15 @@ const converters = {
1292
1298
  addActionGroup(payload, msg, model);
1293
1299
 
1294
1300
  if (options.simulated_brightness) {
1295
- let brightness = globalStore.getValue(msg.endpoint, 'simulated_brightness_brightness', 255);
1301
+ let brightness = globalStore.getValue(msg.endpoint, 'simulated_brightness_brightness', defaultSimulatedBrightness);
1296
1302
  const delta = direction === 'up' ? msg.data.stepsize : -1 * msg.data.stepsize;
1297
1303
  brightness += delta;
1298
1304
  brightness = numberWithinRange(brightness, 0, 255);
1299
1305
  globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', brightness);
1300
1306
  const property = postfixWithEndpointName('brightness', msg, model, meta);
1301
1307
  payload[property] = brightness;
1308
+ const deltaProperty = postfixWithEndpointName('action_brightness_delta', msg, model, meta);
1309
+ payload[deltaProperty] = delta;
1302
1310
  }
1303
1311
 
1304
1312
  return payload;
@@ -7137,6 +7145,7 @@ const converters = {
7137
7145
  const delta = button === 'up' ? deltaOpts : deltaOpts * -1;
7138
7146
  const brightness = globalStore.getValue(msg.endpoint, 'brightness', 255) + delta;
7139
7147
  payload.brightness = numberWithinRange(brightness, 0, 255);
7148
+ payload.action_brightness_delta = delta;
7140
7149
  globalStore.putValue(msg.endpoint, 'brightness', payload.brightness);
7141
7150
  }
7142
7151
 
package/devices/bitron.js CHANGED
@@ -189,7 +189,7 @@ module.exports = [
189
189
  model: 'AV2010/32',
190
190
  vendor: 'SMaBiT (Bitron Video)',
191
191
  description: 'Wireless wall thermostat with relay',
192
- fromZigbee: [fz.legacy.bitron_thermostat_att_report, fz.battery, fz.hvac_user_interface],
192
+ fromZigbee: [fz.legacy.thermostat_att_report, fz.battery, fz.hvac_user_interface],
193
193
  toZigbee: [tz.thermostat_control_sequence_of_operation, tz.thermostat_occupied_heating_setpoint,
194
194
  tz.thermostat_occupied_cooling_setpoint, tz.thermostat_local_temperature_calibration, tz.thermostat_local_temperature,
195
195
  tz.thermostat_running_state, tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode],
@@ -66,7 +66,6 @@ module.exports = [
66
66
  toZigbee: [tz.bticino_4027C_cover_state, tz.bticino_4027C_cover_position, tz.legrand_identify,
67
67
  tz.legrand_settingEnableLedInDark],
68
68
  exposes: [e.cover_position()],
69
- meta: {coverInverted: true},
70
69
  configure: async (device, coordinatorEndpoint, logger) => {
71
70
  const endpoint = device.getEndpoint(1);
72
71
  await reporting.bind(endpoint, coordinatorEndpoint, ['genBinaryInput', 'closuresWindowCovering', 'genIdentify']);
@@ -675,6 +675,7 @@ module.exports = [
675
675
  description: 'Air quality sensor',
676
676
  fromZigbee: [develco.fz.voc, develco.fz.voc_battery, fz.temperature, fz.humidity],
677
677
  toZigbee: [],
678
+ ota: ota.zigbeeOTA,
678
679
  exposes: [
679
680
  e.voc(), e.temperature(), e.humidity(),
680
681
  e.battery(), e.battery_low(),
package/devices/ikea.js CHANGED
@@ -45,6 +45,18 @@ const bulbOnEvent = async (type, data, device, options, state) => {
45
45
  if (state !== undefined && state.level_config !== undefined && state.level_config.execute_if_off === true) {
46
46
  device.endpoints[0].write('genLevelCtrl', {'options': 1});
47
47
  }
48
+ if (state !== undefined && state.level_config !== undefined && state.level_config.on_level !== undefined) {
49
+ let onLevel = state.level_config.on_level;
50
+ if (typeof onLevel === 'string' && onLevel.toLowerCase() == 'previous') {
51
+ onLevel = 255;
52
+ } else {
53
+ onLevel = Number(onLevel);
54
+ }
55
+ if (onLevel > 255) onLevel = 254;
56
+ if (onLevel < 1) onLevel = 1;
57
+
58
+ device.endpoints[0].write('genLevelCtrl', {onLevel});
59
+ }
48
60
  }
49
61
  };
50
62
 
@@ -115,6 +115,7 @@ module.exports = [
115
115
  'brightness_move_down', 'brightness_stop'])],
116
116
  toZigbee: [],
117
117
  meta: {battery: {voltageToPercentage: '3V_2500'}, publishDuplicateTransaction: true},
118
+ onEvent: readInitialBatteryState,
118
119
  configure: async (device, coordinatorEndpoint, logger) => {
119
120
  const endpoint = device.getEndpoint(1);
120
121
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
@@ -130,6 +131,7 @@ module.exports = [
130
131
  e.action(['identify', 'on', 'off', 'toggle', 'brightness_move_up', 'brightness_move_down', 'brightness_stop'])],
131
132
  toZigbee: [],
132
133
  meta: {multiEndpoint: true, battery: {voltageToPercentage: '3V_2500'}, publishDuplicateTransaction: true},
134
+ onEvent: readInitialBatteryState,
133
135
  configure: async (device, coordinatorEndpoint, logger) => {
134
136
  const endpoint = device.getEndpoint(1);
135
137
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'genOnOff', 'genLevelCtrl']);
package/devices/m-elec.js CHANGED
@@ -8,4 +8,11 @@ module.exports = [
8
8
  description: 'Stitchy Dim switchable wall module',
9
9
  extend: extend.light_onoff_brightness(),
10
10
  },
11
+ {
12
+ zigbeeModel: ['ML-ST-BP-DIM'],
13
+ model: 'ML-ST-BP-DIM',
14
+ vendor: 'M-ELEC',
15
+ description: 'Stitchy dim mechanism',
16
+ extend: extend.light_onoff_brightness({disableEffect: true}),
17
+ },
11
18
  ];
@@ -192,4 +192,12 @@ module.exports = [
192
192
  description: 'Tint Armaro',
193
193
  extend: extend.light_onoff_brightness_colortemp(),
194
194
  },
195
+ {
196
+ fingerprint: [{manufacturerName: 'MLI', modelID: 'Bulb white'}],
197
+ model: '45727',
198
+ vendor: 'Müller Licht',
199
+ description: 'Tint Amela 42cm, white+ambiance (1800-6500K)',
200
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
201
+ toZigbee: extend.light_onoff_brightness_colortemp().toZigbee.concat([tz.tint_scene]),
202
+ },
195
203
  ];
package/devices/namron.js CHANGED
@@ -383,7 +383,7 @@ module.exports = [
383
383
  .withSetpoint('occupied_heating_setpoint', 0, 40, 0.1)
384
384
  .withLocalTemperature()
385
385
  .withLocalTemperatureCalibration(-3, 3, 0.1)
386
- .withSystemMode(['off', 'auto', 'heat'])
386
+ .withSystemMode(['off', 'auto', 'dry', 'heat'])
387
387
  .withRunningState(['idle', 'heat']),
388
388
  exposes.binary('away_mode', ea.ALL, 'ON', 'OFF')
389
389
  .withDescription('Enable/disable away mode'),
@@ -609,8 +609,8 @@ module.exports = [
609
609
  .withDescription('Enables/disables physical input on the device'),
610
610
  exposes.numeric('hysterersis', ea.ALL)
611
611
  .withUnit('°C')
612
- .withValueMin(5).withValueMax(50).withValueStep(0.1)
613
- .withDescription('Hysterersis setting, range is 5-50, unit is 0.1oC, Default: 5.'),
612
+ .withValueMin(0.5).withValueMax(2).withValueStep(0.1)
613
+ .withDescription('Hysteresis setting, default: 0.5'),
614
614
  exposes.numeric('display_brightnesss', ea.ALL)
615
615
  .withValueMin(1).withValueMax(7).withValueStep(1)
616
616
  .withDescription('Adjust brightness of display values 1(Low)-7(High)'),
package/devices/onesti.js CHANGED
@@ -8,7 +8,7 @@ const constants = require('../lib/constants');
8
8
 
9
9
  module.exports = [
10
10
  {
11
- zigbeeModel: ['easyCodeTouch_v1', 'EasyCodeTouch', 'EasyFingerTouch'],
11
+ zigbeeModel: ['easyCodeTouch_v1', 'EasyCodeTouch', 'EasyFingerTouch', 'NimlyPRO'],
12
12
  model: 'easyCodeTouch_v1',
13
13
  vendor: 'Onesti Products AS',
14
14
  description: 'Zigbee module for EasyAccess code touch series',
package/devices/osram.js CHANGED
@@ -302,15 +302,17 @@ module.exports = [
302
302
  model: 'AC01353010G',
303
303
  vendor: 'OSRAM',
304
304
  description: 'SMART+ Motion Sensor',
305
- fromZigbee: [fz.temperature, fz.ias_occupancy_only_alarm_2, fz.ignore_basic_report],
305
+ fromZigbee: [fz.temperature, fz.ias_occupancy_only_alarm_2, fz.ignore_basic_report, fz.battery],
306
306
  toZigbee: [],
307
+ meta: {battery: {voltageToPercentage: {min: 1900, max: 3000}}},
307
308
  configure: async (device, coordinatorEndpoint, logger) => {
308
309
  const endpoint = device.getEndpoint(1);
309
310
  await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
310
311
  await reporting.temperature(endpoint);
311
312
  await reporting.batteryVoltage(endpoint);
313
+ await reporting.batteryAlarmState(endpoint);
312
314
  },
313
- exposes: [e.temperature(), e.occupancy()],
315
+ exposes: [e.temperature(), e.occupancy(), e.battery(), e.battery_voltage(), e.battery_low()],
314
316
  },
315
317
  {
316
318
  zigbeeModel: ['MR16 TW OSRAM'],
package/devices/owon.js CHANGED
@@ -181,7 +181,7 @@ module.exports = [
181
181
  toZigbee: [],
182
182
  exposes: [e.battery(), e.temperature()],
183
183
  configure: async (device, coordinatorEndpoint, logger) => {
184
- const endpoint = device.getEndpoint(3);
184
+ const endpoint = device.getEndpoint(3) || device.getEndpoint(1);
185
185
  await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
186
186
  await reporting.temperature(endpoint);
187
187
  await reporting.batteryVoltage(endpoint);
@@ -2729,6 +2729,13 @@ module.exports = [
2729
2729
  description: 'Hue white and color ambiance 5/6" retrofit recessed downlight',
2730
2730
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2731
2731
  },
2732
+ {
2733
+ zigbeeModel: ['LCD007'],
2734
+ model: '579573',
2735
+ vendor: 'Philips',
2736
+ description: 'Hue White and Color Ambiance Slim Downlight 6"',
2737
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2738
+ },
2732
2739
  {
2733
2740
  zigbeeModel: ['LWE004'],
2734
2741
  model: '8719514302235',
@@ -2876,4 +2883,18 @@ module.exports = [
2876
2883
  description: 'Hue white ambiance Garnea downlight',
2877
2884
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2878
2885
  },
2886
+ {
2887
+ zigbeeModel: ['LTE005'],
2888
+ model: '9290031452',
2889
+ vendor: 'Philips',
2890
+ description: 'Hue white ambiance filament E14 (with Bluetooth)',
2891
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [222, 454]}),
2892
+ },
2893
+ {
2894
+ zigbeeModel: ['LTB003'],
2895
+ model: '046677578138',
2896
+ vendor: 'Philips',
2897
+ description: 'Hue White ambiance BR30 E26',
2898
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2899
+ },
2879
2900
  ];
package/devices/sonoff.js CHANGED
@@ -195,6 +195,7 @@ module.exports = [
195
195
  description: '15A Zigbee smart plug',
196
196
  extend: extend.switch(),
197
197
  fromZigbee: [fz.on_off_skip_duplicate_transaction],
198
+ ota: ota.zigbeeOTA,
198
199
  configure: async (device, coordinatorEndpoint, logger) => {
199
200
  const endpoint = device.getEndpoint(1);
200
201
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
package/devices/tuya.js CHANGED
@@ -759,7 +759,7 @@ module.exports = [
759
759
  description: 'Smart air house keeper',
760
760
  fromZigbee: [fz.tuya_air_quality],
761
761
  toZigbee: [],
762
- exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd().withUnit('ppm'),
762
+ exposes: [e.temperature(), e.humidity(), e.co2(), e.voc().withUnit('ppm'), e.formaldehyd().withUnit('µg/m³'),
763
763
  e.pm25().withValueMin(0).withValueMax(999).withValueStep(1)],
764
764
  },
765
765
  {
@@ -803,7 +803,6 @@ module.exports = [
803
803
  fingerprint: [{modelID: 'TS0001', manufacturerName: '_TZ3000_hktqahrq'}, {manufacturerName: '_TZ3000_hktqahrq'},
804
804
  {manufacturerName: '_TZ3000_q6a3tepg'}, {modelID: 'TS000F', manufacturerName: '_TZ3000_m9af2l6g'},
805
805
  {modelID: 'TS000F', manufacturerName: '_TZ3000_mx3vgyea'},
806
- {modelID: 'TS000F', manufacturerName: '_TZ3000_xkap8wtb'},
807
806
  {modelID: 'TS0001', manufacturerName: '_TZ3000_npzfdcof'},
808
807
  {modelID: 'TS0001', manufacturerName: '_TZ3000_5ng23zjs'},
809
808
  {modelID: 'TS0001', manufacturerName: '_TZ3000_rmjr4ufz'},
@@ -925,7 +924,8 @@ module.exports = [
925
924
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bf175wi4'},
926
925
  {modelID: 'TS0505B', manufacturerName: '_TZB210_3zfp8mki'},
927
926
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_y1vbo44x'},
928
- {modelID: 'TS0505B', manufacturerName: '_TZ3210_mny0zvkm'}],
927
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_mny0zvkm'},
928
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_pfupy2pg'}],
929
929
  model: 'TS0505B',
930
930
  vendor: 'TuYa',
931
931
  description: 'Zigbee RGB+CCT light',
@@ -934,6 +934,7 @@ module.exports = [
934
934
  {vendor: 'Aldi', model: 'L122CB63H11A9.0W', description: 'LIGHTWAY smart home LED-lamp - bulb'},
935
935
  {vendor: 'Lidl', model: '14153706L', description: 'Livarno smart LED ceiling light'},
936
936
  {vendor: 'Zemismart', model: 'LXZB-ZB-09A', description: 'Zemismart LED Surface Mounted Downlight 9W RGBW'},
937
+ {vendor: 'Feconn', model: 'FE-GU10-5W', description: 'Zigbee GU10 5W smart bulb'},
937
938
  ],
938
939
  extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500], disableColorTempStartup: true}),
939
940
  meta: {applyRedFix: true, enhancedHue: false},
@@ -1206,7 +1207,8 @@ module.exports = [
1206
1207
  ],
1207
1208
  },
1208
1209
  {
1209
- fingerprint: tuya.fingerprint('TS0601', ['_TZE200_ip2akl4w', '_TZE200_1agwnems', '_TZE200_la2c2uo9', '_TZE200_579lguh2']),
1210
+ fingerprint: tuya.fingerprint('TS0601', ['_TZE200_ip2akl4w', '_TZE200_1agwnems', '_TZE200_la2c2uo9', '_TZE200_579lguh2',
1211
+ '_TZE200_vucankjx']),
1210
1212
  model: 'TS0601_dimmer_1',
1211
1213
  vendor: 'TuYa',
1212
1214
  description: '1 gang smart dimmer',
@@ -1805,6 +1807,26 @@ module.exports = [
1805
1807
  exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(),
1806
1808
  exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore']).withDescription('Recover state after power outage')],
1807
1809
  },
1810
+ {
1811
+ fingerprint: tuya.fingerprint('TS000F', ['_TZ3000_xkap8wtb']),
1812
+ model: 'TS000F_power',
1813
+ description: 'Switch with power monitoring',
1814
+ vendor: 'TuYa',
1815
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report],
1816
+ toZigbee: [tz.on_off],
1817
+ configure: async (device, coordinatorEndpoint, logger) => {
1818
+ const endpoint = device.getEndpoint(1);
1819
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1820
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
1821
+ await reporting.rmsVoltage(endpoint, {change: 5});
1822
+ await reporting.activePower(endpoint, {change: 10});
1823
+ await reporting.currentSummDelivered(endpoint);
1824
+ endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
1825
+ device.save();
1826
+ },
1827
+ whiteLabel: [{vendor: 'Aubess', model: 'WDH02'}],
1828
+ exposes: [e.switch(), e.power(), e.voltage().withAccess(ea.STATE), e.energy()],
1829
+ },
1808
1830
  {
1809
1831
  zigbeeModel: ['TS0001'],
1810
1832
  model: 'TS0001',
@@ -3372,6 +3394,7 @@ module.exports = [
3372
3394
  {modelID: 'TS0601', manufacturerName: '_TZE200_jva8ink8'},
3373
3395
  {modelID: 'TS0601', manufacturerName: '_TZE200_holel4dk'},
3374
3396
  {modelID: 'TS0601', manufacturerName: '_TZE200_wukb7rhc'},
3397
+ {modelID: 'TS0601', manufacturerName: '_TZE204_ztc6ggyl'},
3375
3398
  {modelID: 'TS0601', manufacturerName: '_TZE200_ztc6ggyl'}],
3376
3399
  model: 'TS0601_smart_human_presense_sensor',
3377
3400
  vendor: 'TuYa',
package/lib/exposes.js CHANGED
@@ -498,7 +498,7 @@ module.exports = {
498
498
  occupancy_timeout_2: () => new Numeric(`occupancy_timeout`, access.SET).withValueMin(0).withValueStep(0.1).withUnit('s').withDescription('Time in seconds after which occupancy is cleared after detecting it (default is "detection_interval" + 2 seconds). The value must be equal to or greater than "detection_interval", and it can also be a fraction.'),
499
499
  vibration_timeout: () => new Numeric(`vibration_timeout`, access.SET).withValueMin(0).withDescription('Time in seconds after which vibration is cleared after detecting it (default 90 seconds).'),
500
500
  simulated_brightness: (extraNote='') => new Composite('simulated_brightness', 'simulated_brightness')
501
- .withDescription(`Simulate a brightness value. If this device provides a brightness_move_up or brightness_move_down action it is possible to specify the update interval and delta.${extraNote}`)
501
+ .withDescription(`Simulate a brightness value. If this device provides a brightness_move_up or brightness_move_down action it is possible to specify the update interval and delta. The action_brightness_delta indicates the delta for each interval. ${extraNote}`)
502
502
  .withFeature(new Numeric('delta', access.SET).withValueMin(0).withDescription('Delta per interval, 20 by default'))
503
503
  .withFeature(new Numeric('interval', access.SET).withValueMin(0).withUnit('ms').withDescription('Interval duration')),
504
504
  no_occupancy_since_true: () => new List(`no_occupancy_since`, access.SET).withDescription('Sends a message the last time occupancy (occupancy: true) was detected. When setting this for example to [10, 60] a `{"no_occupancy_since": 10}` will be send after 10 seconds and a `{"no_occupancy_since": 60}` after 60 seconds.'),
@@ -583,7 +583,7 @@ module.exports = {
583
583
  max_heat_setpoint_limit: (min, max, step) => new Numeric('max_heat_setpoint_limit', access.ALL).withUnit('°C').withDescription('Maximum Heating set point limit').withValueMin(min).withValueMax(max).withValueStep(step),
584
584
  min_heat_setpoint_limit: (min, max, step) => new Numeric('min_heat_setpoint_limit', access.ALL).withUnit('°C').withDescription('Minimum Heating set point limit').withValueMin(min).withValueMax(max).withValueStep(step),
585
585
  max_temperature: () => new Numeric('max_temperature', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature').withValueMin(15).withValueMax(35),
586
- max_temperature_limit: () => new Numeric('max_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature limit. Cuts the thermostat out regardless of air temperature if the external floor sensor exceeds this temperature. Only used by the thermostat when in AL sensor mode.').withValueMin(20).withValueMax(70),
586
+ max_temperature_limit: () => new Numeric('max_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature limit. Cuts the thermostat out regardless of air temperature if the external floor sensor exceeds this temperature. Only used by the thermostat when in AL sensor mode.').withValueMin(0).withValueMax(35),
587
587
  min_temperature_limit: () => new Numeric('min_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Minimum temperature limit for frost protection. Turns the thermostat on regardless of setpoint if the tempreature drops below this.').withValueMin(1).withValueMax(5),
588
588
  min_temperature: () => new Numeric('min_temperature', access.STATE_SET).withUnit('°C').withDescription('Minimum temperature').withValueMin(1).withValueMax(15),
589
589
  noise: () => new Numeric('noise', access.STATE).withUnit('dBA').withDescription('The measured noise value'),
package/lib/legacy.js CHANGED
@@ -114,7 +114,8 @@ const postfixWithEndpointName = (name, msg, definition) => {
114
114
  };
115
115
 
116
116
  const transactionStore = {};
117
- const hasAlreadyProcessedMessage = (msg, transaction=null, key=null) => {
117
+ const hasAlreadyProcessedMessage = (msg, model, transaction=null, key=null) => {
118
+ if (model.meta && model.meta.publishDuplicateTransaction) return false;
118
119
  const current = transaction !== null ? transaction : msg.meta.zclTransactionSequenceNumber;
119
120
  key = key || msg.device.ieeeAddr;
120
121
  if (transactionStore[key] === current) return true;
package/lib/tuya.js CHANGED
@@ -1292,7 +1292,9 @@ const valueConverter = {
1292
1292
  const rMinutes = Math.round(minutes);
1293
1293
  const strHours = rHours.toString().padStart(2, '0');
1294
1294
  const strMinutes = rMinutes.toString().padStart(2, '0');
1295
- const temp = parseFloat(v[i * periodSize + 2] / 10);
1295
+ const tempHexArray = [v[i * periodSize + 1], v[i * periodSize + 2]];
1296
+ const tempRaw = Buffer.from(tempHexArray).readUIntBE(0, tempHexArray.length);
1297
+ const temp = tempRaw / 10;
1296
1298
  schedule.push(`${strHours}:${strMinutes}/${temp}`);
1297
1299
  if (rHours === 24) break;
1298
1300
  }
@@ -1351,7 +1353,8 @@ const valueConverter = {
1351
1353
  }
1352
1354
  prevHour = h;
1353
1355
  const segment = (h * 60 + m) / 10;
1354
- payload.push(segment, 0, temp * 10);
1356
+ const tempHexArray = convertDecimalValueTo2ByteHexArray(temp * 10);
1357
+ payload.push(segment, ...tempHexArray);
1355
1358
  }
1356
1359
 
1357
1360
  // Add "technical" periods to be valid payload
package/lib/utils.js CHANGED
@@ -179,6 +179,10 @@ function batteryVoltageToPercentage(voltage, option) {
179
179
  } else if (option === 'Add_1V_42V_CSM300z2v2') {
180
180
  voltage = voltage + 1000;
181
181
  percentage = toPercentage(voltage, 2900, 4100);
182
+ // Generic converter that expects an option object with min and max values
183
+ // I.E. meta: {battery: {voltageToPercentage: {min: 1900, max: 3000}}}
184
+ } else if (typeof option === 'object') {
185
+ percentage = toPercentage(voltage, option.min, option.max);
182
186
  } else {
183
187
  throw new Error(`Not batteryVoltageToPercentage type supported: ${option}`);
184
188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.659",
3
+ "version": "14.0.661",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [