zigbee-herdsman-converters 14.0.378 → 14.0.382

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.
@@ -1380,8 +1380,8 @@ const converters = {
1380
1380
  const payload = {
1381
1381
  action: postfixWithEndpointName(`color_move`, msg, model),
1382
1382
  action_color: {
1383
- x: precisionRound(msg.data.colorx / 65535, 3),
1384
- y: precisionRound(msg.data.colory / 65535, 3),
1383
+ x: precisionRound(msg.data.colorx / 65536, 3),
1384
+ y: precisionRound(msg.data.colory / 65536, 3),
1385
1385
  },
1386
1386
  action_transition_time: msg.data.transtime,
1387
1387
  };
@@ -7928,6 +7928,34 @@ const converters = {
7928
7928
  return result;
7929
7929
  },
7930
7930
  },
7931
+ command_stop_move_raw: {
7932
+ cluster: 'lightingColorCtrl',
7933
+ type: 'raw',
7934
+ convert: (model, msg, publish, options, meta) => {
7935
+ // commandStopMove without params
7936
+ if (msg.data[2] !== 71) return;
7937
+ if (hasAlreadyProcessedMessage(msg)) return;
7938
+ const movestop = 'stop';
7939
+ const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
7940
+ const payload = {action};
7941
+ addActionGroup(payload, msg, model);
7942
+ return payload;
7943
+ },
7944
+ },
7945
+ tuya_multi_action: {
7946
+ cluster: 'genOnOff',
7947
+ type: 'raw',
7948
+ convert: (model, msg, publish, options, meta) => {
7949
+ if (hasAlreadyProcessedMessage(msg, msg.data[2])) return;
7950
+ let action;
7951
+ if (msg.data[2] == 253) {
7952
+ action = {0: 'single', 1: 'double', 2: 'hold'}[msg.data[3]];
7953
+ } else if (msg.data[2] == 252) {
7954
+ action = {0: 'rotate_right', 1: 'rotate_left'}[msg.data[3]];
7955
+ }
7956
+ return {action};
7957
+ },
7958
+ },
7931
7959
  // #endregion
7932
7960
 
7933
7961
  // #region Ignore converters (these message dont need parsing).
@@ -8086,6 +8114,16 @@ const converters = {
8086
8114
  type: ['raw'],
8087
8115
  convert: (model, msg, publish, options, meta) => null,
8088
8116
  },
8117
+ ignore_metering: {
8118
+ cluster: 'seMetering',
8119
+ type: ['attributeReport', 'readResponse'],
8120
+ convert: (model, msg, publish, options, meta) => null,
8121
+ },
8122
+ ignore_electrical_measurement: {
8123
+ cluster: 'haElectricalMeasurement',
8124
+ type: ['attributeReport', 'readResponse'],
8125
+ convert: (model, msg, publish, options, meta) => null,
8126
+ },
8089
8127
  // #endregion
8090
8128
  };
8091
8129
 
@@ -6471,10 +6471,12 @@ const converters = {
6471
6471
  } else {
6472
6472
  throw new Error('Dimmer brightness is out of range 0..255');
6473
6473
  }
6474
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6475
- await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
6474
+ await tuya.sendDataPoints(entity, [
6475
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
6476
+ tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue),
6477
+ ], 'dataRequest', 1);
6476
6478
 
6477
- return {state: {white_brightness: value}};
6479
+ return {state: (key == 'white_brightness') ? {white_brightness: value} : {brightness: value}};
6478
6480
  } else if (key == 'color_temp') {
6479
6481
  const [colorTempMin, colorTempMax] = [250, 454];
6480
6482
  const preset = {
@@ -6496,8 +6498,10 @@ const converters = {
6496
6498
  }
6497
6499
  const data = utils.mapNumberRange(value, colorTempMax, colorTempMin, 0, 1000);
6498
6500
 
6499
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6500
- await tuya.sendDataPointValue(entity, tuya.dataPoints.silvercrestSetColorTemp, data);
6501
+ await tuya.sendDataPoints(entity, [
6502
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
6503
+ tuya.dpValueFromIntValue(tuya.dataPoints.silvercrestSetColorTemp, data),
6504
+ ], 'dataRequest', 1);
6501
6505
 
6502
6506
  return {state: {color_temp: value}};
6503
6507
  } else if (key == 'color' || (separateWhite && (key == 'brightness'))) {
@@ -6550,12 +6554,11 @@ const converters = {
6550
6554
  }
6551
6555
 
6552
6556
  // Scale 0-255 to 0-1000 what the device expects.
6553
- if (b) {
6557
+ if (b != null) {
6554
6558
  hsb.b = make4sizedString(utils.mapNumberRange(b, 0, 255, 0, 1000).toString(16));
6555
- } else if (state.brightness) {
6559
+ } else if (state.brightness != null) {
6556
6560
  hsb.b = make4sizedString(utils.mapNumberRange(state.brightness, 0, 255, 0, 1000).toString(16));
6557
6561
  }
6558
-
6559
6562
  return hsb;
6560
6563
  };
6561
6564
 
@@ -6572,15 +6575,18 @@ const converters = {
6572
6575
  data = data.concat(tuya.convertStringToHexArray(hsb.s));
6573
6576
  data = data.concat(tuya.convertStringToHexArray(hsb.b));
6574
6577
 
6575
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color);
6576
- await tuya.sendDataPointStringBuffer(entity, tuya.dataPoints.silvercrestSetColor, data);
6578
+ const commands = [
6579
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color),
6580
+ tuya.dpValueFromStringBuffer(tuya.dataPoints.silvercrestSetColor, data),
6581
+ ];
6577
6582
 
6578
6583
  if (separateWhite && meta.state.white_brightness != undefined) {
6579
6584
  // restore white state
6580
6585
  const newValue = utils.mapNumberRange(meta.state.white_brightness, 0, 255, 0, 1000);
6581
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6582
- await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
6586
+ commands.push(tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white));
6587
+ commands.push(tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue));
6583
6588
  }
6589
+ await tuya.sendDataPoints(entity, commands, 'dataRequest', 1);
6584
6590
 
6585
6591
  return {state: newState};
6586
6592
  }
package/devices/adeo.js CHANGED
@@ -6,6 +6,18 @@ const tz = require('../converters/toZigbee');
6
6
  const e = exposes.presets;
7
7
 
8
8
  module.exports = [
9
+ {
10
+ zigbeeModel: ['LDSENK01F'],
11
+ model: 'LDSENK01F',
12
+ vendor: 'ADEO',
13
+ description: '10A EU smart plug',
14
+ extend: extend.switch(),
15
+ configure: async (device, coordinatorEndpoint, logger) => {
16
+ const endpoint = device.getEndpoint(1);
17
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
18
+ await reporting.onOff(endpoint);
19
+ },
20
+ },
9
21
  {
10
22
  zigbeeModel: ['LXEK-5'],
11
23
  model: 'HR-C99C-Z-C045',
@@ -68,7 +68,7 @@ module.exports = [
68
68
  extend: extend.light_onoff_brightness_colortemp_color(),
69
69
  },
70
70
  {
71
- zigbeeModel: ['RGBBulb01UK', 'RGBBulb02UK'],
71
+ zigbeeModel: ['RGBBulb01UK', 'RGBBulb02UK', 'RGBBulb51AU'],
72
72
  model: 'AU-A1GSZ9RGBW_HV-GSCXZB269K',
73
73
  vendor: 'Aurora Lighting',
74
74
  description: 'AOne 9.5W smart RGBW GLS E27/B22',
@@ -10,14 +10,15 @@ module.exports = [
10
10
  model: 'V3-BTZB/V3-BTZBE',
11
11
  vendor: 'Danalock',
12
12
  description: 'BT/ZB smartlock',
13
- fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery],
14
- toZigbee: [tz.lock],
13
+ fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event, fz.lock_pin_code_response],
14
+ toZigbee: [tz.lock, tz.pincode_lock, tz.lock_userstatus],
15
+ meta: {pinCodeCount: 20},
15
16
  configure: async (device, coordinatorEndpoint, logger) => {
16
17
  const endpoint = device.getEndpoint(1);
17
18
  await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
18
19
  await reporting.lockState(endpoint);
19
20
  await reporting.batteryPercentageRemaining(endpoint);
20
21
  },
21
- exposes: [e.lock(), e.battery()],
22
+ exposes: [e.lock(), e.battery(), e.pincode()],
22
23
  },
23
24
  ];
@@ -29,6 +29,24 @@ const hueExtend = {
29
29
  };
30
30
 
