zigbee-herdsman-converters 14.0.660 → 14.0.662

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
 
@@ -3420,6 +3420,12 @@ const converters = {
3420
3420
  return tuya.sendDataPointRaw(entity, tuya.dataPoints.moesSchedule, payload);
3421
3421
  },
3422
3422
  },
3423
+ moesS_thermostat_system_mode: {
3424
+ key: ['system_mode'],
3425
+ convertSet: async (entity, key, value, meta) => {
3426
+ return {state: {system_mode: 'heat'}};
3427
+ },
3428
+ },
3423
3429
  moesS_thermostat_preset: {
3424
3430
  key: ['preset'],
3425
3431
  convertSet: async (entity, key, value, meta) => {
@@ -0,0 +1,28 @@
1
+ const exposes = require('../lib/exposes');
2
+ const fz = require('../converters/fromZigbee');
3
+ const reporting = require('../lib/reporting');
4
+ const e = exposes.presets;
5
+
6
+ module.exports = [
7
+ {
8
+ fingerprint: [{modelID: 'TS0201', manufacturerName: '_TYZB01_ujfk3xd9'}],
9
+ model: 'M423-9E',
10
+ vendor: 'Akuvox',
11
+ description: 'Smart temperature & humidity Sensor',
12
+ exposes: [e.battery(), e.temperature(), e.humidity()],
13
+ fromZigbee: [fz.temperature, fz.humidity, fz.battery],
14
+ toZigbee: [],
15
+ meta: {battery: {voltageToPercentage: '3V_2500'}},
16
+ configure: async (device, coordinatorEndpoint, logger) => {
17
+ const endpoint1 = device.getEndpoint(1);
18
+ await reporting.bind(endpoint1, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
19
+ await endpoint1.read('genPowerCfg', ['batteryPercentageRemaining']);
20
+ const endpoint2 = device.getEndpoint(2);
21
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['msRelativeHumidity']);
22
+ await reporting.temperature(endpoint1);
23
+ await reporting.humidity(endpoint2);
24
+ await reporting.batteryVoltage(endpoint1);
25
+ await reporting.batteryPercentageRemaining(endpoint1);
26
+ },
27
+ },
28
+ ];
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(),
@@ -31,4 +31,17 @@ module.exports = [
31
31
  extend: extend.light_onoff_brightness(),
32
32
  ota: ota.zigbeeOTA,
33
33
  },
34
+ {
35
+ zigbeeModel: ['FLS-A lp (1-10V)'],
36
+ model: 'BN-600078',
37
+ vendor: 'Dresden Elektronik',
38
+ description: 'Zigbee controller for 1-10V/PWM',
39
+ extend: extend.light_onoff_brightness(),
40
+ exposes: [e.light_brightness().withEndpoint('l1'), e.light_brightness().withEndpoint('l2'),
41
+ e.light_brightness().withEndpoint('l3'), e.light_brightness().withEndpoint('l4')],
42
+ endpoint: (device) => {
43
+ return {'l1': 11, 'l2': 12, 'l3': 13, 'l4': 14};
44
+ },
45
+ meta: {multiEndpoint: true, disableDefaultResponse: true},
46
+ },
34
47
  ];
@@ -21,6 +21,10 @@ module.exports = [
21
21
  await reporting.onOff(endpoint);
22
22
  await reporting.brightness(endpoint);
23
23
  await reporting.fanMode(endpoint);
24
+
25
+ // Has Unknown power source, force it here.
26
+ device.powerSource = 'Mains (single phase)';
27
+ device.save();
24
28
  },
25
29
  },
26
30
  {
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
 
package/devices/innr.js CHANGED
@@ -1,10 +1,11 @@
1
1
  const exposes = require('../lib/exposes');
2
- const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
2
+ const fz = require('../converters/fromZigbee');
3
3
  const tz = require('../converters/toZigbee');
4
4
  const reporting = require('../lib/reporting');
5
5
  const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
7
  const ea = exposes.access;
8
+ const ota = require('../lib/ota');
8
9
 
9
10
  module.exports = [
10
11
  {
@@ -591,6 +592,7 @@ module.exports = [
591
592
  // Gives UNSUPPORTED_ATTRIBUTE on reporting.readMeteringMultiplierDivisor.
592
593
  endpoint.saveClusterAttributeKeyValue('seMetering', {multiplier: 1, divisor: 100});
593
594
  },
595
+ ota: ota.zigbeeOTA,
594
596
  exposes: [e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.switch(), e.energy()],
595
597
  },
596
598
  {
@@ -25,25 +25,40 @@ const buttonLookup = {
25
25
  };
26
26
 
27
27
  const ledEffects = {
28
- 'off': 0,
29
- 'solid': 1,
30
- 'fast_blink': 2,
31
- 'slow_blink': 3,
32
- 'pulse': 4,
33
- 'chase': 5,
34
- 'open_close': 6,
35
- 'small_to_big': 7,
36
- 'clear_effect': 255,
28
+ off: 0,
29
+ solid: 1,
30
+ fast_blink: 2,
31
+ slow_blink: 3,
32
+ pulse: 4,
33
+ chase: 5,
34
+ open_close: 6,
35
+ small_to_big: 7,
36
+ aurora: 8,
37
+ slow_falling: 9,
38
+ medium_falling: 10,
39
+ fast_falling: 11,
40
+ slow_rising: 12,
41
+ medium_rising: 13,
42
+ fast_rising: 14,
43
+ medium_blink: 15,
44
+ slow_chase: 16,
45
+ fast_chase: 17,
46
+ fast_siren: 18,
47
+ slow_siren: 19,
48
+ clear_effect: 255,
37
49
  };
38
50
 
39
51
  const individualLedEffects = {
40
- 'off': 0,
41
- 'solid': 1,
42
- 'fast_blink': 2,
43
- 'slow_blink': 3,
44
- 'pulse': 4,
45
- 'chase': 5,
46
- 'clear_effect': 255,
52
+ off: 0,
53
+ solid: 1,
54
+ fast_blink: 2,
55
+ slow_blink: 3,
56
+ pulse: 4,
57
+ chase: 5,
58
+ falling: 6,
59
+ rising: 7,
60
+ aurora: 8,
61
+ clear_effect: 255,
47
62
  };
48
63
 
49
64
  const UINT8 = 32;
@@ -629,8 +644,20 @@ const ATTRIBUTES = {
629
644
  dataType: BOOLEAN,
630
645
  min: 0,
631
646
  max: 1,
632
- description: 'Audible Click in On/Off mode.',
633
- values: {'Enabled (Default)': 1, 'Disabled': 0},
647
+ description:
648
+ 'In neutral on/off setups, the default is to have a clicking sound to notify you that the relay ' +
649
+ 'is open or closed. You may disable this sound by creating a, “simulated” on/off where the switch ' +
650
+ 'only will turn onto 100 or off to 0.',
651
+ values: {'Disabled (Click Sound On)': 0, 'Enabled (Click Sound Off)': 1},
652
+ displayType: 'enum',
653
+ },
654
+ doubleTapClearNotifications: {
655
+ ID: 262,
656
+ dataType: BOOLEAN,
657
+ min: 0,
658
+ max: 1,
659
+ description: 'Double-Tap the Config button to clear notifications.',
660
+ values: {'Enabled (Default)': 0, 'Disabled': 1},
634
661
  displayType: 'enum',
635
662
  },
636
663
  };
@@ -656,12 +683,11 @@ tzLocal.inovelli_vzw31sn_parameters = {
656
683
  manufacturerCode: INOVELLI,
657
684
  });
658
685
 
686
+ meta.state[key] = value;
687
+
659
688
  return {
660
689
  state: {
661
- [key]:
662
- ATTRIBUTES[key].displayType === 'enum' ?
663
- ATTRIBUTES[key].values[value] :
664
- value,
690
+ [key]: value,
665
691
  },
666
692
  };
667
693
  },
@@ -1057,12 +1083,24 @@ const exposesList = [
1057
1083
  .enum('effect', ea.SET_STATE, [
1058
1084
  'off',
1059
1085
  'solid',
1060
- 'chase',
1061
1086
  'fast_blink',
1062
1087
  'slow_blink',
1063
1088
  'pulse',
1089
+ 'chase',
1064
1090
  'open_close',
1065
1091
  'small_to_big',
1092
+ 'aurora',
1093
+ 'slow_falling',
1094
+ 'medium_falling',
1095
+ 'fast_falling',
1096
+ 'slow_rising',
1097
+ 'medium_rising',
1098
+ 'fast_rising',
1099
+ 'medium_blink',
1100
+ 'slow_chase',
1101
+ 'fast_chase',
1102
+ 'fast_siren',
1103
+ 'slow_siren',
1066
1104
  'clear_effect',
1067
1105
  ])
1068
1106
  .withDescription('Animation Effect to use for the LEDs'),
@@ -1110,6 +1148,9 @@ const exposesList = [
1110
1148
  'slow_blink',
1111
1149
  'pulse',
1112
1150
  'chase',
1151
+ 'falling',
1152
+ 'rising',
1153
+ 'aurora',
1113
1154
  'clear_effect',
1114
1155
  ])
1115
1156
  .withDescription('Animation Effect to use for the LED'),
@@ -1247,7 +1288,11 @@ module.exports = [
1247
1288
  await reporting.bind(endpoint, coordinatorEndpoint, [
1248
1289
  'seMetering',
1249
1290
  'haElectricalMeasurement',
1291
+ 'genOnOff',
1292
+ 'genLevelCtrl',
1250
1293
  ]);
1294
+ await reporting.onOff(endpoint);
1295
+
1251
1296
  // Bind for Button Event Reporting
1252
1297
  const endpoint2 = device.getEndpoint(2);
1253
1298
  await reporting.bind(endpoint2, coordinatorEndpoint, [
@@ -68,7 +68,7 @@ module.exports = [
68
68
  model: 'AC33905',
69
69
  vendor: 'LEDVANCE',
70
70
  description: 'SMART+ spot GU10 tunable white',
71
- extend: extend.ledvance.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
71
+ extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
72
72
  ota: ota.ledvance,
73
73
  },
74
74
  {
@@ -87,6 +87,14 @@ module.exports = [
87
87
  extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
88
88
  ota: ota.ledvance,
89
89
  },
90
+ {
91
+ zigbeeModel: ['B40S TW'],
92
+ model: 'AC33901',
93
+ vendor: 'LEDVANCE',
94
+ description: 'SMART+ Classic B40 E14 Tunable white',
95
+ extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
96
+ ota: ota.ledvance,
97
+ },
90
98
  {
91
99
  zigbeeModel: ['FLEX RGBW Z3'],
92
100
  model: '4058075208339',
@@ -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/lidl.js CHANGED
@@ -399,27 +399,29 @@ module.exports = [
399
399
  model: 'HG08673-FR',
400
400
  vendor: 'Lidl',
401
401
  description: 'Silvercrest smart plug FR with power monitoring',
402
- ota: ota.zigbeeOTA, // Even though it's a Lidl Device it supports Tuya OTA
402
+ ota: ota.zigbeeOTA,
403
403
  fromZigbee: [fz.on_off, fzLocal.electrical_measurement_skip_duplicate, fzLocal.metering_skip_duplicate, fz.ignore_basic_report,
404
404
  fz.tuya_switch_power_outage_memory, fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
405
405
  toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.ts011f_plug_indicator_mode, tz.ts011f_plug_child_mode],
406
406
  configure: async (device, coordinatorEndpoint, logger) => {
407
407
  const endpoint = device.getEndpoint(1);
408
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
409
- await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
408
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
409
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
410
410
  await reporting.rmsVoltage(endpoint, {change: 5});
411
411
  await reporting.rmsCurrent(endpoint, {change: 50});
412
412
  await reporting.activePower(endpoint, {change: 10});
413
- await reporting.currentSummDelivered(endpoint);
413
+ // Energy reporting (currentSummDelivered) doesn't work; requires polling: https://github.com/Koenkk/zigbee2mqtt/issues/14356
414
414
  endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
415
415
  endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
416
416
  device.save();
417
417
  },
418
+ options: [exposes.options.measurement_poll_interval().withDescription('Only the energy value is polled for this device.')],
418
419
  exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
419
420
  e.energy(), exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore'])
420
421
  .withDescription('Recover state after power outage'),
421
422
  exposes.enum('indicator_mode', ea.ALL, ['off', 'off/on', 'on/off', 'on'])
422
423
  .withDescription('Plug LED indicator mode'), e.child_lock()],
424
+ onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, false, true),
423
425
  },
424
426
  {
425
427
  fingerprint: [{modelID: 'TS004F', manufacturerName: '_TZ3000_rco1yzb1'}],
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
  ];
@@ -50,8 +50,11 @@ module.exports = [
50
50
  onEvent: tuya.onEventSetTime,
51
51
  },
52
52
  {
53
- fingerprint: [{modelID: 'TS0502B', manufacturerName: '_TZ3210_frm6149r'},
54
- {modelID: 'TS0502B', manufacturerName: '_TZ3210_jtifm80b'}],
53
+ fingerprint: [
54
+ {modelID: 'TS0502B', manufacturerName: '_TZ3210_frm6149r'},
55
+ {modelID: 'TS0502B', manufacturerName: '_TZ3210_jtifm80b'},
56
+ {modelID: 'TS0502B', manufacturerName: '_TZ3210_xwqng7ol'},
57
+ ],
55
58
  model: 'FUT035Z',
56
59
  description: 'Dual white LED controller',
57
60
  vendor: 'Miboxer',
package/devices/moes.js CHANGED
@@ -299,7 +299,8 @@ module.exports = [
299
299
  tz.moesS_thermostat_boost_heating, tz.moesS_thermostat_boostHeatingCountdownTimeSet,
300
300
  tz.moesS_thermostat_eco_temperature, tz.moesS_thermostat_max_temperature,
301
301
  tz.moesS_thermostat_min_temperature, tz.moesS_thermostat_moesSecoMode,
302
- tz.moesS_thermostat_preset, tz.moesS_thermostat_schedule_programming],
302
+ tz.moesS_thermostat_preset, tz.moesS_thermostat_schedule_programming,
303
+ tz.moesS_thermostat_system_mode],
303
304
  exposes: [
304
305
  e.battery(), e.child_lock(), e.eco_mode(),
305
306
  e.eco_temperature().withValueMin(5), e.max_temperature().withValueMax(45), e.min_temperature().withValueMin(5),
@@ -308,7 +309,7 @@ module.exports = [
308
309
  exposes.climate()
309
310
  .withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 35, 1, ea.STATE_SET)
310
311
  .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
311
- .withSystemMode(['heat'], ea.STATE)
312
+ .withSystemMode(['heat'], ea.STATE_SET)
312
313
  .withRunningState(['idle', 'heat'], ea.STATE)
313
314
  .withPreset(['programming', 'manual', 'temporary_manual', 'holiday'],
314
315
  'MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. '+
@@ -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'),
package/devices/nue_3a.js CHANGED
@@ -99,7 +99,7 @@ module.exports = [
99
99
  exposes: [e.action(['recall_*']), e.switch()],
100
100
  },
101
101
  {
102
- zigbeeModel: ['LXN56-DC27LX1.1', 'LXN56-DS27LX1.1'],
102
+ zigbeeModel: ['LXN56-DC27LX1.1', 'LXN56-DS27LX1.1', 'LXN56-DS27LX1.3'],
103
103
  model: 'LXZB-02A',
104
104
  vendor: 'Nue / 3A',
105
105
  description: 'Smart light controller',
@@ -159,7 +159,7 @@ module.exports = [
159
159
  },
160
160
  },
161
161
  {
162
- zigbeeModel: ['FB56+ZSC05HG1.0', 'FNB56-ZBW01LX1.2', 'LXN56-DS27LX1.3', 'LXN60-DS27LX1.3'],
162
+ zigbeeModel: ['FB56+ZSC05HG1.0', 'FNB56-ZBW01LX1.2', 'LXN60-DS27LX1.3'],
163
163
  model: 'HGZB-04D / HGZB-4D-UK',
164
164
  vendor: 'Nue / 3A',
165
165
  description: 'Smart dimmer wall switch',
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/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);
@@ -1634,6 +1634,16 @@ module.exports = [
1634
1634
  ...hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}).exposes],
1635
1635
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
1636
1636
  },
1637
+ {
1638
+ zigbeeModel: ['915005987601'],
1639
+ model: '915005987601',
1640
+ vendor: 'Philips',
1641
+ description: 'Hue Gradient Signe floor lamp (black)',
1642
+ toZigbee: [tzLocal.gradient_scene, ...hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}).toZigbee],
1643
+ exposes: [exposes.enum('gradient_scene', ea.SET, Object.keys(gradientScenes)),
1644
+ ...hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}).exposes],
1645
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
1646
+ },
1637
1647
  {
1638
1648
  zigbeeModel: ['LCT020'],
1639
1649
  model: '4080148P7',
@@ -2890,4 +2900,11 @@ module.exports = [
2890
2900
  description: 'Hue white ambiance filament E14 (with Bluetooth)',
2891
2901
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [222, 454]}),
2892
2902
  },
2903
+ {
2904
+ zigbeeModel: ['LTB003'],
2905
+ model: '046677578138',
2906
+ vendor: 'Philips',
2907
+ description: 'Hue White ambiance BR30 E26',
2908
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2909
+ },
2893
2910
  ];
package/devices/sinope.js CHANGED
@@ -249,7 +249,7 @@ module.exports = [
249
249
  .withFeature(exposes.numeric('r', ea.ALL))
250
250
  .withFeature(exposes.numeric('g', ea.ALL))
251
251
  .withFeature(exposes.numeric('b', ea.ALL))
252
- .withDescription('Control status LED intensity when load ON'),
252
+ .withDescription('Control status LED color when load ON'),
253
253
  exposes.composite('led_color_off', 'led_color_off')
254
254
  .withFeature(exposes.numeric('r', ea.ALL))
255
255
  .withFeature(exposes.numeric('g', ea.ALL))
@@ -280,7 +280,7 @@ module.exports = [
280
280
  .withFeature(exposes.numeric('r', ea.ALL))
281
281
  .withFeature(exposes.numeric('g', ea.ALL))
282
282
  .withFeature(exposes.numeric('b', ea.ALL))
283
- .withDescription('Control status LED intensity when load ON'),
283
+ .withDescription('Control status LED color when load ON'),
284
284
  exposes.composite('led_color_off', 'led_color_off')
285
285
  .withFeature(exposes.numeric('r', ea.ALL))
286
286
  .withFeature(exposes.numeric('g', ea.ALL))
package/devices/tuya.js CHANGED
@@ -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'},
@@ -841,10 +840,7 @@ module.exports = [
841
840
  return {'l1': 1, 'l2': 2};
842
841
  },
843
842
  meta: {multiEndpoint: true},
844
- configure: async (device, coordinatorEndpoint, logger) => {
845
- const endpoint = device.getEndpoint(1);
846
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
847
- },
843
+ configure: tuya.configureMagicPacket,
848
844
  },
849
845
  {
850
846
  fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_rk2yzt0u'},
@@ -925,7 +921,8 @@ module.exports = [
925
921
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bf175wi4'},
926
922
  {modelID: 'TS0505B', manufacturerName: '_TZB210_3zfp8mki'},
927
923
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_y1vbo44x'},
928
- {modelID: 'TS0505B', manufacturerName: '_TZ3210_mny0zvkm'}],
924
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_mny0zvkm'},
925
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_pfupy2pg'}],
929
926
  model: 'TS0505B',
930
927
  vendor: 'TuYa',
931
928
  description: 'Zigbee RGB+CCT light',
@@ -934,6 +931,7 @@ module.exports = [
934
931
  {vendor: 'Aldi', model: 'L122CB63H11A9.0W', description: 'LIGHTWAY smart home LED-lamp - bulb'},
935
932
  {vendor: 'Lidl', model: '14153706L', description: 'Livarno smart LED ceiling light'},
936
933
  {vendor: 'Zemismart', model: 'LXZB-ZB-09A', description: 'Zemismart LED Surface Mounted Downlight 9W RGBW'},
934
+ {vendor: 'Feconn', model: 'FE-GU10-5W', description: 'Zigbee GU10 5W smart bulb'},
937
935
  ],
938
936
  extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500], disableColorTempStartup: true}),
939
937
  meta: {applyRedFix: true, enhancedHue: false},
@@ -1084,10 +1082,7 @@ module.exports = [
1084
1082
  exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
1085
1083
  exposes.enum('keep_time', ea.ALL, [30, 60, 120]).withDescription('PIR keep time in seconds'),
1086
1084
  ],
1087
- configure: async (device, coordinatorEndpoint, logger) => {
1088
- const endpoint = device.getEndpoint(1);
1089
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1090
- },
1085
+ configure: tuya.configureMagicPacket,
1091
1086
  },
1092
1087
  {
1093
1088
  fingerprint: [{modelID: 'TS0202', manufacturerName: '_TZ3040_msl6wxk9'}],
@@ -1100,10 +1095,7 @@ module.exports = [
1100
1095
  exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
1101
1096
  exposes.enum('keep_time', ea.ALL, [30, 60, 120]).withDescription('PIR keep time in seconds'),
1102
1097
  ],
1103
- configure: async (device, coordinatorEndpoint, logger) => {
1104
- const endpoint = device.getEndpoint(1);
1105
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1106
- },
1098
+ configure: tuya.configureMagicPacket,
1107
1099
  },
1108
1100
  {
1109
1101
  fingerprint: tuya.fingerprint('TS0202', ['_TZ3000_mcxw5ehu', '_TZ3040_6ygjfyll']),
@@ -1206,7 +1198,8 @@ module.exports = [
1206
1198
  ],
1207
1199
  },
1208
1200
  {
1209
- fingerprint: tuya.fingerprint('TS0601', ['_TZE200_ip2akl4w', '_TZE200_1agwnems', '_TZE200_la2c2uo9', '_TZE200_579lguh2']),
1201
+ fingerprint: tuya.fingerprint('TS0601', ['_TZE200_ip2akl4w', '_TZE200_1agwnems', '_TZE200_la2c2uo9', '_TZE200_579lguh2',
1202
+ '_TZE200_vucankjx']),
1210
1203
  model: 'TS0601_dimmer_1',
1211
1204
  vendor: 'TuYa',
1212
1205
  description: '1 gang smart dimmer',
@@ -1591,10 +1584,7 @@ module.exports = [
1591
1584
  fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fzLocal.TS0201_humidity],
1592
1585
  toZigbee: [],
1593
1586
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
1594
- configure: async (device, coordinatorEndpoint, logger) => {
1595
- const endpoint = device.getEndpoint(1);
1596
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1597
- },
1587
+ configure: tuya.configureMagicPacket,
1598
1588
  },
1599
1589
  {
1600
1590
  fingerprint: [
@@ -1609,10 +1599,7 @@ module.exports = [
1609
1599
  fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
1610
1600
  toZigbee: [],
1611
1601
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
1612
- configure: async (device, coordinatorEndpoint, logger) => {
1613
- const endpoint = device.getEndpoint(1);
1614
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1615
- },
1602
+ configure: tuya.configureMagicPacket,
1616
1603
  },
1617
1604
  {
1618
1605
  fingerprint: tuya.fingerprint('TS0201', ['_TZ3000_dowj6gyi', '_TZ3000_8ybe88nf']),
@@ -1622,10 +1609,7 @@ module.exports = [
1622
1609
  fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
1623
1610
  toZigbee: [],
1624
1611
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
1625
- configure: async (device, coordinatorEndpoint, logger) => {
1626
- const endpoint = device.getEndpoint(1);
1627
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1628
- },
1612
+ configure: tuya.configureMagicPacket,
1629
1613
  },
1630
1614
  {
1631
1615
  fingerprint: [{modelID: 'SM0201', manufacturerName: '_TYZB01_cbiezpds'}],
@@ -1651,9 +1635,8 @@ module.exports = [
1651
1635
  return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4};
1652
1636
  },
1653
1637
  meta: {multiEndpoint: true},
1654
- configure: async (device, coordinatorEndpoint) => {
1655
- await device.getEndpoint(1).read('genBasic',
1656
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1638
+ configure: async (device, coordinatorEndpoint, logger) => {
1639
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1657
1640
  for (const endpointID of [1, 2, 3, 4]) {
1658
1641
  const endpoint = device.getEndpoint(endpointID);
1659
1642
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
@@ -1791,8 +1774,8 @@ module.exports = [
1791
1774
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
1792
1775
  toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
1793
1776
  configure: async (device, coordinatorEndpoint, logger) => {
1777
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1794
1778
  const endpoint = device.getEndpoint(1);
1795
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1796
1779
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
1797
1780
  await reporting.rmsVoltage(endpoint, {change: 5});
1798
1781
  await reporting.rmsCurrent(endpoint, {change: 50});
@@ -1805,6 +1788,28 @@ module.exports = [
1805
1788
  exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(),
1806
1789
  exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore']).withDescription('Recover state after power outage')],
1807
1790
  },
1791
+ {
1792
+ fingerprint: tuya.fingerprint('TS000F', ['_TZ3000_xkap8wtb']),
1793
+ model: 'TS000F_power',
1794
+ description: 'Switch with power monitoring',
1795
+ vendor: 'TuYa',
1796
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.moes_power_on_behavior,
1797
+ fz.tuya_switch_type],
1798
+ toZigbee: [tz.on_off, tz.moes_power_on_behavior, tz.tuya_switch_type],
1799
+ configure: async (device, coordinatorEndpoint, logger) => {
1800
+ const endpoint = device.getEndpoint(1);
1801
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1802
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
1803
+ await reporting.rmsVoltage(endpoint, {change: 5});
1804
+ await reporting.activePower(endpoint, {change: 10});
1805
+ endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
1806
+ device.save();
1807
+ },
1808
+ options: [exposes.options.measurement_poll_interval().withDescription('Only the energy value is polled for this device.')],
1809
+ onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, false, true),
1810
+ whiteLabel: [{vendor: 'Aubess', model: 'WDH02'}],
1811
+ exposes: [e.switch(), e.power(), e.voltage().withAccess(ea.STATE), e.energy(), e.power_on_behavior(), e.switch_type_2()],
1812
+ },
1808
1813
  {
1809
1814
  zigbeeModel: ['TS0001'],
1810
1815
  model: 'TS0001',
@@ -1876,8 +1881,7 @@ module.exports = [
1876
1881
  },
1877
1882
  meta: {multiEndpoint: true},
1878
1883
  configure: async (device, coordinatorEndpoint, logger) => {
1879
- await device.getEndpoint(1).read('genBasic',
1880
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1884
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1881
1885
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
1882
1886
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
1883
1887
  },
@@ -1924,8 +1928,7 @@ module.exports = [
1924
1928
  },
1925
1929
  meta: {multiEndpoint: true},
1926
1930
  configure: async (device, coordinatorEndpoint, logger) => {
1927
- await device.getEndpoint(1).read('genBasic',
1928
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1931
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1929
1932
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
1930
1933
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
1931
1934
  await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
@@ -1952,8 +1955,7 @@ module.exports = [
1952
1955
  },
1953
1956
  meta: {multiEndpoint: true},
1954
1957
  configure: async (device, coordinatorEndpoint, logger) => {
1955
- await device.getEndpoint(1).read('genBasic',
1956
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1958
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
1957
1959
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
1958
1960
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
1959
1961
  await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
@@ -2353,8 +2355,8 @@ module.exports = [
2353
2355
  fz.tuya_switch_power_outage_memory, fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
2354
2356
  toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.ts011f_plug_indicator_mode, tz.ts011f_plug_child_mode],
2355
2357
  configure: async (device, coordinatorEndpoint, logger) => {
2358
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
2356
2359
  const endpoint = device.getEndpoint(1);
2357
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
2358
2360
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
2359
2361
  await reporting.rmsVoltage(endpoint, {change: 5});
2360
2362
  await reporting.rmsCurrent(endpoint, {change: 50});
@@ -2407,14 +2409,8 @@ module.exports = [
2407
2409
  fz.tuya_switch_power_outage_memory, fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
2408
2410
  toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.ts011f_plug_indicator_mode, tz.ts011f_plug_child_mode],
2409
2411
  configure: async (device, coordinatorEndpoint, logger) => {
2412
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
2410
2413
  const endpoint = device.getEndpoint(1);
2411
- // Enables reporting of physical state changes
2412
- // https://github.com/Koenkk/zigbee2mqtt/issues/9057#issuecomment-1007742130
2413
- try {
2414
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
2415
- } catch (e) {
2416
- // Sometimes can fail: https://github.com/Koenkk/zigbee2mqtt/issues/12760#issuecomment-1165435220
2417
- }
2418
2414
  endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
2419
2415
  endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
2420
2416
  device.save();
@@ -2658,8 +2654,7 @@ module.exports = [
2658
2654
  },
2659
2655
  meta: {multiEndpoint: true},
2660
2656
  configure: async (device, coordinatorEndpoint, logger) => {
2661
- await device.getEndpoint(1).read('genBasic',
2662
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
2657
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
2663
2658
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
2664
2659
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
2665
2660
  device.powerSource = 'Mains (single phase)';
@@ -2712,8 +2707,7 @@ module.exports = [
2712
2707
  whiteLabel: [{vendor: 'TUYATEC', model: 'GDKES-03TZXD'}],
2713
2708
  meta: {multiEndpoint: true},
2714
2709
  configure: async (device, coordinatorEndpoint, logger) => {
2715
- await device.getEndpoint(1).read('genBasic',
2716
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
2710
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
2717
2711
  try {
2718
2712
  for (const ID of [1, 2, 3]) {
2719
2713
  const endpoint = device.getEndpoint(ID);
@@ -2834,8 +2828,7 @@ module.exports = [
2834
2828
  },
2835
2829
  meta: {multiEndpoint: true},
2836
2830
  configure: async (device, coordinatorEndpoint, logger) => {
2837
- await device.getEndpoint(1).read('genBasic',
2838
- ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
2831
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
2839
2832
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
2840
2833
  await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
2841
2834
  await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
@@ -3005,10 +2998,7 @@ module.exports = [
3005
2998
  fromZigbee: [fz.battery, fz.illuminance, fzLocal.TS0222],
3006
2999
  toZigbee: [],
3007
3000
  exposes: [e.battery(), e.illuminance(), e.illuminance_lux()],
3008
- configure: async (device, coordinatorEndpoint, logger) => {
3009
- const endpoint = device.getEndpoint(1);
3010
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
3011
- },
3001
+ configure: tuya.configureMagicPacket,
3012
3002
  },
3013
3003
  {
3014
3004
  fingerprint: [{modelID: 'TS0210', manufacturerName: '_TYZB01_3zv6oleo'},
@@ -3110,7 +3100,7 @@ module.exports = [
3110
3100
  configure: async (device, coordinatorEndpoint, logger) => {
3111
3101
  const endpoint = device.getEndpoint(1);
3112
3102
  // Enables reporting of measurement state changes
3113
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
3103
+ await tuya.configureMagicPacket(device, coordinatorEndpoint, logger);
3114
3104
  await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic', 'genPowerCfg',
3115
3105
  'msTemperatureMeasurement', 'msIlluminanceMeasurement', 'msRelativeHumidity', 'manuSpecificTuya_2']);
3116
3106
  },
@@ -3372,6 +3362,7 @@ module.exports = [
3372
3362
  {modelID: 'TS0601', manufacturerName: '_TZE200_jva8ink8'},
3373
3363
  {modelID: 'TS0601', manufacturerName: '_TZE200_holel4dk'},
3374
3364
  {modelID: 'TS0601', manufacturerName: '_TZE200_wukb7rhc'},
3365
+ {modelID: 'TS0601', manufacturerName: '_TZE204_ztc6ggyl'},
3375
3366
  {modelID: 'TS0601', manufacturerName: '_TZE200_ztc6ggyl'}],
3376
3367
  model: 'TS0601_smart_human_presense_sensor',
3377
3368
  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.'),
@@ -507,7 +507,7 @@ module.exports = {
507
507
  no_position_support: () => new Binary('no_position_support', access.SET, true, false).withDescription('Set to true when your device only reports position 0, 100 and 50 (in this case your device has an older firmware) (default false).'),
508
508
  transition: () => new Numeric(`transition`, access.SET).withValueMin(0).withDescription('Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).'),
509
509
  legacy: () => new Binary(`legacy`, access.SET, true, false).withDescription(`Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).`),
510
- measurement_poll_interval: () => new Numeric(`measurement_poll_interval`, access.SET).withValueMin(-1).withDescription(`This device does not support reporting electric measurements so it is polled instead. The default poll interval is 60 seconds, set to -1 to disable.`),
510
+ measurement_poll_interval: (extraNote='') => new Numeric(`measurement_poll_interval`, access.SET).withValueMin(-1).withDescription(`This device does not support reporting electric measurements so it is polled instead. The default poll interval is 60 seconds, set to -1 to disable.${extraNote}`),
511
511
  illuminance_below_threshold_check: () => new Binary(`illuminance_below_threshold_check`, access.SET, true, false).withDescription(`Set to false to also send messages when illuminance is above threshold in night mode (default true).`),
512
512
  },
513
513
  presets: {
@@ -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/tuya.js CHANGED
@@ -243,7 +243,7 @@ function convertDecimalValueTo2ByteHexArray(value) {
243
243
  return [chunk1, chunk2].map((hexVal) => parseInt(hexVal, 16));
244
244
  }
245
245
 
246
- async function onEventMeasurementPoll(type, data, device, options) {
246
+ async function onEventMeasurementPoll(type, data, device, options, electricalMeasurement=true, metering=false) {
247
247
  const endpoint = device.getEndpoint(1);
248
248
  if (type === 'stop') {
249
249
  clearInterval(globalStore.getValue(device, 'interval'));
@@ -253,7 +253,12 @@ async function onEventMeasurementPoll(type, data, device, options) {
253
253
  if (seconds === -1) return;
254
254
  const interval = setInterval(async () => {
255
255
  try {
256
- await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
256
+ if (electricalMeasurement) {
257
+ await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
258
+ }
259
+ if (metering) {
260
+ await endpoint.read('seMetering', ['currentSummDelivered']);
261
+ }
257
262
  } catch (error) {/* Do nothing*/}
258
263
  }, seconds*1000);
259
264
  globalStore.putValue(device, 'interval', interval);
@@ -1170,8 +1175,18 @@ const skip = {
1170
1175
  };
1171
1176
 
1172
1177
  const configureMagicPacket = async (device, coordinatorEndpoint, logger) => {
1173
- const endpoint = device.endpoints[0];
1174
- await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1178
+ try {
1179
+ const endpoint = device.endpoints[0];
1180
+ await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
1181
+ } catch (e) {
1182
+ // Fails for some TuYa devices with UNSUPPORTED_ATTRIBUTE, ignore that.
1183
+ // e.g. https://github.com/Koenkk/zigbee2mqtt/issues/14857
1184
+ if (e.message.includes('UNSUPPORTED_ATTRIBUTE')) {
1185
+ logger.debug('TuYa configureMagicPacket failed, ignoring...');
1186
+ } else {
1187
+ throw e;
1188
+ }
1189
+ }
1175
1190
  };
1176
1191
 
1177
1192
  const fingerprint = (modelID, manufacturerNames) => {
@@ -1231,7 +1246,7 @@ const valueConverter = {
1231
1246
  onOff: valueConverterBasic.lookup({'ON': true, 'OFF': false}),
1232
1247
  powerOnBehavior: valueConverterBasic.lookup({'off': 0, 'on': 1, 'previous': 2}),
1233
1248
  lightType: valueConverterBasic.lookup({'led': 0, 'incandescent': 1, 'halogen': 2}),
1234
- countdown: valueConverterBasic.raw,
1249
+ countdown: valueConverterBasic.raw(),
1235
1250
  scale0_254to0_1000: valueConverterBasic.scale(0, 254, 0, 1000),
1236
1251
  scale0_1to0_1000: valueConverterBasic.scale(0, 1, 0, 1000),
1237
1252
  divideBy100: valueConverterBasic.divideBy(100),
@@ -1292,7 +1307,9 @@ const valueConverter = {
1292
1307
  const rMinutes = Math.round(minutes);
1293
1308
  const strHours = rHours.toString().padStart(2, '0');
1294
1309
  const strMinutes = rMinutes.toString().padStart(2, '0');
1295
- const temp = parseFloat(v[i * periodSize + 2] / 10);
1310
+ const tempHexArray = [v[i * periodSize + 1], v[i * periodSize + 2]];
1311
+ const tempRaw = Buffer.from(tempHexArray).readUIntBE(0, tempHexArray.length);
1312
+ const temp = tempRaw / 10;
1296
1313
  schedule.push(`${strHours}:${strMinutes}/${temp}`);
1297
1314
  if (rHours === 24) break;
1298
1315
  }
@@ -1351,7 +1368,8 @@ const valueConverter = {
1351
1368
  }
1352
1369
  prevHour = h;
1353
1370
  const segment = (h * 60 + m) / 10;
1354
- payload.push(segment, 0, temp * 10);
1371
+ const tempHexArray = convertDecimalValueTo2ByteHexArray(temp * 10);
1372
+ payload.push(segment, ...tempHexArray);
1355
1373
  }
1356
1374
 
1357
1375
  // Add "technical" periods to be valid payload
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.660",
3
+ "version": "14.0.662",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [