zigbee-herdsman-converters 25.92.0 → 25.94.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 (55) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/converters/fromZigbee.d.ts +1 -1
  3. package/dist/converters/fromZigbee.d.ts.map +1 -1
  4. package/dist/converters/fromZigbee.js +4 -4
  5. package/dist/converters/fromZigbee.js.map +1 -1
  6. package/dist/devices/ctm.d.ts.map +1 -1
  7. package/dist/devices/ctm.js +51 -9
  8. package/dist/devices/ctm.js.map +1 -1
  9. package/dist/devices/dresden_elektronik.d.ts.map +1 -1
  10. package/dist/devices/dresden_elektronik.js +16 -6
  11. package/dist/devices/dresden_elektronik.js.map +1 -1
  12. package/dist/devices/ezviz.d.ts +3 -0
  13. package/dist/devices/ezviz.d.ts.map +1 -0
  14. package/dist/devices/ezviz.js +47 -0
  15. package/dist/devices/ezviz.js.map +1 -0
  16. package/dist/devices/gewiss.d.ts.map +1 -1
  17. package/dist/devices/gewiss.js +2 -1
  18. package/dist/devices/gewiss.js.map +1 -1
  19. package/dist/devices/heiman.d.ts.map +1 -1
  20. package/dist/devices/heiman.js +948 -256
  21. package/dist/devices/heiman.js.map +1 -1
  22. package/dist/devices/index.d.ts.map +1 -1
  23. package/dist/devices/index.js +2 -0
  24. package/dist/devices/index.js.map +1 -1
  25. package/dist/devices/jxuan.js +1 -1
  26. package/dist/devices/jxuan.js.map +1 -1
  27. package/dist/devices/ledvance.d.ts.map +1 -1
  28. package/dist/devices/ledvance.js +14 -20
  29. package/dist/devices/ledvance.js.map +1 -1
  30. package/dist/devices/legrand.d.ts.map +1 -1
  31. package/dist/devices/legrand.js +8 -1
  32. package/dist/devices/legrand.js.map +1 -1
  33. package/dist/devices/moes.d.ts.map +1 -1
  34. package/dist/devices/moes.js +98 -0
  35. package/dist/devices/moes.js.map +1 -1
  36. package/dist/devices/muller_licht.d.ts.map +1 -1
  37. package/dist/devices/muller_licht.js +7 -0
  38. package/dist/devices/muller_licht.js.map +1 -1
  39. package/dist/devices/paulmann.d.ts.map +1 -1
  40. package/dist/devices/paulmann.js +7 -0
  41. package/dist/devices/paulmann.js.map +1 -1
  42. package/dist/devices/philips.d.ts.map +1 -1
  43. package/dist/devices/philips.js +37 -13
  44. package/dist/devices/philips.js.map +1 -1
  45. package/dist/devices/sonoff.d.ts.map +1 -1
  46. package/dist/devices/sonoff.js +5 -0
  47. package/dist/devices/sonoff.js.map +1 -1
  48. package/dist/devices/tuya.d.ts.map +1 -1
  49. package/dist/devices/tuya.js +440 -16
  50. package/dist/devices/tuya.js.map +1 -1
  51. package/dist/lib/modernExtend.d.ts.map +1 -1
  52. package/dist/lib/modernExtend.js +3 -3
  53. package/dist/lib/modernExtend.js.map +1 -1
  54. package/dist/models-index.json +1 -1
  55. package/package.json +3 -3
@@ -412,6 +412,40 @@ const convLocal = {
412
412
  },
413
413
  },
414
414
  };
415
+ // TS0601_smart_scene_knob constants and helpers //
416
+ // 4 physical buttons with knob rotation, 3 modes: Scene (DP 1-4), Light (ZCL), Curtain (DP broadcast)
417
+ // Mode switch: hold button 2 or 4 for 5 seconds (only cycles through bound modes)
418
+ // Group ID pattern: base + (button-1) * 20, detected from first button press
419
+ const modeScene = 0x01;
420
+ const modeLight = 0x03;
421
+ const modeCurtain = 0x04;
422
+ const groupIdOffset = 20;
423
+ const statusUnassigned = "unassigned";
424
+ const statusWaiting = "waiting_button_1";
425
+ const statusReady = "ready";
426
+ const getButtonFromGroupId = (groupId, baseGroupId) => {
427
+ if (!baseGroupId || !groupId)
428
+ return null;
429
+ const offset = groupId - baseGroupId;
430
+ if (offset >= 0 && offset % groupIdOffset === 0) {
431
+ const button = Math.floor(offset / groupIdOffset) + 1;
432
+ if (button >= 1 && button <= 4)
433
+ return button;
434
+ }
435
+ return null;
436
+ };
437
+ // DP 102 payload: [0x01, 0x01, mode, ...name(12 bytes), ...suffix(4 bytes)]
438
+ // Suffix: slot number at position (slot-1), rest 0xff
439
+ const bindSlotTS0601SmartSceneKnob = async (entity, slot, mode) => {
440
+ const modeNames = { [modeScene]: "Scene", [modeLight]: "Light", [modeCurtain]: "Curtain" };
441
+ const slotName = `${modeNames[mode] || "Scene"} ${slot}`;
442
+ const nameBuffer = Buffer.alloc(12, 0);
443
+ nameBuffer.write(slotName, "utf8");
444
+ const suffix = Buffer.from([0xff, 0xff, 0xff, 0xff]);
445
+ suffix[slot - 1] = slot;
446
+ const payload = Buffer.concat([Buffer.from([0x01, 0x01, mode]), nameBuffer, suffix]);
447
+ await tuya.sendDataPointRaw(entity, 102, payload, "dataRequest", 0x10 + (slot - 1));
448
+ };
415
449
  const tzLocal = {
416
450
  ts0049_countdown: {
417
451
  key: ["water_countdown"],
@@ -797,6 +831,56 @@ const tzLocal = {
797
831
  return { state: { backlight_mode: value } };
798
832
  },
799
833
  },
834
+ // TS0601_smart_scene_knob //
835
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
836
+ TS0601_smart_scene_knob_bind_all: {
837
+ key: ["bind_all_scene", "bind_all_light", "bind_all_curtain"],
838
+ convertSet: async (entity, key, value, meta) => {
839
+ const modes = {
840
+ bind_all_scene: modeScene,
841
+ bind_all_light: modeLight,
842
+ bind_all_curtain: modeCurtain,
843
+ };
844
+ const mode = modes[key];
845
+ for (let slot = 1; slot <= 4; slot++) {
846
+ await bindSlotTS0601SmartSceneKnob(entity, slot, mode);
847
+ if (slot < 4)
848
+ await new Promise((resolve) => setTimeout(resolve, 500));
849
+ }
850
+ // Scene mode doesn't use Group ID
851
+ if (key === "bind_all_scene") {
852
+ return {};
853
+ }
854
+ const currentStatus = meta.state?.assignment_status;
855
+ const baseGroupId = meta.state?.base_group_id;
856
+ if (currentStatus !== statusReady || !baseGroupId) {
857
+ return { state: { assignment_status: statusWaiting } };
858
+ }
859
+ return {};
860
+ },
861
+ },
862
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
863
+ TS0601_smart_scene_knob_assign_button_1: {
864
+ key: ["assign_button_1"],
865
+ convertSet: (entity, key, value, meta) => {
866
+ return { state: { assignment_status: statusWaiting } };
867
+ },
868
+ },
869
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
870
+ TS0601_smart_scene_knob_set_base_group_id: {
871
+ key: ["set_base_group_id"],
872
+ convertSet: (entity, key, value, meta) => {
873
+ const baseGroupId = Number.parseInt(value, 10);
874
+ if (Number.isNaN(baseGroupId) || baseGroupId < 1 || baseGroupId > 65000)
875
+ return {};
876
+ return {
877
+ state: {
878
+ base_group_id: baseGroupId,
879
+ assignment_status: statusReady,
880
+ },
881
+ };
882
+ },
883
+ },
800
884
  };
801
885
  const fzLocal = {
802
886
  TLSR82xxAction: {
@@ -1048,6 +1132,213 @@ const fzLocal = {
1048
1132
  }
1049
1133
  },
1050
1134
  },
1135
+ // TS0601_smart_scene_knob //
1136
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
1137
+ TS0601_smart_scene_knob_light_onoff: {
1138
+ cluster: "genOnOff",
1139
+ type: ["commandOn", "commandOff"],
1140
+ convert: (model, msg, publish, options, meta) => {
1141
+ const groupId = msg.groupID;
1142
+ if (!groupId)
1143
+ return;
1144
+ const baseGroupId = meta.state?.base_group_id;
1145
+ const status = meta.state?.assignment_status || statusUnassigned;
1146
+ const command = msg.type === "commandOn" ? "on" : "off";
1147
+ if (status === statusWaiting) {
1148
+ return {
1149
+ base_group_id: groupId,
1150
+ assignment_status: statusReady,
1151
+ action: `light_1_${command}`,
1152
+ action_group: groupId,
1153
+ action_button: 1,
1154
+ };
1155
+ }
1156
+ if (status === statusReady && baseGroupId) {
1157
+ const button = getButtonFromGroupId(groupId, baseGroupId);
1158
+ if (!button)
1159
+ return;
1160
+ return {
1161
+ action: `light_${button}_${command}`,
1162
+ action_group: groupId,
1163
+ action_button: button,
1164
+ };
1165
+ }
1166
+ return { action_group: groupId, assignment_status: statusUnassigned };
1167
+ },
1168
+ },
1169
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
1170
+ TS0601_smart_scene_knob_light_brightness: {
1171
+ cluster: "genLevelCtrl",
1172
+ type: ["commandMoveToLevelWithOnOff", "commandMoveToLevel"],
1173
+ convert: (model, msg, publish, options, meta) => {
1174
+ const groupId = msg.groupID;
1175
+ if (!groupId)
1176
+ return;
1177
+ const baseGroupId = meta.state?.base_group_id;
1178
+ const status = meta.state?.assignment_status || statusUnassigned;
1179
+ // Device sends 0xFF at max brightness, which zigbee-herdsman parses as NaN
1180
+ // Clamp to 254 (max valid ZCL level per Zigbee spec)
1181
+ let level = msg.data.level;
1182
+ if (Number.isNaN(level)) {
1183
+ level = 254;
1184
+ }
1185
+ const prevBrightness = meta.state?.brightness;
1186
+ const prevDirection = meta.state?.brightness_direction;
1187
+ let direction = "";
1188
+ if (prevBrightness !== undefined) {
1189
+ if (level > prevBrightness)
1190
+ direction = "_up";
1191
+ else if (level < prevBrightness)
1192
+ direction = "_down";
1193
+ else
1194
+ direction = prevDirection || "";
1195
+ }
1196
+ if (status === statusWaiting) {
1197
+ return {
1198
+ base_group_id: groupId,
1199
+ assignment_status: statusReady,
1200
+ action: `light_1_brightness${direction}`,
1201
+ action_group: groupId,
1202
+ action_button: 1,
1203
+ brightness: level,
1204
+ brightness_direction: direction,
1205
+ };
1206
+ }
1207
+ if (status === statusReady && baseGroupId) {
1208
+ const button = getButtonFromGroupId(groupId, baseGroupId);
1209
+ if (!button)
1210
+ return;
1211
+ return {
1212
+ action: `light_${button}_brightness${direction}`,
1213
+ action_group: groupId,
1214
+ action_button: button,
1215
+ brightness: level,
1216
+ brightness_direction: direction,
1217
+ };
1218
+ }
1219
+ return { action_group: groupId, brightness: level };
1220
+ },
1221
+ },
1222
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
1223
+ TS0601_smart_scene_knob_light_colortemp: {
1224
+ // Direction: higher mired = warmer = down, lower mired = cooler = up
1225
+ cluster: "lightingColorCtrl",
1226
+ type: ["commandMoveToColorTemp"],
1227
+ convert: (model, msg, publish, options, meta) => {
1228
+ const groupId = msg.groupID;
1229
+ if (!groupId)
1230
+ return;
1231
+ const baseGroupId = meta.state?.base_group_id;
1232
+ const status = meta.state?.assignment_status || statusUnassigned;
1233
+ const colortemp = msg.data.colortemp;
1234
+ const prevColortemp = meta.state?.color_temp;
1235
+ const prevDirection = meta.state?.color_temp_direction;
1236
+ let direction = "";
1237
+ if (prevColortemp !== undefined) {
1238
+ if (colortemp > prevColortemp)
1239
+ direction = "_down";
1240
+ else if (colortemp < prevColortemp)
1241
+ direction = "_up";
1242
+ else
1243
+ direction = prevDirection || "";
1244
+ }
1245
+ if (status === statusWaiting) {
1246
+ return {
1247
+ base_group_id: groupId,
1248
+ assignment_status: statusReady,
1249
+ action: `light_1_colortemp${direction}`,
1250
+ action_group: groupId,
1251
+ action_button: 1,
1252
+ color_temp: colortemp,
1253
+ color_temp_direction: direction,
1254
+ };
1255
+ }
1256
+ if (status === statusReady && baseGroupId) {
1257
+ const button = getButtonFromGroupId(groupId, baseGroupId);
1258
+ if (!button)
1259
+ return;
1260
+ return {
1261
+ action: `light_${button}_colortemp${direction}`,
1262
+ action_group: groupId,
1263
+ action_button: button,
1264
+ color_temp: colortemp,
1265
+ color_temp_direction: direction,
1266
+ };
1267
+ }
1268
+ return { action_group: groupId, color_temp: colortemp };
1269
+ },
1270
+ },
1271
+ // biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
1272
+ TS0601_smart_scene_knob_curtain_command: {
1273
+ // DP 1: 0=start, 2=stop (1=init rotation, ignored)
1274
+ // DP 2: 4-byte big-endian position 0-100%
1275
+ cluster: "manuSpecificTuya",
1276
+ type: ["commandDataRequest"],
1277
+ convert: (model, msg, publish, options, meta) => {
1278
+ const groupId = msg.groupID;
1279
+ if (!groupId)
1280
+ return;
1281
+ const baseGroupId = meta.state?.base_group_id;
1282
+ const status = meta.state?.assignment_status || statusUnassigned;
1283
+ const dpValues = msg.data.dpValues;
1284
+ if (!dpValues || dpValues.length === 0)
1285
+ return;
1286
+ const dp = dpValues[0].dp;
1287
+ const data = dpValues[0].data;
1288
+ let action = null;
1289
+ let position = null;
1290
+ if (dp === 1) {
1291
+ const commands = { 0: "start", 2: "stop" };
1292
+ action = commands[data[0]] || null;
1293
+ }
1294
+ else if (dp === 2) {
1295
+ position = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
1296
+ const prevPosition = meta.state?.curtain_position;
1297
+ const prevDirection = meta.state?.curtain_position_direction;
1298
+ if (prevPosition !== undefined) {
1299
+ if (position > prevPosition)
1300
+ action = "position_open";
1301
+ else if (position < prevPosition)
1302
+ action = "position_close";
1303
+ else
1304
+ action = prevDirection ? `position${prevDirection}` : "position";
1305
+ }
1306
+ else {
1307
+ action = "position";
1308
+ }
1309
+ }
1310
+ if (!action)
1311
+ return;
1312
+ const result = { action_group: groupId };
1313
+ if (position !== null) {
1314
+ result.curtain_position = position;
1315
+ if (action.includes("_open"))
1316
+ result.curtain_position_direction = "_open";
1317
+ else if (action.includes("_close"))
1318
+ result.curtain_position_direction = "_close";
1319
+ }
1320
+ if (status === statusWaiting) {
1321
+ return {
1322
+ ...result,
1323
+ base_group_id: groupId,
1324
+ assignment_status: statusReady,
1325
+ action: `curtain_1_${action}`,
1326
+ action_button: 1,
1327
+ };
1328
+ }
1329
+ if (status === statusReady && baseGroupId) {
1330
+ const button = getButtonFromGroupId(groupId, baseGroupId);
1331
+ if (!button)
1332
+ return;
1333
+ return {
1334
+ ...result,
1335
+ action: `curtain_${button}_${action}`,
1336
+ action_button: button,
1337
+ };
1338
+ }
1339
+ return result;
1340
+ },
1341
+ },
1051
1342
  };
1052
1343
  exports.definitions = [
1053
1344
  {
@@ -2214,7 +2505,7 @@ exports.definitions = [
2214
2505
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_ogkdpgy2", "_TZE200_3ejwxpmu", "_TZE204_3ejwxpmu"]),
2215
2506
  model: "TS0601_temperature_humidity_co2_sensor",
2216
2507
  vendor: "Tuya",
2217
- description: "NDIR co2 sensor",
2508
+ description: "CO2 sensor",
2218
2509
  fromZigbee: [legacy.fromZigbee.tuya_air_quality],
2219
2510
  toZigbee: [],
2220
2511
  exposes: [e.temperature(), e.humidity(), e.co2()],
@@ -4291,6 +4582,7 @@ exports.definitions = [
4291
4582
  "_TZ3000_ssp0maqm",
4292
4583
  "_TZ3000_p3fph1go",
4293
4584
  "_TZ3000_9r5jaajv",
4585
+ "_TZ3000_nxdziqzc",
4294
4586
  ]),
4295
4587
  model: "TS0215A_sos",
4296
4588
  vendor: "Tuya",
@@ -5389,6 +5681,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
5389
5681
  "_TZ3000_66fekqhh",
5390
5682
  "_TZ3000_ok0ggpk7",
5391
5683
  "_TZ3000_aknpkt02",
5684
+ "_TZ3000_pfc7i3kt",
5392
5685
  ]),
5393
5686
  model: "TS0003_switch_3_gang_with_backlight",
5394
5687
  vendor: "Tuya",
@@ -5397,12 +5690,14 @@ Ensure all 12 segments are defined and separated by spaces.`),
5397
5690
  tuya.modernExtend.tuyaMagicPacket(),
5398
5691
  m.deviceEndpoints({ endpoints: { l1: 1, l2: 2, l3: 3 } }),
5399
5692
  tuya.modernExtend.tuyaOnOff({
5693
+ onOffCountdown: (m) => m !== "_TZ3000_pfc7i3kt",
5400
5694
  powerOnBehavior2: (m) => m !== "_TZ3000_nwidmc4n",
5401
- indicatorMode: (m) => m !== "_TZ3000_nwidmc4n",
5402
- backlightModeOffOn: true,
5695
+ indicatorMode: (m) => m !== "_TZ3000_nwidmc4n" && m !== "_TZ3000_pfc7i3kt",
5696
+ inchingSwitch: (m) => m !== "_TZ3000_pfc7i3kt",
5697
+ backlightModeOffOn: (m) => m !== "_TZ3000_pfc7i3kt",
5403
5698
  endpoints: ["l1", "l2", "l3"],
5404
5699
  powerOutageMemory: (m) => m === "_TZ3000_nwidmc4n",
5405
- switchType: (m) => m === "_TZ3000_nwidmc4n",
5700
+ switchType: (m) => m === "_TZ3000_nwidmc4n" || m === "_TZ3000_pfc7i3kt",
5406
5701
  }),
5407
5702
  ],
5408
5703
  configure: async (device, coordinatorEndpoint) => {
@@ -5412,6 +5707,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
5412
5707
  await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ["genOnOff"]);
5413
5708
  },
5414
5709
  whiteLabel: [
5710
+ tuya.whitelabel("Moes", "MS-104CZ", "3 gang switch module", ["_TZ3000_pfc7i3kt"]),
5415
5711
  tuya.whitelabel("Lonsonho", "X703A", "3 Gang switch with backlight", ["_TZ3000_rhkfbfcv"]),
5416
5712
  tuya.whitelabel("Zemismart", "ZM-L03E-Z", "3 gang switch with neutral", ["_TZ3000_empogkya", "_TZ3000_lsunm46z"]),
5417
5713
  tuya.whitelabel("Zemismart", "KES-606US-L3", "3 gang switch with neutral", ["_TZ3000_uilitwsy"]),
@@ -12162,6 +12458,22 @@ Ensure all 12 segments are defined and separated by spaces.`),
12162
12458
  await reporting.onOff(endpoint);
12163
12459
  },
12164
12460
  },
12461
+ {
12462
+ fingerprint: tuya.fingerprint("TS110E", ["_TZE200_ubgdwsnr"]),
12463
+ model: "EKAC-T3096Z",
12464
+ vendor: "Ekaza",
12465
+ description: "2 channel dimmer",
12466
+ extend: [tuya.modernExtend.tuyaBase({ dp: true }), m.deviceEndpoints({ endpoints: { l1: 1, l2: 2 } })],
12467
+ exposes: [e.light_brightness().withEndpoint("l1"), e.light_brightness().withEndpoint("l2")],
12468
+ meta: {
12469
+ tuyaDatapoints: [
12470
+ [1, "state_l1", tuya.valueConverter.onOff],
12471
+ [2, "brightness_l1", tuya.valueConverter.scale0_254to0_1000],
12472
+ [7, "state_l2", tuya.valueConverter.onOff],
12473
+ [8, "brightness_l2", tuya.valueConverter.scale0_254to0_1000],
12474
+ ],
12475
+ },
12476
+ },
12165
12477
  {
12166
12478
  fingerprint: tuya.fingerprint("TS110E", ["_TZ3210_wdexaypg"]),
12167
12479
  model: "TS110E_2gang_1",
@@ -13941,7 +14253,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
13941
14253
  whiteLabel: [tuya.whitelabel("Nous", "A4Z", "2 gang outdoor plug", ["_TZ3000_rqbjepe8", "_TZ3000_uwkja6z1"])],
13942
14254
  },
13943
14255
  {
13944
- fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_cfnprab5", "_TZ3000_o005nuxx", "_TZ3000_gdyjfvgm"]),
14256
+ fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_cfnprab5", "_TZ3000_o005nuxx", "_TZ3000_gdyjfvgm", "_TZ3000_pl5v1yyy"]),
13945
14257
  model: "TS011F_5",
13946
14258
  description: "Power strip 5 gang",
13947
14259
  vendor: "Tuya",
@@ -17605,6 +17917,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
17605
17917
  },
17606
17918
  },
17607
17919
  {
17920
+ zigbeeModel: ["ZG-303Z"],
17608
17921
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_wqashyqo"]),
17609
17922
  model: "ZG-303Z",
17610
17923
  vendor: "HOBEIAN",
@@ -19839,7 +20152,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
19839
20152
  },
19840
20153
  },
19841
20154
  {
19842
- zigbeeModel: ["ZG-303Z"],
20155
+ zigbeeModel: ["CS-201Z"],
19843
20156
  fingerprint: tuya.fingerprint("TS0601", ["_TZE200_npj9bug3", "_TZE200_wrmhp6b3"]),
19844
20157
  model: "CS-201Z",
19845
20158
  vendor: "COOLO",
@@ -20039,6 +20352,117 @@ Ensure all 12 segments are defined and separated by spaces.`),
20039
20352
  l2: 1,
20040
20353
  }),
20041
20354
  },
20355
+ {
20356
+ fingerprint: tuya.fingerprint("TS0601", ["_TZE284_nj7sfid2"]),
20357
+ model: "TS0601_smart_scene_knob",
20358
+ vendor: "Tuya",
20359
+ description: "Smart scene knob controller with 4 buttons",
20360
+ extend: [tuya.modernExtend.tuyaBase({ dp: true })],
20361
+ fromZigbee: [
20362
+ fzLocal.TS0601_smart_scene_knob_light_onoff,
20363
+ fzLocal.TS0601_smart_scene_knob_light_brightness,
20364
+ fzLocal.TS0601_smart_scene_knob_light_colortemp,
20365
+ fzLocal.TS0601_smart_scene_knob_curtain_command,
20366
+ ],
20367
+ toZigbee: [
20368
+ tzLocal.TS0601_smart_scene_knob_bind_all,
20369
+ tzLocal.TS0601_smart_scene_knob_assign_button_1,
20370
+ tzLocal.TS0601_smart_scene_knob_set_base_group_id,
20371
+ ],
20372
+ exposes: [
20373
+ e
20374
+ .action([
20375
+ "scene_1",
20376
+ "scene_2",
20377
+ "scene_3",
20378
+ "scene_4",
20379
+ "light_1_on",
20380
+ "light_1_off",
20381
+ "light_1_brightness_up",
20382
+ "light_1_brightness_down",
20383
+ "light_1_colortemp_up",
20384
+ "light_1_colortemp_down",
20385
+ "light_2_on",
20386
+ "light_2_off",
20387
+ "light_2_brightness_up",
20388
+ "light_2_brightness_down",
20389
+ "light_2_colortemp_up",
20390
+ "light_2_colortemp_down",
20391
+ "light_3_on",
20392
+ "light_3_off",
20393
+ "light_3_brightness_up",
20394
+ "light_3_brightness_down",
20395
+ "light_3_colortemp_up",
20396
+ "light_3_colortemp_down",
20397
+ "light_4_on",
20398
+ "light_4_off",
20399
+ "light_4_brightness_up",
20400
+ "light_4_brightness_down",
20401
+ "light_4_colortemp_up",
20402
+ "light_4_colortemp_down",
20403
+ "curtain_1_start",
20404
+ "curtain_1_stop",
20405
+ "curtain_1_position_open",
20406
+ "curtain_1_position_close",
20407
+ "curtain_2_start",
20408
+ "curtain_2_stop",
20409
+ "curtain_2_position_open",
20410
+ "curtain_2_position_close",
20411
+ "curtain_3_start",
20412
+ "curtain_3_stop",
20413
+ "curtain_3_position_open",
20414
+ "curtain_3_position_close",
20415
+ "curtain_4_start",
20416
+ "curtain_4_stop",
20417
+ "curtain_4_position_open",
20418
+ "curtain_4_position_close",
20419
+ ])
20420
+ .withDescription("Triggered action from scene button, light knob, or curtain control"),
20421
+ e.numeric("brightness", ea.STATE).withValueMin(0).withValueMax(254).withDescription("Brightness level from light mode (1-254)"),
20422
+ e.numeric("color_temp", ea.STATE).withValueMin(150).withValueMax(500).withDescription("Color temperature from light mode (mired)"),
20423
+ e
20424
+ .numeric("curtain_position", ea.STATE)
20425
+ .withValueMin(0)
20426
+ .withValueMax(100)
20427
+ .withUnit("%")
20428
+ .withDescription("Curtain position from curtain mode (0-100%)"),
20429
+ e
20430
+ .enum("assignment_status", ea.STATE, [statusUnassigned, statusWaiting, statusReady])
20431
+ .withCategory("diagnostic")
20432
+ .withDescription("Button assignment status"),
20433
+ e
20434
+ .numeric("base_group_id", ea.STATE)
20435
+ .withCategory("diagnostic")
20436
+ .withDescription("Base Group ID for button 1 (buttons 2-4 are +20, +40, +60)"),
20437
+ e
20438
+ .numeric("action_button", ea.STATE)
20439
+ .withValueMin(1)
20440
+ .withValueMax(4)
20441
+ .withCategory("diagnostic")
20442
+ .withDescription("Button number from last action"),
20443
+ e.numeric("action_group", ea.STATE).withCategory("diagnostic").withDescription("Group ID from last action"),
20444
+ e.enum("bind_all_scene", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Scene mode (red LED)"),
20445
+ e.enum("bind_all_light", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Light mode (green LED)"),
20446
+ e.enum("bind_all_curtain", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Curtain mode (blue LED)"),
20447
+ e.enum("assign_button_1", ea.SET, ["assign"]).withCategory("config").withDescription("Start assignment: press button 1 after clicking"),
20448
+ e
20449
+ .numeric("set_base_group_id", ea.SET)
20450
+ .withValueMin(1)
20451
+ .withValueMax(65000)
20452
+ .withCategory("config")
20453
+ .withDescription("Manually set base Group ID (advanced)"),
20454
+ ],
20455
+ meta: {
20456
+ tuyaDatapoints: [
20457
+ [1, "action", tuya.valueConverter.static("scene_1")],
20458
+ [2, "action", tuya.valueConverter.static("scene_2")],
20459
+ [3, "action", tuya.valueConverter.static("scene_3")],
20460
+ [4, "action", tuya.valueConverter.static("scene_4")],
20461
+ [52, "binding_confirmation", tuya.valueConverter.raw],
20462
+ [102, "binding_config", tuya.valueConverter.raw],
20463
+ ],
20464
+ },
20465
+ },
20042
20466
  {
20043
20467
  fingerprint: [{ modelID: "TS0601", manufacturerName: "_TZE200_khah2lkr" }],
20044
20468
  model: "HY607W-3A",
@@ -20559,7 +20983,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
20559
20983
  manual: tuya.enum(7),
20560
20984
  }),
20561
20985
  ],
20562
- [11, "power", tuya.valueConverter.raw],
20986
+ [11, "power", tuya.valueConverter.divideBy10],
20563
20987
  [16, "local_temperature", tuya.valueConverter.divideBy10],
20564
20988
  [
20565
20989
  17,
@@ -20577,8 +21001,8 @@ Ensure all 12 segments are defined and separated by spaces.`),
20577
21001
  [101, "voltage", tuya.valueConverter.divideBy10],
20578
21002
  [102, "current", tuya.valueConverter.divideBy1000],
20579
21003
  [103, "temperature_sensibility", tuya.valueConverter.divideBy10],
20580
- [104, "energy_today", tuya.valueConverter.raw],
20581
- [105, "energy_yesterday", tuya.valueConverter.raw],
21004
+ [104, "energy_today", tuya.valueConverter.divideBy10],
21005
+ [105, "energy_yesterday", tuya.valueConverter.divideBy10],
20582
21006
  [
20583
21007
  106,
20584
21008
  "device_mode_type",
@@ -20588,7 +21012,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
20588
21012
  switch: tuya.enum(2),
20589
21013
  }),
20590
21014
  ],
20591
- [107, "energy", tuya.valueConverter.raw],
21015
+ [107, "energy", tuya.valueConverter.divideBy10],
20592
21016
  [108, "week_program_1", tuya.valueConverter.raw],
20593
21017
  [109, "week_program_2", tuya.valueConverter.raw],
20594
21018
  [110, "week_program_3", tuya.valueConverter.raw],
@@ -20631,7 +21055,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
20631
21055
  e.energy(),
20632
21056
  e.numeric("energy_today", ea.STATE).withUnit("kWh").withDescription("Energy consumed today"),
20633
21057
  e.numeric("energy_yesterday", ea.STATE).withUnit("kWh").withDescription("Energy consumed yesterday"),
20634
- e.binary("device_mode_type", ea.STATE_SET, "ON", "OFF").withDescription("Set pilot wire mode to 6 (includes comfort 1 & 2)."),
21058
+ e.binary("device_mode_type", ea.STATE_SET, "ON", "OFF").withDescription("Set pilot wire mode to 6 modes (includes comfort 1 & 2)."),
20635
21059
  ],
20636
21060
  meta: {
20637
21061
  tuyaDatapoints: [
@@ -20647,7 +21071,7 @@ Ensure all 12 segments are defined and separated by spaces.`),
20647
21071
  comfort_2: tuya.enum(5),
20648
21072
  }),
20649
21073
  ],
20650
- [11, "power", tuya.valueConverter.raw],
21074
+ [11, "power", tuya.valueConverter.divideBy10],
20651
21075
  [16, "local_temperature", tuya.valueConverter.divideBy10],
20652
21076
  [19, "local_temperature_calibration", tuya.valueConverter.localTempCalibration2],
20653
21077
  [20, "fault", tuya.valueConverter.raw],
@@ -20667,10 +21091,10 @@ Ensure all 12 segments are defined and separated by spaces.`),
20667
21091
  [113, "window_timeout", tuya.valueConverter.raw],
20668
21092
  [114, "device_mode_type", tuya.valueConverter.onOff],
20669
21093
  [115, "voltage", tuya.valueConverter.divideBy10],
20670
- [116, "current", tuya.valueConverter.divideBy1000],
20671
- [117, "energy", tuya.valueConverter.raw],
20672
- [119, "energy_today", tuya.valueConverter.raw],
20673
- [120, "energy_yesterday", tuya.valueConverter.raw],
21094
+ [116, "current", tuya.valueConverter.divideBy10],
21095
+ [117, "energy", tuya.valueConverter.divideBy10],
21096
+ [119, "energy_today", tuya.valueConverter.divideBy10],
21097
+ [120, "energy_yesterday", tuya.valueConverter.divideBy10],
20674
21098
  ],
20675
21099
  },
20676
21100
  },