31
31
  module.exports = [
32
+ {
33
+ zigbeeModel: ['LWA018'],
34
+ model: '9290024693',
35
+ vendor: 'Philips',
36
+ description: 'Hue white A60 bulb B22 1055lm with Bluetooth',
37
+ meta: {turnsOffAtBrightness1: true},
38
+ extend: extend.light_onoff_brightness(),
39
+ ota: ota.zigbeeOTA,
40
+ },
41
+ {
42
+ zigbeeModel: ['LCX004'],
43
+ model: '929002994901',
44
+ vendor: 'Philips',
45
+ description: 'Hue gradient lightstrip',
46
+ meta: {turnsOffAtBrightness1: true},
47
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
48
+ ota: ota.zigbeeOTA,
49
+ },
32
50
  {
33
51
  zigbeeModel: ['929003047501'],
34
52
  model: '929003047501',
@@ -911,7 +929,7 @@ module.exports = [
911
929
  vendor: 'Philips',
912
930
  description: 'Hue white ambiance E14 (with Bluetooth)',
913
931
  meta: {turnsOffAtBrightness1: true},
914
- extend: hueExtend.light_onoff_brightness_colortemp(),
932
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
915
933
  ota: ota.zigbeeOTA,
916
934
  },
917
935
  {
@@ -71,7 +71,8 @@ module.exports = [
71
71
  fromZigbee: [fz.battery, fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fz.command_recall,
72
72
  fz.command_move_hue, fz.command_move_to_color, fz.command_move_to_color_temp],
73
73
  exposes: [e.battery(), e.action(['on', 'off', 'brightness_step_up', 'brightness_step_down', 'brightness_move_up',
74
- 'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3'])],
74
+ 'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3', 'hue_move', 'color_temperature_move',
75
+ 'color_move', 'hue_stop'])],
75
76
  toZigbee: [],
76
77
  meta: {multiEndpoint: true, battery: {dontDividePercentage: true}},
77
78
  configure: async (device, coordinatorEndpoint) => {
@@ -5,7 +5,10 @@ const ea = exposes.access;
5
5
 
6
6
  module.exports = [
7
7
  {
8
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'}],
8
+ fingerprint: [
9
+ {modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'},
10
+ {modelID: 'TS0601', manufacturerName: '_TZE200_fcooykb4'},
11
+ ],
9
12
  model: 'WZ5_dim',
10
13
  vendor: 'Skydance',
11
14
  description: 'Zigbee & RF 5 in 1 LED controller (DIM mode)',
@@ -17,7 +20,10 @@ module.exports = [
17
20
  ],
18
21
  },
19
22
  {
20
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'}],
23
+ fingerprint: [
24
+ {modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'},
25
+ {modelID: 'TS0601', manufacturerName: '_TZE200_nthosjmx'},
26
+ ],
21
27
  model: 'WZ5_cct',
22
28
  vendor: 'Skydance',
23
29
  description: 'Zigbee & RF 5 in 1 LED controller (CCT mode)',
@@ -29,7 +35,10 @@ module.exports = [
29
35
  ],
30
36
  },
31
37
  {
32
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'}],
38
+ fingerprint: [
39
+ {modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'},
40
+ {modelID: 'TS0601', manufacturerName: '_TZE200_9mt3kgn0'},
41
+ ],
33
42
  model: 'WZ5_rgb',
34
43
  vendor: 'Skydance',
35
44
  description: 'Zigbee & RF 5 in 1 LED controller (RGB mode)',
@@ -41,7 +50,10 @@ module.exports = [
41
50
  ],
42
51
  },
43
52
  {
44
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'}],
53
+ fingerprint: [
54
+ {modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'},
55
+ {modelID: 'TS0601', manufacturerName: '_TZE200_g9jdneiu'},
56
+ ],
45
57
  model: 'WZ5_rgbw',
46
58
  vendor: 'Skydance',
47
59
  description: 'Zigbee & RF 5 in 1 LED controller (RGBW mode)',
@@ -56,7 +68,10 @@ module.exports = [
56
68
  meta: {separateWhite: true},
57
69
  },
58
70
  {
59
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'}],
71
+ fingerprint: [
72
+ {modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'},
73
+ {modelID: 'TS0601', manufacturerName: '_TZE200_aa9awrng'},
74
+ ],
60
75
  model: 'WZ5_rgbcct',
61
76
  vendor: 'Skydance',
62
77
  description: 'Zigbee & RF 5 in 1 LED controller (RGB+CCT mode)',
package/devices/tuya.js CHANGED
@@ -12,7 +12,7 @@ const utils = require('../lib/utils');
12
12
 
13
13
  const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
14
14
  '_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
15
- '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_v1pdxuqq', '_TZ3000_bfn1w0mm'];
15
+ '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_v1pdxuqq'];
16
16
 
17
17
  const tzLocal = {
18
18
  TS0504B_color: {
@@ -162,7 +162,8 @@ module.exports = [
162
162
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_0rn9qhnu'},
163
163
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
164
164
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
165
- {modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'}],
165
+ {modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
166
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'}],
166
167
  model: 'TS0505B',
167
168
  vendor: 'TuYa',
168
169
  description: 'Zigbee RGB+CCT light',
@@ -177,6 +178,7 @@ module.exports = [
177
178
  {
178
179
  fingerprint: [{modelID: 'TS0503B', manufacturerName: '_TZ3000_i8l0nqdu'},
179
180
  {modelID: 'TS0503B', manufacturerName: '_TZ3210_a5fxguxr'},
181
+ {modelID: 'TS0503B', manufacturerName: '_TZ3210_778drfdt'},
180
182
  {modelID: 'TS0503B', manufacturerName: '_TZ3000_g5xawfcq'}],
181
183
  model: 'TS0503B',
182
184
  vendor: 'TuYa',
@@ -187,7 +189,9 @@ module.exports = [
187
189
  },
188
190
  {
189
191
  fingerprint: [{modelID: 'TS0504B', manufacturerName: '_TZ3000_ukuvyhaa'},
190
- {modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'}, {modelID: 'TS0504B', manufacturerName: '_TZ3210_sroezl0s'}],
192
+ {modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'},
193
+ {modelID: 'TS0504B', manufacturerName: '_TZ3210_sroezl0s'},
194
+ {modelID: 'TS0504B', manufacturerName: '_TZ3210_1elppmba'}],
191
195
  model: 'TS0504B',
192
196
  vendor: 'TuYa',
193
197
  description: 'Zigbee RGBW light',
@@ -199,7 +203,8 @@ module.exports = [
199
203
  fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3000_4whigl8i'},
200
204
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
201
205
  {modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
202
- {modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'}],
206
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'},
207
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'}],
203
208
  model: 'TS0501B',
204
209
  description: 'Zigbee light',
205
210
  vendor: 'TuYa',
@@ -216,6 +221,7 @@ module.exports = [
216
221
  {modelID: 'TS0202', manufacturerName: '_TZ3000_kmh5qpmb'},
217
222
  {modelID: 'TS0202', manufacturerName: '_TYZB01_zwvaj5wy'},
218
223
  {modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
224
+ {modelID: 'TS0202', manufacturerName: '_TZ3000_bsvqrxru'},
219
225
  {modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
220
226
  {modelID: 'TS0202', manufacturerName: '_TYZB01_tv3wxhcz'},
221
227
  {modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
@@ -309,7 +315,8 @@ module.exports = [
309
315
  ],
310
316
  },
311
317
  {
312
- fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'}],
318
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'},
319
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_o1jzcxou'}],
313
320
  model: 'TS011F_socket_module',
314
321
  vendor: 'TuYa',
315
322
  description: 'Socket module',
@@ -901,7 +908,7 @@ module.exports = [
901
908
  'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
902
909
  'to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` ' +
903
910
  'instead setting the desired temperature.')
904
- .withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET)
911
+ .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
905
912
  .withAwayMode().withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco']),
906
913
  e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
907
914
  e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
@@ -1116,7 +1123,8 @@ module.exports = [
1116
1123
  {
1117
1124
  fingerprint: [
1118
1125
  {modelID: 'TS011F', manufacturerName: '_TZ3000_hyfvrar3'},
1119
- {modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'}],
1126
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
1127
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_bfn1w0mm'}],
1120
1128
  model: 'TS011F_plug_2',
1121
1129
  description: 'Smart plug (without power monitoring)',
1122
1130
  vendor: 'TuYa',
@@ -1831,9 +1839,29 @@ module.exports = [
1831
1839
  model: 'ERS-10TZBVK-AA',
1832
1840
  vendor: 'TuYa',
1833
1841
  description: 'Smart knob',
1834
- fromZigbee: [fz.command_step, fz.command_toggle, fz.command_move_hue],
1835
- toZigbee: [],
1836
- exposes: [e.action(['toggle', 'brightness_step_up', 'brightness_step_down'])],
1842
+ fromZigbee: [
1843
+ fz.command_step, fz.command_toggle, fz.command_move_hue, fz.command_step_color_temperature, fz.command_stop_move_raw,
1844
+ fz.tuya_multi_action, fz.tuya_operation_mode, fz.battery,
1845
+ ],
1846
+ toZigbee: [tz.tuya_operation_mode],
1847
+ exposes: [
1848
+ e.action([
1849
+ 'toggle', 'brightness_step_up', 'brightness_step_down', 'color_temperature_step_up', 'color_temperature_step_down',
1850
+ 'saturation_move', 'hue_move', 'hue_stop', 'single', 'double', 'hold', 'rotate_left', 'rotate_right',
1851
+ ]),
1852
+ exposes.numeric('action_step_size', ea.STATE).withValueMin(0).withValueMax(255),
1853
+ exposes.numeric('action_transition_time', ea.STATE).withUnit('s'),
1854
+ exposes.numeric('action_rate', ea.STATE).withValueMin(0).withValueMax(255),
1855
+ e.battery(),
1856
+ exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
1857
+ 'Operation mode: "command" - for group control, "event" - for clicks'),
1858
+ ],
1859
+ configure: async (device, coordinatorEndpoint, logger) => {
1860
+ const endpoint = device.getEndpoint(1);
1861
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
1862
+ await reporting.batteryPercentageRemaining(endpoint);
1863
+ await endpoint.read('genOnOff', ['tuyaOperationMode']);
1864
+ },
1837
1865
  },
1838
1866
  {
1839
1867
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kzm5w4iz'}],
package/devices/xiaomi.js CHANGED
@@ -1402,7 +1402,8 @@ module.exports = [
1402
1402
  model: 'SSM-U01',
1403
1403
  vendor: 'Xiaomi',
1404
1404
  description: 'Aqara single switch module T1 (with neutral)',
1405
- fromZigbee: [fz.on_off, fz.metering, fz.electrical_measurement, fz.device_temperature, fz.aqara_opple],
1405
+ // Ignore energy metering reports, rely on aqara_opple: https://github.com/Koenkk/zigbee2mqtt/issues/10709
1406
+ fromZigbee: [fz.on_off, fz.device_temperature, fz.aqara_opple, fz.ignore_metering, fz.ignore_electrical_measurement],
1406
1407
  exposes: [e.switch(), e.energy(), e.power(), e.device_temperature(), e.power_outage_memory(), e.switch_type()],
1407
1408
  toZigbee: [tz.xiaomi_switch_type, tz.on_off, tz.xiaomi_switch_power_outage_memory],
1408
1409
  configure: async (device, coordinatorEndpoint, logger) => {
package/lib/ota/common.js CHANGED
@@ -265,6 +265,11 @@ async function isNewImageAvailable(current, logger, device, getImageMeta) {
265
265
  const meta = await getImageMeta(current, logger, device);
266
266
  const [currentS, metaS] = [JSON.stringify(current), JSON.stringify(meta)];
267
267
  logger.debug(`Is new image available for '${device.ieeeAddr}', current '${currentS}', latest meta '${metaS}'`);
268
+
269
+ if (meta.force) {
270
+ return -1; // Negative number means the new firmware is 'newer' than current one
271
+ }
272
+
268
273
  return Math.sign(current.fileVersion - meta.fileVersion);
269
274
  }
270
275
 
@@ -411,7 +416,7 @@ async function updateToLatest(device, logger, onProgress, getNewImage, getImageM
411
416
  async function getNewImage(current, logger, device, getImageMeta, downloadImage) {
412
417
  const meta = await getImageMeta(current, logger, device);
413
418
  logger.debug(`getNewImage for '${device.ieeeAddr}', meta ${JSON.stringify(meta)}`);
414
- assert(meta.fileVersion > current.fileVersion, 'No new image available');
419
+ assert(meta.fileVersion > current.fileVersion || meta.force, 'No new image available');
415
420
 
416
421
  const download = downloadImage ? await downloadImage(meta, logger) :
417
422
  await getAxios().get(meta.url, {responseType: 'arraybuffer'});
@@ -4,8 +4,10 @@ const common = require('./common');
4
4
  const axios = common.getAxios();
5
5
  const fs = require('fs');
6
6
  const URI = require('uri-js');
7
+ const path = require('path');
7
8
 
8
- let overrideFileName = null;
9
+ let overrideIndexFileName = null;
10
+ let dataDir = null;
9
11
 
10
12
  /**
11
13
  * Helper functions
@@ -22,7 +24,7 @@ function isValidUrl(url) {
22
24
  return parsed.scheme === 'http' || parsed.scheme === 'https';
23
25
  }
24
26
 
25
- async function getFile(urlOrName) {
27
+ async function getIndexFile(urlOrName) {
26
28
  if (isValidUrl(urlOrName)) {
27
29
  return (await axios.get(urlOrName)).data;
28
30
  }
@@ -30,14 +32,33 @@ async function getFile(urlOrName) {
30
32
  return JSON.parse(fs.readFileSync(urlOrName));
31
33
  }
32
34
 
35
+ async function getFirmwareFile(image, logger) {
36
+ let urlOrName = image.url;
37
+
38
+ // First try to download firmware file with the URL provided
39
+ if (isValidUrl(urlOrName)) {
40
+ logger.debug(`ZigbeeOTA: downloading firmware image from ${urlOrName}`);
41
+ return await axios.get(urlOrName, {responseType: 'arraybuffer'});
42
+ }
43
+
44
+ // If the file name is not a full path, then treat it as a relative to the data directory
45
+ if (!path.isAbsolute(urlOrName) && dataDir) {
46
+ urlOrName = path.join(dataDir, urlOrName);
47
+ }
48
+
49
+ logger.debug(`ZigbeeOTA: getting local firmware file ${urlOrName}`);
50
+ return {data: fs.readFileSync(urlOrName)};
51
+ }
52
+
53
+
33
54
  async function getIndex(logger) {
34
55
  const index = (await axios.get(url)).data;
35
56
 
36
57
  logger.debug(`ZigbeeOTA: downloaded main index`);
37
58
 
38
- if (overrideFileName) {
39
- logger.debug(`ZigbeeOTA: Loading override index ${overrideFileName}`);
40
- const localIndex = await getFile(overrideFileName);
59
+ if (overrideIndexFileName) {
60
+ logger.debug(`ZigbeeOTA: Loading override index ${overrideIndexFileName}`);
61
+ const localIndex = await getIndexFile(overrideIndexFileName);
41
62
 
42
63
  // Resulting index will have overriden items first
43
64
  return localIndex.concat(index);
@@ -58,6 +79,7 @@ async function getImageMeta(current, logger, device) {
58
79
  // For this case additional identification through the modelId is done.
59
80
  // In the case of Tuya and Moes, additional identification is carried out through the manufacturerName.
60
81
  const image = images.find((i) => i.imageType === imageType && i.manufacturerCode === manufacturerCode &&
82
+ (!i.minFileVersion || current.fileVersion >= i.minFileVersion) && (!i.maxFileVersion || current.fileVersion <= i.maxFileVersion) &&
61
83
  (!i.modelId || i.modelId === modelId) && (!i.manufacturerName || i.manufacturerName.includes(manufacturerName)));
62
84
 
63
85
  assert(image !== undefined, `No image available for imageType '${imageType}'`);
@@ -66,6 +88,7 @@ async function getImageMeta(current, logger, device) {
66
88
  fileSize: image.fileSize,
67
89
  url: image.url,
68
90
  sha512: image.sha512,
91
+ force: image.force,
69
92
  };
70
93
  }
71
94
 
@@ -78,7 +101,7 @@ async function isUpdateAvailable(device, logger, requestPayload=null) {
78
101
  }
79
102
 
80
103
  async function updateToLatest(device, logger, onProgress) {
81
- return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta);
104
+ return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta, getFirmwareFile);
82
105
  }
83
106
 
84
107
  module.exports = {
@@ -86,6 +109,9 @@ module.exports = {
86
109
  isUpdateAvailable,
87
110
  updateToLatest,
88
111
  useIndexOverride: (indexFileName) => {
89
- overrideFileName = indexFileName;
112
+ overrideIndexFileName = indexFileName;
113
+ },
114
+ setDataDir: (dir) => {
115
+ dataDir = dir;
90
116
  },
91
117
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.378",
3
+ "version": "14.0.382",
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.378",
3
+ "version": "14.0.382",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [