zigbee-herdsman-converters 25.104.0 → 25.106.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 (69) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/converters/actions.d.ts.map +1 -1
  3. package/dist/converters/actions.js +0 -2
  4. package/dist/converters/actions.js.map +1 -1
  5. package/dist/devices/engo.d.ts.map +1 -1
  6. package/dist/devices/engo.js +179 -0
  7. package/dist/devices/engo.js.map +1 -1
  8. package/dist/devices/envilar.js +1 -1
  9. package/dist/devices/heiman.d.ts.map +1 -1
  10. package/dist/devices/heiman.js +94 -23
  11. package/dist/devices/heiman.js.map +1 -1
  12. package/dist/devices/istar.d.ts.map +1 -1
  13. package/dist/devices/istar.js +7 -0
  14. package/dist/devices/istar.js.map +1 -1
  15. package/dist/devices/ledvance.d.ts.map +1 -1
  16. package/dist/devices/ledvance.js +7 -0
  17. package/dist/devices/ledvance.js.map +1 -1
  18. package/dist/devices/lumi.d.ts.map +1 -1
  19. package/dist/devices/lumi.js +3 -1
  20. package/dist/devices/lumi.js.map +1 -1
  21. package/dist/devices/moes.js +1 -1
  22. package/dist/devices/moes.js.map +1 -1
  23. package/dist/devices/namron.d.ts.map +1 -1
  24. package/dist/devices/namron.js +9 -0
  25. package/dist/devices/namron.js.map +1 -1
  26. package/dist/devices/niko.d.ts.map +1 -1
  27. package/dist/devices/niko.js +8 -4
  28. package/dist/devices/niko.js.map +1 -1
  29. package/dist/devices/nous.js +2 -2
  30. package/dist/devices/nous.js.map +1 -1
  31. package/dist/devices/schneider_electric.d.ts.map +1 -1
  32. package/dist/devices/schneider_electric.js +66 -36
  33. package/dist/devices/schneider_electric.js.map +1 -1
  34. package/dist/devices/shelly.d.ts.map +1 -1
  35. package/dist/devices/shelly.js +21 -0
  36. package/dist/devices/shelly.js.map +1 -1
  37. package/dist/devices/sinope.js +1 -1
  38. package/dist/devices/sinope.js.map +1 -1
  39. package/dist/devices/siterwell.d.ts.map +1 -1
  40. package/dist/devices/siterwell.js +1 -0
  41. package/dist/devices/siterwell.js.map +1 -1
  42. package/dist/devices/sonoff.d.ts.map +1 -1
  43. package/dist/devices/sonoff.js +1 -0
  44. package/dist/devices/sonoff.js.map +1 -1
  45. package/dist/devices/sunricher.d.ts.map +1 -1
  46. package/dist/devices/sunricher.js +31 -84
  47. package/dist/devices/sunricher.js.map +1 -1
  48. package/dist/devices/third_reality.js +3 -3
  49. package/dist/devices/third_reality.js.map +1 -1
  50. package/dist/devices/tuya.d.ts.map +1 -1
  51. package/dist/devices/tuya.js +300 -92
  52. package/dist/devices/tuya.js.map +1 -1
  53. package/dist/lib/exposes.d.ts.map +1 -1
  54. package/dist/lib/exposes.js +1 -1
  55. package/dist/lib/exposes.js.map +1 -1
  56. package/dist/lib/generateDefinition.js +367 -14
  57. package/dist/lib/generateDefinition.js.map +1 -1
  58. package/dist/lib/modernExtend.d.ts +4 -0
  59. package/dist/lib/modernExtend.d.ts.map +1 -1
  60. package/dist/lib/modernExtend.js +26 -3
  61. package/dist/lib/modernExtend.js.map +1 -1
  62. package/dist/lib/ota.d.ts.map +1 -1
  63. package/dist/lib/ota.js +7 -1
  64. package/dist/lib/ota.js.map +1 -1
  65. package/dist/lib/ubisys.d.ts.map +1 -1
  66. package/dist/lib/ubisys.js +2 -2
  67. package/dist/lib/ubisys.js.map +1 -1
  68. package/dist/models-index.json +1 -1
  69. package/package.json +3 -3
@@ -3009,7 +3009,7 @@ exports.definitions = [
3009
3009
  ]),
3010
3010
  tuya.whitelabel("MiBoxer", "E3-ZR", "3 in 1 LED Controller", ["_TZB210_wy1pyu1q", "_TZB210_yatkpuha"]),
3011
3011
  tuya.whitelabel("MiBoxer", "SZ5", "5 in 1 LED Controller", ["_TZB210_w9hcix2r"]),
3012
- tuya.whitelabel("MiBoxer", "FUT037Z+", "RGB led controller", ["_TZB210_417ikxay", "_TZB210_wxazcmsh"]),
3012
+ tuya.whitelabel("MiBoxer", "FUT037Z+", "RGB led controller", ["_TZB210_417ikxay", "_TZB210_wxazcmsh", "_TZB210_u3ri0968"]),
3013
3013
  tuya.whitelabel("MiBoxer", "FUT039Z", "RGB+CCT LED controller", ["_TZ3210_jicmoite", "_TZB210_rs0ufzwg"]),
3014
3014
  tuya.whitelabel("MiBoxer", "FUT066Z", "RGB+CCT LED Downlight", ["_TZ3210_zrvxvydd"]),
3015
3015
  tuya.whitelabel("MiBoxer", "FUT068ZR", "RGB+CCT LED Downlight", ["_TZB210_endmggws"]),
@@ -4311,6 +4311,33 @@ exports.definitions = [
4311
4311
  ],
4312
4312
  },
4313
4313
  },
4314
+ {
4315
+ fingerprint: tuya.fingerprint("TS0301", ["_TZE210_inpjmc0h"]),
4316
+ model: "TS0301_dual_rail",
4317
+ vendor: "Tuya",
4318
+ description: "Top-down bottom-up dual motor shade",
4319
+ extend: [tuya.modernExtend.tuyaBase({ dp: true }), m.deviceEndpoints({ endpoints: { bottom: 1, top: 1 } })],
4320
+ exposes: [
4321
+ e.cover_position().withEndpoint("bottom").withDescription("Bottom rail"),
4322
+ e.cover_position().withEndpoint("top").withDescription("Top rail"),
4323
+ e.battery(),
4324
+ ],
4325
+ meta: {
4326
+ tuyaDatapoints: [
4327
+ // Bottom rail - DP109 is control, DP101 is set position, DP102 is current position
4328
+ [109, "state_bottom", tuya.valueConverterBasic.lookup({ OPEN: tuya.enum(0), CLOSE: tuya.enum(1), STOP: tuya.enum(2) })],
4329
+ [101, "position_bottom", tuya.valueConverter.coverPositionInverted],
4330
+ [102, "position_bottom", tuya.valueConverter.coverPositionInverted],
4331
+ // Top rail - DP1 is control, DP2 is set position, DP3 is current position
4332
+ // Note: State commands are reversed for Home Assistant compatibility with top-down operation
4333
+ [1, "state_top", tuya.valueConverterBasic.lookup({ OPEN: tuya.enum(1), CLOSE: tuya.enum(0), STOP: tuya.enum(2) })],
4334
+ [2, "position_top", tuya.valueConverter.coverPosition],
4335
+ [3, "position_top", tuya.valueConverter.coverPosition],
4336
+ // Battery
4337
+ [13, "battery", tuya.valueConverter.raw],
4338
+ ],
4339
+ },
4340
+ },
4314
4341
  {
4315
4342
  fingerprint: tuya.fingerprint("TS0601", [
4316
4343
  "_TZE200_aqnazj70",
@@ -5210,24 +5237,30 @@ exports.definitions = [
5210
5237
  },
5211
5238
  {
5212
5239
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_dzuqwsyg", "_TZE204_dzuqwsyg"]),
5213
- model: "BAC-003",
5240
+ model: "BAC-002-ALZB",
5214
5241
  vendor: "Tuya",
5215
5242
  description: "FCU thermostat temperature controller",
5216
5243
  extend: [tuya.modernExtend.tuyaBase({ dp: true, forceTimeUpdates: true, timeStart: "1970" })],
5217
5244
  options: [
5218
5245
  e
5219
- .enum("control_sequence_of_operation", ea.SET, ["cooling_only", "cooling_and_heating_4-pipes"])
5220
- .withDescription("Operating environment of the thermostat"),
5221
- e.binary("expose_device_state", ea.SET, true, false).withDescription("Expose device power state as a separate property when enabled."),
5246
+ .enum("control_sequence_of_operation", ea.SET, ["cooling_only", "cooling_and_heating"])
5247
+ .withLabel("Device Configuration")
5248
+ .withDescription("Report either cooling and fan or cooling, heating and fan capability."),
5249
+ e
5250
+ .binary("expose_device_state", ea.SET, true, false)
5251
+ .withLabel("Expose device switch")
5252
+ .withDescription("Expose a separate on/off switch, instead of including it in system mode."),
5253
+ e
5254
+ .binary("wake_before_power_transition", ea.SET, true, false)
5255
+ .withLabel("Wake before Power Transition")
5256
+ .withDescription("Send a wake-up command before turning the device on or/off, required for some firmware revisions."),
5222
5257
  ],
5223
5258
  exposes: (device, options) => {
5224
5259
  const system_modes = ["off", "cool", "heat", "fan_only"];
5225
- // Device can operate either in 2-pipe or 4-pipe configuration
5226
- // For 2-pipe configurations remove 'heat' mode
5227
- switch (options?.control_sequence_of_operation) {
5228
- case "cooling_only":
5229
- system_modes.splice(2, 1);
5230
- break;
5260
+ // Device can operate either in cooling or heating/cooling configuration
5261
+ // For cooling only configurations remove 'heat' mode
5262
+ if (options.control_sequence_of_operation === "cooling_only") {
5263
+ system_modes.splice(2, 1);
5231
5264
  }
5232
5265
  const exposes = [
5233
5266
  e
@@ -5237,25 +5270,19 @@ exports.definitions = [
5237
5270
  .withFanMode(["low", "medium", "high", "auto"], ea.STATE_SET)
5238
5271
  .withSetpoint("current_heating_setpoint", 5, 35, 1, ea.STATE_SET)
5239
5272
  .withPreset(["auto", "manual"])
5240
- .withLocalTemperatureCalibration(-3, 3, 1, ea.STATE_SET),
5273
+ .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
5241
5274
  e.child_lock(),
5242
- e
5243
- .composite("schedule", "schedule", ea.STATE_SET)
5244
- .withFeature(e.text("weekdays", ea.SET).withDescription('Schedule (1-5), 4 periods in format "hh:mm/tt".'))
5245
- .withFeature(e.text("saturday", ea.SET).withDescription('Schedule (6), 4 periods in format "hh:mm/tt".'))
5246
- .withFeature(e.text("sunday", ea.SET).withDescription('Schedule (7), 4 periods in format "hh:mm/tt".'))
5247
- .withDescription('Auto-mode schedule, 4 periods each per category. Example: "06:00/20 11:30/21 13:30/22 17:30/23.5".'),
5248
- e.max_temperature().withValueMin(35).withValueMax(45).withPreset("default", 35, "Default value"),
5249
- e
5250
- .numeric("deadzone_temperature", ea.STATE_SET)
5251
- .withUnit("°C")
5252
- .withValueMax(5)
5253
- .withValueMin(1)
5254
- .withValueStep(1)
5255
- .withPreset("default", 1, "Default value")
5256
- .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity"),
5275
+ e.max_temperature().withValueMin(35).withValueMax(45),
5276
+ e.numeric("deadzone_temperature", ea.STATE_SET).withUnit("°C").withValueMax(5).withValueMin(0),
5277
+ e.text("schedule_text", ea.STATE_SET).withDescription(`Weekly schedule in the format "HH:MM/TT HH:MM/TT ...".
5278
+ Example for 12 segments:
5279
+ "06:00/20 11:30/21 13:30/22 17:30/23 06:00/24 12:00/23 14:30/22 17:30/21 06:00/19 12:30/20 14:30/21 18:30/20".
5280
+ Each segment contains:
5281
+ - HH:MM: Time in 24-hour format.
5282
+ - TT: Temperature in °C.
5283
+ Ensure all 12 segments are defined and separated by spaces.`),
5257
5284
  ];
5258
- if (options?.expose_device_state === true) {
5285
+ if (options.expose_device_state === true) {
5259
5286
  exposes.unshift(e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("Turn the thermostat ON or OFF"));
5260
5287
  }
5261
5288
  return exposes;
@@ -5268,15 +5295,14 @@ exports.definitions = [
5268
5295
  "state",
5269
5296
  {
5270
5297
  to: async (v, meta) => {
5271
- if (meta.options?.expose_device_state === true) {
5298
+ if (meta.options.expose_device_state === true) {
5272
5299
  await tuya.sendDataPointBool(meta.device.endpoints[0], 1, utils.getFromLookup(v, { on: true, off: false }), "dataRequest", 1);
5273
5300
  }
5274
5301
  },
5275
5302
  from: (v, meta, options) => {
5276
5303
  meta.state.system_mode = v === true ? (meta.state.system_mode_device ?? "cool") : "off";
5277
- if (options?.expose_device_state === true) {
5304
+ if (options.expose_device_state === true)
5278
5305
  return v === true ? "ON" : "OFF";
5279
- }
5280
5306
  delete meta.state.state;
5281
5307
  },
5282
5308
  },
@@ -5285,22 +5311,29 @@ exports.definitions = [
5285
5311
  2,
5286
5312
  "system_mode",
5287
5313
  {
5288
- // Extend system_mode to support 'off' in addition to 'cool', 'heat' and 'fan_only'
5289
5314
  to: async (v, meta) => {
5290
- const entity = meta.device.endpoints[0];
5291
- // Power State
5292
- await tuya.sendDataPointBool(entity, 1, v !== "off", "dataRequest", 1);
5293
- switch (v) {
5294
- case "cool":
5295
- await tuya.sendDataPointEnum(entity, 2, 0, "dataRequest", 1);
5296
- break;
5297
- case "heat":
5298
- await tuya.sendDataPointEnum(entity, 2, 1, "dataRequest", 1);
5299
- break;
5300
- case "fan_only":
5301
- await tuya.sendDataPointEnum(entity, 2, 2, "dataRequest", 1);
5302
- break;
5315
+ const ep = meta.device.endpoints[0];
5316
+ if (v === "off") {
5317
+ if (meta.options.wake_before_power_transition === true) {
5318
+ await tuya.sendDataPointBool(ep, 1, true, "dataRequest", 1);
5319
+ await new Promise((r) => setTimeout(r, 120));
5320
+ }
5321
+ await tuya.sendDataPointBool(ep, 1, false, "dataRequest", 1);
5322
+ return;
5303
5323
  }
5324
+ if (meta.options.wake_before_power_transition === true) {
5325
+ if (meta.state.system_mode === "off") {
5326
+ await tuya.sendDataPointBool(ep, 1, true, "dataRequest", 1);
5327
+ await new Promise((r) => setTimeout(r, 120));
5328
+ }
5329
+ }
5330
+ await tuya.sendDataPointBool(ep, 1, true, "dataRequest", 1);
5331
+ if (v === "cool")
5332
+ await tuya.sendDataPointEnum(ep, 2, 0, "dataRequest", 1);
5333
+ if (v === "heat")
5334
+ await tuya.sendDataPointEnum(ep, 2, 1, "dataRequest", 1);
5335
+ if (v === "fan_only")
5336
+ await tuya.sendDataPointEnum(ep, 2, 2, "dataRequest", 1);
5304
5337
  },
5305
5338
  from: (v, meta) => {
5306
5339
  const modes = ["cool", "heat", "fan_only"];
@@ -5309,7 +5342,21 @@ exports.definitions = [
5309
5342
  },
5310
5343
  },
5311
5344
  ],
5312
- [4, "preset", tuya.valueConverterBasic.lookup({ manual: true, auto: false })],
5345
+ [
5346
+ 4,
5347
+ "preset",
5348
+ {
5349
+ to: async (v, meta) => {
5350
+ const ep = meta.device.endpoints[0];
5351
+ await tuya.sendDataPointBool(ep, 4, v === "manual");
5352
+ },
5353
+ from: (v, meta) => {
5354
+ const preset = v ? "manual" : "auto";
5355
+ meta.state.preset = preset;
5356
+ return preset;
5357
+ },
5358
+ },
5359
+ ],
5313
5360
  [16, "current_heating_setpoint", tuya.valueConverter.raw],
5314
5361
  [19, "max_temperature", tuya.valueConverter.raw],
5315
5362
  [24, "local_temperature", tuya.valueConverter.divideBy10],
@@ -5330,52 +5377,45 @@ exports.definitions = [
5330
5377
  101,
5331
5378
  "schedule",
5332
5379
  {
5333
- to: (v, meta) => {
5334
- const periods = (value) => {
5335
- const regex = /((?<h>[01][0-9]|2[0-3]):(?<m>[0-5][0-9])\/(?<t>[0-3][0-9](\.[0,5]|)))/gm;
5336
- const matches = [...value.matchAll(regex)];
5337
- if (matches.length === 4) {
5338
- return matches.reduce((arr, m) => {
5339
- arr.push(Number.parseInt(m.groups.h, 10));
5340
- arr.push(Number.parseInt(m.groups.m, 10));
5341
- arr.push(Number.parseFloat(m.groups.t) * 2);
5342
- return arr;
5343
- }, []);
5344
- }
5345
- logger_1.logger.warning("Ignoring invalid or incomplete schedule", NS);
5346
- };
5347
- const schedule = [...periods(v.weekdays), ...periods(v.saturday), ...periods(v.sunday)];
5348
- return schedule;
5349
- },
5350
5380
  from: (v, meta) => {
5351
- const format = (data) => {
5352
- return data.reduce((a, v, i) => {
5353
- switch (i % 3) {
5354
- // Hour
5355
- case 0:
5356
- return `${a}${i > 0 ? " " : ""}${v.toString().padStart(2, "0")}`;
5357
- // Minute
5358
- case 1:
5359
- return `${a}:${v.toString().padStart(2, "0")}`;
5360
- // Setpoint
5361
- case 2:
5362
- return `${a}/${v / 2}`;
5363
- default:
5364
- throw new Error(`Unexpected index ${i} in schedule data`);
5365
- }
5366
- }, "");
5367
- };
5368
- return {
5369
- weekdays: format(v.slice(0, 12)),
5370
- saturday: format(v.slice(1 * 12, 2 * 12)),
5371
- sunday: format(v.slice(2 * 12, 3 * 12)),
5372
- };
5381
+ const format = (data) => data.reduce((txt, val, i) => {
5382
+ if (i % 3 === 0)
5383
+ return `${txt}${i > 0 ? " " : ""}${val.toString().padStart(2, "0")}`;
5384
+ if (i % 3 === 1)
5385
+ return `${txt}:${val.toString().padStart(2, "0")}`;
5386
+ return `${txt}/${val / 2}`;
5387
+ }, "");
5388
+ const weekdays = format(v.slice(0, 12));
5389
+ const saturday = format(v.slice(12, 24));
5390
+ const sunday = format(v.slice(24, 36));
5391
+ const full = `${weekdays} ${saturday} ${sunday}`.trim();
5392
+ meta.state.schedule_text = full;
5393
+ return full;
5394
+ },
5395
+ },
5396
+ ],
5397
+ [
5398
+ 202,
5399
+ "schedule_text",
5400
+ {
5401
+ to: async (v, meta) => {
5402
+ const regex = /((?<h>[01][0-9]|2[0-3]):(?<m>[0-5][0-9])\/(?<t>[0-3]?[0-9](\.[0,5])?))/gm;
5403
+ const matches = [...v.matchAll(regex)];
5404
+ if (matches.length !== 12)
5405
+ return;
5406
+ const result = [];
5407
+ for (const m of matches) {
5408
+ result.push(Number(m.groups?.h));
5409
+ result.push(Number(m.groups?.m));
5410
+ result.push(Number(m.groups?.t) * 2);
5411
+ }
5412
+ await tuya.sendDataPointRaw(meta.device.endpoints[0], 101, Buffer.from(result));
5373
5413
  },
5374
5414
  },
5375
5415
  ],
5376
5416
  ],
5377
5417
  },
5378
- whiteLabel: [tuya.whitelabel("Tuya", "BAC-002-ALZB", "FCU thermostat temperature controller", ["_TZE200_dzuqwsyg"])],
5418
+ whiteLabel: [tuya.whitelabel("Tuya", "BAC-003", "FCU thermostat temperature controller", ["_TZE204_dzuqwsyg"])],
5379
5419
  },
5380
5420
  {
5381
5421
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_qq9mpfhw"]),
@@ -6003,7 +6043,7 @@ exports.definitions = [
6003
6043
  onOffCountdown: (m) => m !== "_TZ3000_xfxpoxe0",
6004
6044
  indicatorMode: (m) => m !== "_TZ3000_xfxpoxe0",
6005
6045
  powerOutageMemory: true,
6006
- backlightModeOffOn: true,
6046
+ backlightModeOffOn: (m) => m === "_TZ3000_xfxpoxe0",
6007
6047
  }),
6008
6048
  ],
6009
6049
  configure: async (device, coordinatorEndpoint) => {
@@ -9598,10 +9638,9 @@ exports.definitions = [
9598
9638
  extend: [
9599
9639
  m.deviceEndpoints({ endpoints: { l1: 1, l2: 2, l3: 3, l4: 4 } }),
9600
9640
  tuya.modernExtend.tuyaOnOff({
9601
- powerOnBehavior2: (m) => m !== "_TZ3000_r9e2w7dn",
9641
+ powerOnBehavior2: true,
9602
9642
  backlightModeOffOn: true,
9603
9643
  endpoints: ["l1", "l2", "l3", "l4"],
9604
- powerOutageMemory: (m) => m === "_TZ3000_r9e2w7dn",
9605
9644
  switchType: (m) => m === "_TZ3000_r9e2w7dn",
9606
9645
  }),
9607
9646
  ],
@@ -11516,7 +11555,7 @@ exports.definitions = [
11516
11555
  },
11517
11556
  },
11518
11557
  {
11519
- fingerprint: tuya.fingerprint("TS0601", ["_TZE204_qasjif9e", "_TZE204_ztqnh5cg", "_TZE204_iadro9bf", "_TZE284_iadro9bf"]),
11558
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE204_qasjif9e", "_TZE200_qasjif9e", "_TZE204_ztqnh5cg", "_TZE204_iadro9bf", "_TZE284_iadro9bf"]),
11520
11559
  model: "ZY-M100-S_2",
11521
11560
  vendor: "Tuya",
11522
11561
  description: "Mini human breathe sensor",
@@ -14794,6 +14833,20 @@ exports.definitions = [
14794
14833
  ],
14795
14834
  },
14796
14835
  },
14836
+ {
14837
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE204_w2vunxzm"]),
14838
+ model: "_TZE204_w2vunxzm",
14839
+ vendor: "Tuya",
14840
+ description: "Pressure sensor",
14841
+ extend: [tuya.modernExtend.tuyaBase({ dp: true })],
14842
+ exposes: [e.pressure(), e.temperature()],
14843
+ meta: {
14844
+ tuyaDatapoints: [
14845
+ [101, "pressure", tuya.valueConverter.divideBy10],
14846
+ [8, "temperature", tuya.valueConverter.divideBy100],
14847
+ ],
14848
+ },
14849
+ },
14797
14850
  {
14798
14851
  fingerprint: tuya.fingerprint("TS0601", ["_TZE204_sooucan5", "_TZE204_oqtpvx51"]),
14799
14852
  model: "YXZBRB58",
@@ -16042,7 +16095,10 @@ exports.definitions = [
16042
16095
  model: "BLE-YL01",
16043
16096
  vendor: "Tuya",
16044
16097
  description: "Smart WiFi Zigbee chlorine meter",
16045
- whiteLabel: [tuya.whitelabel("Tuya", "YK-S03", "Smart pH and Chlorine Tester for Swimming Pool", ["_TZE200_d9mzkhoq"])],
16098
+ whiteLabel: [
16099
+ tuya.whitelabel("Tuya", "YK-S03", "Smart pH and Chlorine Tester for Swimming Pool", ["_TZE200_d9mzkhoq"]),
16100
+ { model: "YY-1099L", vendor: "Tuya" },
16101
+ ],
16046
16102
  // Don't query too often. Values are not always updated. https://github.com/Koenkk/zigbee2mqtt/issues/18704
16047
16103
  extend: [
16048
16104
  tuya.modernExtend.tuyaBase({
@@ -18703,11 +18759,12 @@ exports.definitions = [
18703
18759
  },
18704
18760
  },
18705
18761
  {
18706
- fingerprint: tuya.fingerprint("TS0601", ["_TZE284_kyyu8rbj"]),
18762
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE284_kyyu8rbj", "_TZE204_7yyuo8sr"]),
18707
18763
  model: "ME201WZ",
18708
18764
  vendor: "Tuya",
18709
18765
  description: "Water level sensor",
18710
18766
  extend: [tuya.modernExtend.tuyaBase({ dp: true, forceTimeUpdates: true })],
18767
+ whiteLabel: [tuya.whitelabel("Tuya", "872WZ", "Water level sensor", ["_TZE204_7yyuo8sr"])],
18711
18768
  exposes: [
18712
18769
  e.numeric("liquid_level_percent", ea.STATE).withUnit("%").withDescription("Liquid level ratio"),
18713
18770
  e.numeric("liquid_depth", ea.STATE).withUnit("m").withDescription("Liquid Depth"),
@@ -19640,6 +19697,84 @@ exports.definitions = [
19640
19697
  ],
19641
19698
  },
19642
19699
  },
19700
+ {
19701
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE284_cgr0rhza"]),
19702
+ model: "TS0601_thermostat_6",
19703
+ vendor: "Tuya",
19704
+ description: "Thermostatic radiator valve",
19705
+ extend: [tuya.modernExtend.tuyaBase({ dp: true, forceTimeUpdates: true })],
19706
+ exposes: [
19707
+ e.child_lock(),
19708
+ e.battery(),
19709
+ e.open_window(),
19710
+ e.window_detection(),
19711
+ e.battery_low(),
19712
+ e
19713
+ .climate()
19714
+ .withSetpoint("current_heating_setpoint", 5, 35, 0.5, ea.STATE_SET)
19715
+ .withLocalTemperature(ea.STATE)
19716
+ .withPreset(["manual", "schedule", "eco", "comfort", "antifrost", "off"])
19717
+ .withSystemMode(["off", "heat"], ea.STATE)
19718
+ .withLocalTemperatureCalibration(-12, 12, 1, ea.STATE_SET),
19719
+ ...tuya.exposes.scheduleAllDays(ea.STATE_SET, "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C"),
19720
+ e.comfort_temperature().withValueMin(5).withValueMax(35),
19721
+ e.eco_temperature().withValueMin(5).withValueMax(35),
19722
+ e
19723
+ .binary("scale_protection", ea.STATE_SET, "ON", "OFF")
19724
+ .withDescription("If the heat sink is not fully opened within " +
19725
+ "two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be " +
19726
+ "able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every " +
19727
+ 'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
19728
+ "again."),
19729
+ e
19730
+ .binary("frost_protection", ea.STATE_SET, "ON", "OFF")
19731
+ .withDescription("When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes."),
19732
+ e.numeric("error", ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
19733
+ ],
19734
+ meta: {
19735
+ tuyaDatapoints: [
19736
+ [
19737
+ 2,
19738
+ "preset",
19739
+ tuya.valueConverterBasic.lookup({
19740
+ manual: tuya.enum(0),
19741
+ schedule: tuya.enum(1),
19742
+ eco: tuya.enum(2),
19743
+ comfort: tuya.enum(3),
19744
+ antifrost: tuya.enum(4),
19745
+ off: tuya.enum(5),
19746
+ }),
19747
+ ],
19748
+ [4, "current_heating_setpoint", tuya.valueConverter.divideBy10],
19749
+ [5, "local_temperature", tuya.valueConverter.divideBy10],
19750
+ [6, "battery", tuya.valueConverter.raw],
19751
+ [7, "child_lock", tuya.valueConverter.lockUnlock],
19752
+ [8, "window_detection", tuya.valueConverter.onOff],
19753
+ [14, "open_window", tuya.valueConverter.onOff],
19754
+ [24, "comfort_temperature", tuya.valueConverter.divideBy10],
19755
+ [25, "eco_temperature", tuya.valueConverter.divideBy10],
19756
+ [28, "schedule_monday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
19757
+ [29, "schedule_tuesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
19758
+ [30, "schedule_wednesday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
19759
+ [31, "schedule_thursday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
19760
+ [32, "schedule_friday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
19761
+ [33, "schedule_saturday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
19762
+ [34, "schedule_sunday", tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
19763
+ [35, "fault_alarm", tuya.valueConverter.errorOrBatteryLow],
19764
+ [36, "frost_protection", tuya.valueConverter.onOff],
19765
+ [39, "scale_protection", tuya.valueConverter.onOff],
19766
+ [47, "local_temperature_calibration", tuya.valueConverter.localTempCalibration2],
19767
+ [
19768
+ 49,
19769
+ "system_mode",
19770
+ tuya.valueConverterBasic.lookup({
19771
+ off: tuya.enum(0),
19772
+ heat: tuya.enum(1),
19773
+ }),
19774
+ ],
19775
+ ],
19776
+ },
19777
+ },
19643
19778
  {
19644
19779
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wem3gxyx"]),
19645
19780
  model: "AE-940K",
@@ -22790,6 +22925,30 @@ exports.definitions = [
22790
22925
  ],
22791
22926
  },
22792
22927
  },
22928
+ {
22929
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE200_fphxkxue"]),
22930
+ model: "ZVL-PRO",
22931
+ vendor: "Nova Digital",
22932
+ description: "Water walve",
22933
+ extend: [tuya.modernExtend.tuyaBase({ dp: true })],
22934
+ exposes: [
22935
+ e.switch().setAccess("state", ea.STATE_SET),
22936
+ e.battery(),
22937
+ e.numeric("countdown", ea.STATE_SET).withUnit("s").withValueMin(0).withValueMax(86400).withDescription("Countdown time in seconds"),
22938
+ e.enum("work_state", ea.STATE, ["auto", "manual", "idle"]).withDescription("Current state of operation"),
22939
+ e.numeric("water_once", ea.STATE).withUnit("L").withDescription("Consumption from the last watering"),
22940
+ ],
22941
+ meta: {
22942
+ tuyaDatapoints: [
22943
+ [1, "state", tuya.valueConverter.onOff],
22944
+ [7, "battery", tuya.valueConverter.raw],
22945
+ [11, "countdown", tuya.valueConverter.raw],
22946
+ [12, "work_state", tuya.valueConverter.raw],
22947
+ [5, "water_once", tuya.valueConverter.raw],
22948
+ [4, "fault", tuya.valueConverter.raw],
22949
+ ],
22950
+ },
22951
+ },
22793
22952
  {
22794
22953
  fingerprint: tuya.fingerprint("TS0601", ["_TZE204_wc2w9t1s"]),
22795
22954
  model: "BOT-R9V-ZB",
@@ -23009,5 +23168,54 @@ exports.definitions = [
23009
23168
  ],
23010
23169
  },
23011
23170
  },
23171
+ {
23172
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE284_vceqncho"]),
23173
+ model: "ZIS-01P",
23174
+ vendor: "Novato",
23175
+ description: "Dual-tech presence sensor (PIR + radar)",
23176
+ extend: [tuya.modernExtend.tuyaBase({ dp: true })],
23177
+ exposes: [
23178
+ e.occupancy(),
23179
+ e
23180
+ .numeric("presence_distance", ea.STATE_SET)
23181
+ .withUnit("m")
23182
+ .withDescription("Detection distance")
23183
+ .withValueMin(1)
23184
+ .withValueMax(3)
23185
+ .withValueStep(1),
23186
+ e
23187
+ .numeric("presence_sensitivity", ea.STATE_SET)
23188
+ .withDescription("Presence detection sensitivity")
23189
+ .withValueMin(1)
23190
+ .withValueMax(3)
23191
+ .withValueStep(1),
23192
+ e.binary("radar_switch", ea.STATE_SET, "ON", "OFF").withDescription("Enable/disable radar detection"),
23193
+ e.numeric("pir_sensitivity", ea.STATE_SET).withDescription("PIR sensor sensitivity").withValueMin(1).withValueMax(3).withValueStep(1),
23194
+ e
23195
+ .numeric("delay_time", ea.STATE_SET)
23196
+ .withUnit("s")
23197
+ .withDescription("Delay time before reporting no presence")
23198
+ .withValueMin(10)
23199
+ .withValueMax(600),
23200
+ e.binary("led_switch", ea.STATE_SET, "ON", "OFF").withDescription("Enable/disable LED indicator"),
23201
+ e.illuminance().withUnit("lx"),
23202
+ e.battery().withUnit("%"),
23203
+ e.numeric("radar_threshold", ea.STATE_SET).withDescription("Radar detection threshold").withValueMin(5).withValueMax(50).withValueStep(1),
23204
+ ],
23205
+ meta: {
23206
+ tuyaDatapoints: [
23207
+ [1, "occupancy", tuya.valueConverter.trueFalse1],
23208
+ [102, "presence_distance", tuya.valueConverter.raw],
23209
+ [103, "presence_sensitivity", tuya.valueConverter.raw],
23210
+ [104, "radar_switch", tuya.valueConverter.onOff],
23211
+ [105, "pir_sensitivity", tuya.valueConverter.raw],
23212
+ [106, "delay_time", tuya.valueConverter.raw],
23213
+ [107, "led_switch", tuya.valueConverter.onOff],
23214
+ [108, "illuminance", tuya.valueConverter.raw],
23215
+ [109, "battery", tuya.valueConverter.raw],
23216
+ [164, "radar_threshold", tuya.valueConverter.raw],
23217
+ ],
23218
+ },
23219
+ },
23012
23220
  ];
23013
23221
  //# sourceMappingURL=tuya.js.map