zigbee-herdsman-converters 25.80.0 → 25.82.0

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/devices/aurora_lighting.d.ts.map +1 -1
  3. package/dist/devices/aurora_lighting.js +10 -0
  4. package/dist/devices/aurora_lighting.js.map +1 -1
  5. package/dist/devices/centralite.d.ts.map +1 -1
  6. package/dist/devices/centralite.js +5 -20
  7. package/dist/devices/centralite.js.map +1 -1
  8. package/dist/devices/iotperfect.d.ts.map +1 -1
  9. package/dist/devices/iotperfect.js +8 -1
  10. package/dist/devices/iotperfect.js.map +1 -1
  11. package/dist/devices/lightsolutions.d.ts.map +1 -1
  12. package/dist/devices/lightsolutions.js +1 -0
  13. package/dist/devices/lightsolutions.js.map +1 -1
  14. package/dist/devices/lumi.js +1 -1
  15. package/dist/devices/lumi.js.map +1 -1
  16. package/dist/devices/nous.d.ts.map +1 -1
  17. package/dist/devices/nous.js +14 -3
  18. package/dist/devices/nous.js.map +1 -1
  19. package/dist/devices/philips.d.ts.map +1 -1
  20. package/dist/devices/philips.js +37 -11
  21. package/dist/devices/philips.js.map +1 -1
  22. package/dist/devices/somfy.d.ts.map +1 -1
  23. package/dist/devices/somfy.js +7 -0
  24. package/dist/devices/somfy.js.map +1 -1
  25. package/dist/devices/sonoff.d.ts.map +1 -1
  26. package/dist/devices/sonoff.js +1 -0
  27. package/dist/devices/sonoff.js.map +1 -1
  28. package/dist/devices/tuya.d.ts.map +1 -1
  29. package/dist/devices/tuya.js +110 -57
  30. package/dist/devices/tuya.js.map +1 -1
  31. package/dist/devices/zemismart.js +1 -1
  32. package/dist/devices/zemismart.js.map +1 -1
  33. package/dist/index.js +2 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/lib/tuya.d.ts +12 -0
  36. package/dist/lib/tuya.d.ts.map +1 -1
  37. package/dist/lib/tuya.js +91 -0
  38. package/dist/lib/tuya.js.map +1 -1
  39. package/dist/lib/types.d.ts +2 -2
  40. package/dist/lib/types.d.ts.map +1 -1
  41. package/dist/models-index.json +1 -1
  42. package/package.json +1 -1
@@ -184,6 +184,17 @@ const storeLocal = {
184
184
  this[`power_factor_${channel}`] = 100;
185
185
  this.flush(result, channel, options);
186
186
  },
187
+ // Some times the device sends a single zero value (either power or current).
188
+ // This is most likely a glitch. We flush all values but set them to null
189
+ // to indicate that they are not valid.
190
+ //
191
+ flushNull: function (result, channel, options) {
192
+ this[`sign_${channel}`] = null;
193
+ this[`power_${channel}`] = null;
194
+ this[`current_${channel}`] = null;
195
+ this[`power_factor_${channel}`] = null;
196
+ this.flush(result, channel, options);
197
+ },
187
198
  clear: () => {
188
199
  priv.sign_a = null;
189
200
  priv.sign_b = null;
@@ -193,6 +204,11 @@ const storeLocal = {
193
204
  priv.current_b = null;
194
205
  priv.power_factor_a = null;
195
206
  priv.power_factor_b = null;
207
+ // Used to detect single zero values
208
+ priv.zero_power_a = null;
209
+ priv.zero_power_b = null;
210
+ priv.zero_current_a = null;
211
+ priv.zero_current_b = null;
196
212
  },
197
213
  };
198
214
  globalStore.putValue(device, "private_state", priv);
@@ -224,8 +240,19 @@ const convLocal = {
224
240
  priv[`power_${channel}`] = v / 10;
225
241
  priv[`timestamp_${channel}`] = new Date().toISOString();
226
242
  if (v === 0) {
227
- priv.flushZero(result, channel, options);
228
- return result;
243
+ const singleZeroRemoveKey = "single_zero_remove";
244
+ const singleZeroRemove = options[singleZeroRemoveKey] != null ? options[singleZeroRemoveKey] : false;
245
+ if (singleZeroRemove && !priv[`zero_power_${channel}`]) {
246
+ logger_1.logger.info("[PJ1203A] power is zero, flushing one time", NS);
247
+ priv.flushNull(result, channel, options);
248
+ }
249
+ else {
250
+ priv.flushZero(result, channel, options);
251
+ }
252
+ priv[`zero_power_${channel}`] = true;
253
+ }
254
+ else {
255
+ priv[`zero_power_${channel}`] = false;
229
256
  }
230
257
  return result;
231
258
  },
@@ -238,8 +265,19 @@ const convLocal = {
238
265
  const result = {};
239
266
  priv[`current_${channel}`] = v / 1000;
240
267
  if (v === 0) {
241
- priv.flushZero(result, channel, options);
242
- return result;
268
+ const singleZeroRemoveKey = "single_zero_remove";
269
+ const singleZeroRemove = options[singleZeroRemoveKey] != null ? options[singleZeroRemoveKey] : false;
270
+ if (singleZeroRemove && !priv[`zero_current_${channel}`]) {
271
+ logger_1.logger.info("[PJ1203A] current is zero, flushing one time", NS);
272
+ priv.flushNull(result, channel, options);
273
+ }
274
+ else {
275
+ priv.flushZero(result, channel, options);
276
+ }
277
+ priv[`zero_current_${channel}`] = true;
278
+ }
279
+ else {
280
+ priv[`zero_current_${channel}`] = false;
243
281
  }
244
282
  return result;
245
283
  },
@@ -755,7 +793,7 @@ const tzLocal = {
755
793
  const lookup = { red_when_on: 0, pink_when_on: 1, red_on_blue_off: 2, pink_on_blue_off: 3 };
756
794
  const modeValue = utils.getFromLookup(value, lookup);
757
795
  await entity.write("genOnOff", { tuyaBacklightMode: modeValue });
758
- return { state: { backlight_mode: utils.getFromLookup(modeValue, lookup) } };
796
+ return { state: { backlight_mode: value } };
759
797
  },
760
798
  },
761
799
  };
@@ -828,7 +866,7 @@ const fzLocal = {
828
866
  TS0201_humidity: {
829
867
  ...fz.humidity,
830
868
  convert: (model, msg, publish, options, meta) => {
831
- if (["_TZ3210_ncw88jfq", "_TZ3000_ywagc4rj", "_TZ3000_isw9u95y"].includes(meta.device.manufacturerName)) {
869
+ if (["_TZ3210_ncw88jfq", "_TZ3000_ywagc4rj", "_TZ3000_isw9u95y", "_TZ3000_yupc0pb7"].includes(meta.device.manufacturerName)) {
832
870
  msg.data.measuredValue *= 10;
833
871
  }
834
872
  return fz.humidity.convert(model, msg, publish, options, meta);
@@ -2290,11 +2328,10 @@ exports.definitions = [
2290
2328
  },
2291
2329
  },
2292
2330
  {
2293
- // Tuya/Senoro window sensor variant with 3-state opening on DP101.
2331
+ // Senoro window sensor variant with 3-state opening on DP101.
2294
2332
  fingerprint: tuya.fingerprint("TS0601", ["_TZE284_6teua268"]),
2295
- model: "TZE284_6teua268",
2296
- vendor: "Tuya",
2297
- whiteLabel: [{ vendor: "Senoro", model: "Senoro.Win v2" }],
2333
+ model: "Senoro.Win v2",
2334
+ vendor: "Senoro",
2298
2335
  description: "Window sensor with 3-state opening (DP101), optional alarm, battery",
2299
2336
  extend: [tuya.modernExtend.tuyaBase({ dp: true })],
2300
2337
  exposes: [
@@ -2977,9 +3014,9 @@ exports.definitions = [
2977
3014
  fromZigbee: [tuya.fz.datapoints],
2978
3015
  extend: [m.iasZoneAlarm({ zoneType: "rain", zoneAttributes: ["alarm_1"] }), m.battery({ percentageReporting: true })],
2979
3016
  exposes: [
2980
- e.illuminance().withUnit("lx"),
2981
- e.numeric("illuminance_average_20min", ea.STATE).withUnit("lx").withDescription("Illuminance average for the last 20 minutes"),
2982
- e.numeric("illuminance_maximum_today", ea.STATE).withUnit("lx").withDescription("Illuminance maximum for the last 24 hours"),
3017
+ e.illuminance().withUnit("mV"),
3018
+ e.numeric("illuminance_average_20min", ea.STATE).withUnit("mV").withDescription("Illuminance average for the last 20 minutes"),
3019
+ e.numeric("illuminance_maximum_today", ea.STATE).withUnit("mV").withDescription("Illuminance maximum for the last 24 hours"),
2983
3020
  e.binary("cleaning_reminder", ea.STATE, true, false).withDescription("Cleaning reminder"),
2984
3021
  e.numeric("rain_intensity", ea.STATE).withUnit("mV").withDescription("Rainfall intensity"),
2985
3022
  ],
@@ -4094,7 +4131,7 @@ exports.definitions = [
4094
4131
  },
4095
4132
  },
4096
4133
  {
4097
- fingerprint: tuya.fingerprint("TS0601", ["_TZE204_2imwyigp", "_TZE200_2imwyigp"]),
4134
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE204_2imwyigp", "_TZE200_2imwyigp", "_TZE200_go3tvswy"]),
4098
4135
  model: "MG-ZG03W",
4099
4136
  vendor: "Tuya",
4100
4137
  description: "3 gang switch",
@@ -4117,7 +4154,7 @@ exports.definitions = [
4117
4154
  },
4118
4155
  },
4119
4156
  {
4120
- fingerprint: tuya.fingerprint("TS0601", ["_TZE200_go3tvswy", "_TZE200_oyti2ums"]),
4157
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE200_oyti2ums"]),
4121
4158
  model: "MG-GPO04ZSLP",
4122
4159
  vendor: "Tuya",
4123
4160
  description: "2 x socket + 1 x light with master switch and metering",
@@ -4339,7 +4376,7 @@ exports.definitions = [
4339
4376
  tuya.whitelabel("Danfoss", "014G2480", "Temperature and humidity sensor", ["_TZ3000_mxzo5rhf"]),
4340
4377
  tuya.whitelabel("Tuya", "HS09", "Hanging temperature humidity sensor", ["_TZ3000_1twfmkcc"]),
4341
4378
  tuya.whitelabel("Nedis", "ZBSC10WT", "Temperature and humidity sensor", ["_TZ3000_fie1dpkm"]),
4342
- tuya.whitelabel("Tuya", "TH09Z", "Temperature and humidity sensor", ["_TZ3000_isw9u95y"]),
4379
+ tuya.whitelabel("Tuya", "TH09Z", "Temperature and humidity sensor", ["_TZ3000_isw9u95y", "_TZ3000_yupc0pb7"]),
4343
4380
  ],
4344
4381
  },
4345
4382
  {
@@ -7556,35 +7593,41 @@ exports.definitions = [
7556
7593
  exposes: [
7557
7594
  e.battery(),
7558
7595
  e.child_lock(),
7559
- e.window_detection(),
7560
- e.binary("window", ea.STATE, "OPEN", "CLOSE").withDescription("Window status closed or open "),
7561
- e.enum("mode", ea.STATE_SET, ["auto", "manual"]).withDescription("Mode"),
7562
- e.binary("holiday_mode", ea.STATE_SET, "ON", "OFF"),
7563
- e.binary("heating_stop", ea.STATE_SET, "ON", "OFF"),
7596
+ e.window_detection_bool(),
7597
+ e.window_open(),
7564
7598
  e
7565
7599
  .climate()
7566
- .withLocalTemperature(ea.STATE)
7567
7600
  .withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
7568
- .withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET),
7569
- e.comfort_temperature().withValueMin(5).withValueMax(30).withDescription("Comfort mode temperature"),
7570
- e.eco_temperature().withValueMin(5).withValueMax(30).withDescription("Eco mode temperature"),
7571
- e.enum("screen_orientation", ea.STATE_SET, ["up", "right", "down", "left"]).withDescription("Screen orientation"),
7572
- tuya.exposes.frostProtection(),
7601
+ .withLocalTemperature(ea.STATE) // local_temperature
7602
+ .withLocalTemperatureCalibration(-7, 7, 0.5, ea.STATE_SET) // local_temperature_calibration
7603
+ .withSystemMode(["auto", "off"], ea.STATE_SET) // system_mode
7604
+ .withPreset(["schedule", "manual", "holiday"]), //preset
7605
+ e.comfort_temperature().withValueMin(15).withValueMax(35),
7606
+ e.eco_temperature().withValueMin(5).withValueMax(22),
7607
+ e.holiday_temperature().withValueMin(5).withValueMax(35),
7608
+ e.text("holiday_time", ea.STATE_SET).withDescription("Holiday start and end time in format YYYY/MM/DD HH:MM | YYYY/MM/DD HH:MM"),
7573
7609
  e.binary("boost_heating", ea.STATE_SET, "ON", "OFF"),
7574
- e.numeric("boost_time", ea.STATE_SET).withUnit("min").withDescription("Countdown in minutes").withValueMin(0).withValueMax(1000),
7610
+ e.numeric("boost_time", ea.STATE_SET).withUnit("min").withDescription("Countdown in minutes").withValueMin(0).withValueMax(30),
7611
+ e
7612
+ .binary("frost_protection", ea.STATE_SET, "ON", "OFF")
7613
+ .withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
7614
+ ...["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"].map((day) => e.text(`schedule_${day}`, ea.STATE_SET).withDescription("Schedule in 8 segments format: HH:MM/TT.T HH:MM/TT.T ...")),
7615
+ e.enum("screen_orientation", ea.STATE_SET, ["up", "right", "down", "left"]).withDescription("Screen orientation"),
7575
7616
  e.numeric("fault_code", ea.STATE).withDescription("Raw fault code"),
7576
7617
  ],
7577
7618
  meta: {
7578
7619
  tuyaDatapoints: [
7579
7620
  [
7580
7621
  2,
7581
- "mode",
7622
+ "preset",
7582
7623
  tuya.valueConverterBasic.lookup({
7583
- auto: tuya.enum(0),
7624
+ schedule: tuya.enum(0),
7625
+ holiday: tuya.enum(1), // only possible to set during holiday_time
7584
7626
  manual: tuya.enum(2),
7585
7627
  }),
7586
7628
  ],
7587
- [4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
7629
+ // when system_mode is 'off', current_heating_setpoint is set to -5000... hence limits
7630
+ [4, "current_heating_setpoint", tuya.valueConverterBasic.divideByWithLimits(10, 0, 35)],
7588
7631
  [5, "local_temperature", tuya.valueConverter.divideBy10],
7589
7632
  [6, "battery", tuya.valueConverter.raw],
7590
7633
  [
@@ -7595,29 +7638,23 @@ exports.definitions = [
7595
7638
  UNLOCK: false,
7596
7639
  }),
7597
7640
  ],
7598
- [14, "window_detection", tuya.valueConverter.onOff],
7599
- [
7600
- 15,
7601
- "window",
7602
- tuya.valueConverterBasic.lookup({
7603
- CLOSE: tuya.enum(0),
7604
- OPEN: tuya.enum(1),
7605
- }),
7606
- ],
7641
+ [14, "window_detection", tuya.valueConverter.raw],
7642
+ [15, "window_open", tuya.valueConverter.trueFalseEnum1],
7607
7643
  [21, "holiday_temperature", tuya.valueConverter.divideBy10],
7608
7644
  [36, "frost_protection", tuya.valueConverter.onOff],
7609
- [39, "switch_scale", tuya.valueConverter.raw],
7610
- [47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
7645
+ [39, "anti_scale", tuya.valueConverter.raw],
7646
+ [47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1], // duplicate/legacy
7647
+ [49, "valve_status", tuya.valueConverter.raw],
7611
7648
  [101, "boost_heating", tuya.valueConverter.onOff],
7612
7649
  [102, "boost_time", tuya.valueConverter.countdown],
7613
- [103, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(1)],
7614
- [104, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(2)],
7615
- [105, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(3)],
7616
- [106, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(4)],
7617
- [107, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(5)],
7618
- [108, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(6)],
7619
- [109, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV602Z_WithDayNumber(7)],
7620
- [110, "holiday_mode", tuya.valueConverter.onOff],
7650
+ [103, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7651
+ [104, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7652
+ [105, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7653
+ [106, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7654
+ [107, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7655
+ [108, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7656
+ [109, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDP_TRV603WZ],
7657
+ [110, "holiday_time", tuya.valueConverter.thermostatHolidayStartStopUnixTS],
7621
7658
  [
7622
7659
  111,
7623
7660
  "screen_orientation",
@@ -7629,7 +7666,14 @@ exports.definitions = [
7629
7666
  }),
7630
7667
  ],
7631
7668
  [112, "antifrost_temperature", tuya.valueConverter.divideBy10],
7632
- [113, "heating_stop", tuya.valueConverter.onOff],
7669
+ [
7670
+ 113,
7671
+ "system_mode",
7672
+ tuya.valueConverterBasic.lookup({
7673
+ auto: false,
7674
+ off: true,
7675
+ }),
7676
+ ],
7633
7677
  [114, "local_temperature_calibration", tuya.valueConverter.localTempCalibration1],
7634
7678
  [115, "programming_mode", tuya.valueConverter.raw],
7635
7679
  [116, "eco_temperature", tuya.valueConverter.divideBy10],
@@ -9248,7 +9292,7 @@ exports.definitions = [
9248
9292
  },
9249
9293
  },
9250
9294
  {
9251
- fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_wsspgtcd", "_TZ3000_s678wazd", "_TZ3002_pzao9ls1"]),
9295
+ fingerprint: tuya.fingerprint("TS0726", ["_TZ3000_wsspgtcd", "_TZ3000_s678wazd", "_TZ3002_pzao9ls1", "_TZ3000_kfkqkjqe"]),
9252
9296
  model: "TS0726_4_gang",
9253
9297
  vendor: "Tuya",
9254
9298
  description: "4 gang switch with neutral wire",
@@ -9764,7 +9808,9 @@ exports.definitions = [
9764
9808
  model: "ZWT198/ZWT100-BH",
9765
9809
  vendor: "Tuya",
9766
9810
  description: "Wall thermostat",
9767
- extend: [tuya.modernExtend.tuyaBase({ dp: true, respondToMcuVersionResponse: true, timeStart: "1970" })],
9811
+ // Don't enable mcuVersionResponse
9812
+ // https://github.com/Koenkk/zigbee2mqtt/issues/28455#issuecomment-3603696676
9813
+ extend: [tuya.modernExtend.tuyaBase({ dp: true, timeStart: "1970" })],
9768
9814
  whiteLabel: [tuya.whitelabel("AVATTO", "WT-100-BH", "Wall thermostat", ["_TZE204_gops3slb", "_TZE284_gops3slb"])],
9769
9815
  exposes: [
9770
9816
  e.binary("factory_reset", ea.STATE_SET, "ON", "OFF").withDescription("Full factory reset, use with caution!"),
@@ -11838,11 +11884,15 @@ exports.definitions = [
11838
11884
  model: "ZG-204ZM",
11839
11885
  vendor: "Tuya",
11840
11886
  description: "PIR 24Ghz human presence sensor",
11841
- extend: [tuya.modernExtend.tuyaBase({ dp: true })],
11887
+ extend: [
11888
+ tuya.modernExtend.tuyaBase({ dp: true }),
11889
+ // Besides dp, also uses standard illuminance cluster
11890
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/10897
11891
+ m.illuminance({ reporting: false }),
11892
+ ],
11842
11893
  exposes: [
11843
11894
  e.presence(),
11844
11895
  e.enum("motion_state", ea.STATE, ["none", "large", "small", "static"]).withDescription("Motion state"),
11845
- e.illuminance(),
11846
11896
  e.battery(),
11847
11897
  e
11848
11898
  .numeric("fading_time", ea.STATE_SET)
@@ -13784,7 +13834,7 @@ exports.definitions = [
13784
13834
  ],
13785
13835
  },
13786
13836
  {
13787
- fingerprint: tuya.fingerprint("TS0001", ["_TZ3210_dse8ogfy", "_TZ3210_j4pdtz9v", "_TZ3210_7vgttna6", "_TZ3210_a04acm9s"]),
13837
+ fingerprint: tuya.fingerprint("TS0001", ["_TZ3210_dse8ogfy", "_TZ3210_j4pdtz9v", "_TZ3210_7vgttna6", "_TZ3210_a04acm9s", "_TZ3210_cm9mbpr1"]),
13788
13838
  model: "TS0001_fingerbot",
13789
13839
  vendor: "Tuya",
13790
13840
  description: "Zigbee fingerbot plus",
@@ -15012,6 +15062,9 @@ exports.definitions = [
15012
15062
  .withDescription("Report energy flow direction for channel B using signed power (default false)."),
15013
15063
  e.binary("invert_energy_flow_a", ea.SET, true, false).withDescription("Report energy flow direction inverted for channel A."),
15014
15064
  e.binary("invert_energy_flow_b", ea.SET, true, false).withDescription("Report energy flow direction inverted for channel B."),
15065
+ e
15066
+ .binary("single_zero_remove", ea.SET, true, false)
15067
+ .withDescription("If true then single-zero power or current values will be disgarded. The default is false."),
15015
15068
  ],
15016
15069
  exposes: [
15017
15070
  e.ac_frequency(),
@@ -21125,7 +21178,7 @@ exports.definitions = [
21125
21178
  fingerprint: tuya.fingerprint("TS0601", ["_TZE284_iwyqtclw"]),
21126
21179
  model: "M9Pro",
21127
21180
  vendor: "Tuya",
21128
- description: "Smart 4 gang switch, curtain, smart light or scene. 1x thermosat control",
21181
+ description: "Smart 4 gang switch, curtain, smart light or scene. 1x thermostat control",
21129
21182
  exposes: [
21130
21183
  ...[1, 2, 3, 4].map((i) => e.switch().withEndpoint(`l${i}`).setAccess("state", ea.STATE_SET)),
21131
21184
  ...[1, 2, 3].map((i) => e.enum("mode", ea.STATE_SET, ["switch", "scene", "smart_light", "curtain"]).withEndpoint(`l${i}`).withDescription(`Switch ${i} mode`)),