zigbee-herdsman-converters 25.51.1 → 25.52.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.
@@ -46,16 +46,20 @@ const e = exposes.presets;
46
46
  const ea = exposes.access;
47
47
  //const NS = "zhc:slacky_diy";
48
48
  const ppmReporting = { min: 10, max: 300, change: 0.000001 };
49
- const batteryReporting = { min: 3600, max: 0, change: 0 };
49
+ const batteryReporting = { min: 3600, max: 21600, change: 0 };
50
50
  const temperatureReporting = { min: 10, max: 3600, change: 10 };
51
51
  const humidityReporting = { min: 10, max: 3600, change: 10 };
52
52
  const model_r01 = "THERM_SLACKY_DIY_R01";
53
+ //const model_r02 = "THERM_SLACKY_DIY_R02";
53
54
  const model_r03 = "THERM_SLACKY_DIY_R03";
54
55
  const model_r04 = "THERM_SLACKY_DIY_R04";
56
+ //const model_r05 = "THERM_SLACKY_DIY_R05";
55
57
  const model_r06 = "THERM_SLACKY_DIY_R06";
56
58
  const model_r07 = "THERM_SLACKY_DIY_R07";
57
59
  const model_r08 = "THERM_SLACKY_DIY_R08";
58
60
  const model_r09 = "THERM_SLACKY_DIY_R09";
61
+ //const model_r0a = "THERM_SLACKY_DIY_R0A";
62
+ const model_r0b = "THERM_SLACKY_DIY_R0B";
59
63
  const attrThermSensorUser = 0xf000;
60
64
  const attrThermFrostProtect = 0xf001;
61
65
  const attrThermHeatProtect = 0xf002;
@@ -70,6 +74,7 @@ const attrThermInversion = 0xf00a;
70
74
  const attrThermEcoModeCoolTemperature = 0xf00b;
71
75
  const attrThermExtTemperatureCalibration = 0xf00c;
72
76
  const attrThermModeKeyLock = 0xf00d;
77
+ const attrThermManufName = 0xf00e;
73
78
  const attrFanCtrlControl = 0xf000;
74
79
  const switchSensorUsed = ["Inner (IN)", "All (AL)", "Outer (OU)"];
75
80
  const attrElCityMeterModelPreset = 0xf000;
@@ -99,13 +104,19 @@ const fzLocal = {
99
104
  convert: (model, msg, publish, options, meta) => {
100
105
  const result = {};
101
106
  if (msg.data[attrThermSensorUser] !== undefined) {
102
- const lookup = { 0: "Inner (IN)", 1: "All (AL)", 2: "Outer (OU)" };
103
- result.sensor = utils.getFromLookup(msg.data[attrThermSensorUser], lookup);
107
+ const lookup2 = { 0: "Inner (IN)", 1: "Outer (OU)" };
108
+ const lookup3 = { 0: "Inner (IN)", 1: "All (AL)", 2: "Outer (OU)" };
109
+ if (model.model === model_r0b) {
110
+ result.sensor = utils.getFromLookup(msg.data[attrThermSensorUser], lookup2);
111
+ }
112
+ else {
113
+ result.sensor = utils.getFromLookup(msg.data[attrThermSensorUser], lookup3);
114
+ }
104
115
  }
105
116
  if (msg.data.minSetpointDeadBand !== undefined) {
106
117
  //logger.info(`Model: ${model.model}`, NS);
107
118
  let data;
108
- if (model.model === model_r06 || model.model === model_r09) {
119
+ if (model.model === model_r06 || model.model === model_r09 || model.model === model_r0b) {
109
120
  data = msg.data.minSetpointDeadBand / 10;
110
121
  result.hysteresis_temperature = data;
111
122
  }
@@ -138,8 +149,14 @@ const fzLocal = {
138
149
  result.frost_protect_on_off = msg.data[attrThermFrostProtectOnOff] === 1 ? "On" : "Off";
139
150
  }
140
151
  if (msg.data[attrThermLevel] !== undefined) {
141
- const lookup = { 0: "Off", 1: "Low", 2: "Medium", 3: "High" };
142
- result.brightness_level = utils.getFromLookup(msg.data[attrThermLevel], lookup);
152
+ if (model.model === model_r0b) {
153
+ const lookup_sleep = { 0: "Off", 1: "Dim", 2: "On" };
154
+ result.screen_sleep_mode = utils.getFromLookup(msg.data[attrThermLevel], lookup_sleep);
155
+ }
156
+ else {
157
+ const lookup = { 0: "Off", 1: "Low", 2: "Medium", 3: "High" };
158
+ result.brightness_level = utils.getFromLookup(msg.data[attrThermLevel], lookup);
159
+ }
143
160
  }
144
161
  if (msg.data[attrThermSound] !== undefined) {
145
162
  result.sound = msg.data[attrThermSound] === 1 ? "On" : "Off";
@@ -163,7 +180,7 @@ const fzLocal = {
163
180
  },
164
181
  thermostat_schedule: {
165
182
  cluster: "hvacThermostat",
166
- type: ["commandSetWeeklySchedule"],
183
+ type: ["commandSetWeeklySchedule", "commandGetWeeklyScheduleRsp"],
167
184
  convert: (model, msg, publish, options, meta) => {
168
185
  const { data } = msg;
169
186
  const daysOfWeekNums = [...Array.from(Array(7).keys()).filter((x) => (2 ** x) & data.dayofweek)];
@@ -213,12 +230,16 @@ const tzLocal = {
213
230
  thermostat_sensor_used: {
214
231
  key: ["sensor"],
215
232
  convertSet: async (entity, key, value, meta) => {
216
- const endpoint = meta.device.getEndpoint(1);
217
- const lookup = { "Inner (IN)": 0, "All (AL)": 1, "Outer (OU)": 2 };
218
- await endpoint.write("hvacThermostat", { [attrThermSensorUser]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
219
- return {
220
- state: { [key]: value },
221
- };
233
+ //const endpoint = meta.device.getEndpoint(1);
234
+ const lookup2 = { "Inner (IN)": 0, "Outer (OU)": 1 };
235
+ const lookup3 = { "Inner (IN)": 0, "All (AL)": 1, "Outer (OU)": 2 };
236
+ if (meta.mapped.model === model_r0b) {
237
+ await entity.write("hvacThermostat", { [attrThermSensorUser]: { value: utils.getFromLookup(value, lookup2), type: 0x30 } });
238
+ }
239
+ else {
240
+ await entity.write("hvacThermostat", { [attrThermSensorUser]: { value: utils.getFromLookup(value, lookup3), type: 0x30 } });
241
+ }
242
+ return { readAfterWriteTime: 250, state: { sensor: value } };
222
243
  },
223
244
  convertGet: async (entity, key, meta) => {
224
245
  await entity.read("hvacThermostat", [attrThermSensorUser]);
@@ -252,8 +273,7 @@ const tzLocal = {
252
273
  key: ["frost_protect"],
253
274
  convertSet: async (entity, key, value, meta) => {
254
275
  utils.assertNumber(value);
255
- if (!utils.isInRange(0, 10, Number(value)))
256
- throw new Error(`Invalid value: ${value} (expected ${0} to ${10})`);
276
+ //if (!utils.isInRange(0, 10, Number(value))) throw new Error(`Invalid value: ${value} (expected ${0} to ${10})`);
257
277
  const frost_protect = Number(Math.round(value)) * 100;
258
278
  await entity.write("hvacThermostat", { [attrThermFrostProtect]: { value: frost_protect, type: 0x29 } });
259
279
  return { readAfterWriteTime: 250, state: { frost_protect: value } };
@@ -266,8 +286,7 @@ const tzLocal = {
266
286
  key: ["heat_protect"],
267
287
  convertSet: async (entity, key, value, meta) => {
268
288
  utils.assertNumber(value);
269
- if (!utils.isInRange(25, 70, Number(value)))
270
- throw new Error(`Invalid value: ${value} (expected ${25} to ${70})`);
289
+ //if (!utils.isInRange(25, 70, Number(value))) throw new Error(`Invalid value: ${value} (expected ${25} to ${70})`);
271
290
  const heat_protect = Number(Math.round(value)) * 100;
272
291
  await entity.write("hvacThermostat", { [attrThermHeatProtect]: { value: heat_protect, type: 0x29 } });
273
292
  return { readAfterWriteTime: 250, state: { heat_protect: value } };
@@ -280,8 +299,7 @@ const tzLocal = {
280
299
  key: ["setpoint_raise_lower"],
281
300
  convertSet: async (entity, key, value, meta) => {
282
301
  utils.assertNumber(value);
283
- if (!utils.isInRange(-5, 5, Number(value)))
284
- throw new Error(`Invalid value: ${value} (expected ${-5} to ${5})`);
302
+ //if (!utils.isInRange(-5, 5, Number(value))) throw new Error(`Invalid value: ${value} (expected ${-5} to ${5})`);
285
303
  const setpoint_raise_lower = Number(Math.fround(value)) * 10; //Step 0.1°C. 5°C - 50, 1°C - 10 etc.
286
304
  await entity.command("hvacThermostat", "setpointRaiseLower", { mode: 0, amount: setpoint_raise_lower });
287
305
  return { readAfterWriteTime: 250, state: { setpoint_raise_lower: value } };
@@ -313,8 +331,7 @@ const tzLocal = {
313
331
  key: ["eco_mode_cool_temperature"],
314
332
  convertSet: async (entity, key, value, meta) => {
315
333
  utils.assertNumber(value);
316
- if (!utils.isInRange(5, 45, Number(value)))
317
- throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
334
+ //if (!utils.isInRange(5, 45, Number(value))) throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
318
335
  const eco_mode_cool_temperature = Number(Math.round(value)) * 100;
319
336
  await entity.write("hvacThermostat", { [attrThermEcoModeCoolTemperature]: { value: eco_mode_cool_temperature, type: 0x29 } });
320
337
  return { readAfterWriteTime: 250, state: { eco_mode_cool_temperature: value } };
@@ -327,8 +344,7 @@ const tzLocal = {
327
344
  key: ["eco_mode_heat_temperature"],
328
345
  convertSet: async (entity, key, value, meta) => {
329
346
  utils.assertNumber(value);
330
- if (!utils.isInRange(5, 45, Number(value)))
331
- throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
347
+ //if (!utils.isInRange(5, 45, Number(value))) throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
332
348
  const eco_mode_heat_temperature = Number(Math.round(value)) * 100;
333
349
  await entity.write("hvacThermostat", { [attrThermEcoModeHeatTemperature]: { value: eco_mode_heat_temperature, type: 0x29 } });
334
350
  return { readAfterWriteTime: 250, state: { eco_mode_heat_temperature: value } };
@@ -371,6 +387,18 @@ const tzLocal = {
371
387
  await entity.read("hvacThermostat", [attrThermLevel]);
372
388
  },
373
389
  },
390
+ thermostat_screen_sleep_mode: {
391
+ key: ["screen_sleep_mode"],
392
+ convertSet: async (entity, key, value, meta) => {
393
+ //utils.assertNumber(value);
394
+ const lookup = { Off: 0, Dim: 1, On: 2 };
395
+ await entity.write("hvacThermostat", { [attrThermLevel]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
396
+ return { state: { screen_sleep_mode: value } };
397
+ },
398
+ convertGet: async (entity, key, meta) => {
399
+ await entity.read("hvacThermostat", [attrThermLevel]);
400
+ },
401
+ },
374
402
  thermostat_inversion: {
375
403
  key: ["relay_type"],
376
404
  convertSet: async (entity, key, value, meta) => {
@@ -417,8 +445,7 @@ const tzLocal = {
417
445
  key: ["external_temperature_calibration"],
418
446
  convertSet: async (entity, key, value, meta) => {
419
447
  utils.assertNumber(value);
420
- if (!utils.isInRange(-9, 9, Number(value)))
421
- throw new Error(`Invalid value: ${value} (expected ${-9} to ${9})`);
448
+ //if (!utils.isInRange(-9, 9, Number(value))) throw new Error(`Invalid value: ${value} (expected ${-9} to ${9})`);
422
449
  const external_temperature_calibration = Number(Math.round(value)) * 10;
423
450
  await entity.write("hvacThermostat", { [attrThermExtTemperatureCalibration]: { value: external_temperature_calibration, type: 0x28 } });
424
451
  return { readAfterWriteTime: 250, state: { external_temperature_calibration: value } };
@@ -427,6 +454,17 @@ const tzLocal = {
427
454
  await entity.read("hvacThermostat", [attrThermExtTemperatureCalibration]);
428
455
  },
429
456
  },
457
+ thermostat_manuf_name: {
458
+ key: ["manuf_name"],
459
+ convertSet: async (entity, key, value, meta) => {
460
+ const lookup = { r0: 0, r1: 1, r2: 2, r3: 3, r4: 4, r5: 5, r6: 6, r7: 7, r8: 8, r9: 9, r10: 10, r11: 11 };
461
+ await entity.write("hvacThermostat", { [attrThermManufName]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
462
+ return { state: { manuf_name: value } };
463
+ },
464
+ convertGet: async (entity, key, meta) => {
465
+ await entity.read("hvacThermostat", [attrThermManufName]);
466
+ },
467
+ },
430
468
  };
431
469
  const localFromZigbeeThermostat = [
432
470
  fz.thermostat,
@@ -463,14 +501,56 @@ const localToZigbeeThermostat = [
463
501
  tzLocal.thermostat_eco_mode_heat_temperature,
464
502
  tzLocal.thermostat_frost_protect_onoff,
465
503
  tzLocal.thermostat_brightness_level,
504
+ tzLocal.thermostat_screen_sleep_mode,
466
505
  tzLocal.thermostat_sound,
467
506
  tzLocal.thermostat_inversion,
468
507
  tzLocal.thermostat_schedule_mode,
469
508
  tzLocal.thermostat_settings_reset,
470
509
  tzLocal.thermostat_ext_temperature_calibration,
471
510
  tzLocal.thermostat_mode_child_lock,
511
+ tzLocal.thermostat_manuf_name,
472
512
  tzLocal.fancontrol_control,
473
513
  ];
514
+ function localActionExtend(args = {}) {
515
+ const { localAction = ["hold", "single", "double", "triple", "quadruple", "quintuple", "release"], reporting = true, reportingConfig = { min: 10, max: 0, change: 1 }, endpointNames = undefined, } = args;
516
+ let actions = localAction;
517
+ if (endpointNames) {
518
+ actions = localAction.flatMap((c) => endpointNames.map((e) => `${c}_${e}`));
519
+ }
520
+ const exposes = [e.enum("action", ea.STATE, actions)];
521
+ const actionPayloadLookup = {
522
+ 0: "hold",
523
+ 1: "single",
524
+ 2: "double",
525
+ 3: "triple",
526
+ 4: "quadruple",
527
+ 5: "quintuple",
528
+ 255: "release",
529
+ };
530
+ const fromZigbee = [
531
+ {
532
+ cluster: "genMultistateInput",
533
+ type: ["attributeReport", "readResponse"],
534
+ convert: (model, msg, publish, options, meta) => {
535
+ if (utils.hasAlreadyProcessedMessage(msg, model))
536
+ return;
537
+ const value = msg.data.presentValue;
538
+ //logger.logger.info('msg.data: ' + data[attribute]);
539
+ if (value === 300)
540
+ return { action: "N/A" };
541
+ const payload = { action: utils.postfixWithEndpointName(actionPayloadLookup[value], msg, model, meta) };
542
+ return payload;
543
+ },
544
+ },
545
+ ];
546
+ const result = { exposes, fromZigbee, isModernExtend: true };
547
+ if (reporting)
548
+ result.configure = [
549
+ m.setupConfigureForBinding("genMultistateInput", "output", endpointNames),
550
+ m.setupConfigureForReporting("genMultistateInput", "presentValue", { config: reportingConfig, access: ea.GET, endpointNames }),
551
+ ];
552
+ return result;
553
+ }
474
554
  async function configureCommon(device, coordinatorEndpoint, definition) {
475
555
  //logger.info(definition.model, NS);
476
556
  const endpoint1 = device.getEndpoint(1);
@@ -539,7 +619,7 @@ async function configureCommon(device, coordinatorEndpoint, definition) {
539
619
  await endpoint1.configureReporting("hvacThermostat", payload_min);
540
620
  const payload_max = [{ attribute: { ID: 0x0016, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
541
621
  await endpoint1.configureReporting("hvacThermostat", payload_max);
542
- if (definition.model !== model_r01 && definition.model !== model_r06) {
622
+ if (definition.model !== model_r01 && definition.model !== model_r06 && definition.model !== model_r0b) {
543
623
  const payload_outdoor = [{ attribute: { ID: 0x0001, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
544
624
  await endpoint1.configureReporting("hvacThermostat", payload_outdoor);
545
625
  }
@@ -1976,36 +2056,138 @@ exports.definitions = [
1976
2056
  meta: {},
1977
2057
  ota: true,
1978
2058
  },
2059
+ {
2060
+ zigbeeModel: ["Tuya_Thermostat_r0A"],
2061
+ model: "THERM_SLACKY_DIY_R0A",
2062
+ vendor: "Slacky-DIY",
2063
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
2064
+ endpoint: (device) => {
2065
+ return { day: 1, night: 2 };
2066
+ },
2067
+ fromZigbee: localFromZigbeeThermostat,
2068
+ toZigbee: localToZigbeeThermostat,
2069
+ configure: configureCommon,
2070
+ exposes: [
2071
+ e.binary("child_lock", ea.ALL, "Lock", "Unlock").withDescription("Enables/disables physical input on the device"),
2072
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
2073
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
2074
+ e
2075
+ .numeric("deadzone_temperature", ea.ALL)
2076
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
2077
+ .withUnit("°C")
2078
+ .withValueMin(1)
2079
+ .withValueMax(5)
2080
+ .withValueStep(1),
2081
+ e
2082
+ .numeric("min_heat_setpoint_limit", ea.ALL)
2083
+ .withUnit("°C")
2084
+ .withDescription("Minimum Heating set point limit")
2085
+ .withValueMin(0)
2086
+ .withValueMax(20)
2087
+ .withValueStep(1),
2088
+ e
2089
+ .numeric("max_heat_setpoint_limit", ea.ALL)
2090
+ .withDescription("Maximum Heating set point limit")
2091
+ .withUnit("°C")
2092
+ .withValueMin(20)
2093
+ .withValueMax(50)
2094
+ .withValueStep(1),
2095
+ e
2096
+ .numeric("heat_protect", ea.ALL)
2097
+ .withUnit("°C")
2098
+ .withDescription("Protection against maximum heating temperature")
2099
+ .withValueMin(25)
2100
+ .withValueMax(70)
2101
+ .withValueStep(1),
2102
+ e.binary("eco_mode", ea.ALL, "On", "Off").withDescription("On/Off Eco Mode"),
2103
+ e
2104
+ .climate()
2105
+ .withLocalTemperature()
2106
+ .withSetpoint("occupied_heating_setpoint", 1, 50, 1)
2107
+ .withLocalTemperatureCalibration(-9, 9, 1)
2108
+ .withSystemMode(["off", "heat"])
2109
+ .withRunningState(["idle", "heat"], ea.STATE)
2110
+ .withWeeklySchedule(["heat"], ea.ALL),
2111
+ e.text("schedule_monday", ea.STATE).withDescription("Schedule for the working week"),
2112
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
2113
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
2114
+ ],
2115
+ meta: {},
2116
+ ota: true,
2117
+ },
2118
+ {
2119
+ zigbeeModel: ["Tuya_Thermostat_r0B"],
2120
+ model: "THERM_SLACKY_DIY_R0B",
2121
+ vendor: "Slacky-DIY",
2122
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
2123
+ endpoint: (device) => {
2124
+ return { day: 1, night: 2 };
2125
+ },
2126
+ fromZigbee: localFromZigbeeThermostat,
2127
+ toZigbee: localToZigbeeThermostat,
2128
+ configure: configureCommon,
2129
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
2130
+ exposes: [
2131
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
2132
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
2133
+ e.enum("sensor", ea.ALL, ["Inner (IN)", "Outer (OU)"]).withDescription("Select temperature sensor to use"),
2134
+ e.enum("screen_sleep_mode", ea.ALL, ["Off", "Dim", "On"]).withDescription("Screen sleep mode of brightness"),
2135
+ e
2136
+ .numeric("hysteresis_temperature", ea.ALL)
2137
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
2138
+ .withUnit("°C")
2139
+ .withValueMin(0.5)
2140
+ .withValueMax(5)
2141
+ .withValueStep(0.5),
2142
+ e
2143
+ .numeric("min_heat_setpoint_limit", ea.ALL)
2144
+ .withUnit("°C")
2145
+ .withDescription("Minimum Heating set point limit")
2146
+ .withValueMin(1)
2147
+ .withValueMax(5)
2148
+ .withValueStep(0.5),
2149
+ e
2150
+ .numeric("max_heat_setpoint_limit", ea.ALL)
2151
+ .withDescription("Maximum Heating set point limit")
2152
+ .withUnit("°C")
2153
+ .withValueMin(35)
2154
+ .withValueMax(50)
2155
+ .withValueStep(0.5),
2156
+ e
2157
+ .climate()
2158
+ .withLocalTemperature()
2159
+ .withSetpoint("occupied_heating_setpoint", 1, 50, 1)
2160
+ .withLocalTemperatureCalibration(-9, 9, 1)
2161
+ .withSystemMode(["off", "heat"])
2162
+ .withRunningState(["idle", "heat"], ea.STATE)
2163
+ .withWeeklySchedule(["heat"], ea.ALL),
2164
+ e.text("schedule_monday", ea.STATE).withDescription("Schedule for the working week"),
2165
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
2166
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
2167
+ ],
2168
+ meta: {},
2169
+ ota: true,
2170
+ },
1979
2171
  {
1980
2172
  zigbeeModel: ["TS0201-z-SlD"],
1981
2173
  model: "TS0201-z-SlD",
1982
2174
  vendor: "Slacky-DIY",
1983
2175
  description: "Tuya temperature and humidity sensor with custom Firmware",
1984
- configure: async (device, coordinatorEndpoint, logger) => {
1985
- const endpoint = device.getEndpoint(1);
1986
- await endpoint.read("msTemperatureMeasurement", [attrSensorReadPeriod]);
1987
- await endpoint.read("msTemperatureMeasurement", [attrTemperatureOffset]);
1988
- await endpoint.read("msTemperatureMeasurement", [attrTemperatureOnOff]);
1989
- await endpoint.read("msTemperatureMeasurement", [attrTemperatureLow]);
1990
- await endpoint.read("msTemperatureMeasurement", [attrTemperatureHigh]);
1991
- await endpoint.read("msRelativeHumidity", [attrHumidityOffset]);
1992
- await endpoint.read("msRelativeHumidity", [attrHumidityOnOff]);
1993
- await endpoint.read("msRelativeHumidity", [attrHumidityLow]);
1994
- await endpoint.read("msRelativeHumidity", [attrHumidityHigh]);
1995
- },
1996
2176
  extend: [
2177
+ m.deviceEndpoints({
2178
+ endpoints: {
2179
+ "1": 1,
2180
+ "2": 2,
2181
+ },
2182
+ }),
1997
2183
  m.battery({
1998
2184
  voltage: true,
1999
2185
  voltageReporting: true,
2000
2186
  percentageReportingConfig: batteryReporting,
2001
2187
  voltageReportingConfig: batteryReporting,
2002
2188
  }),
2003
- m.temperature({
2004
- reporting: temperatureReporting,
2005
- }),
2006
- m.humidity({
2007
- reporting: humidityReporting,
2008
- }),
2189
+ m.temperature({ reporting: temperatureReporting }),
2190
+ m.humidity({ reporting: humidityReporting }),
2009
2191
  m.numeric({
2010
2192
  name: "temperature_offset",
2011
2193
  cluster: "msTemperatureMeasurement",
@@ -2033,7 +2215,7 @@ exports.definitions = [
2033
2215
  cluster: "msTemperatureMeasurement",
2034
2216
  attribute: { ID: attrSensorReadPeriod, type: 0x21 },
2035
2217
  unit: "Sec",
2036
- valueMin: 5,
2218
+ valueMin: 15,
2037
2219
  valueMax: 600,
2038
2220
  valueStep: 1,
2039
2221
  description: "Sensors reading period",
@@ -2068,6 +2250,14 @@ exports.definitions = [
2068
2250
  scale: 100,
2069
2251
  description: "Temperature high turn-on limit",
2070
2252
  }),
2253
+ m.enumLookup({
2254
+ name: "temperature_actions",
2255
+ endpointName: "1",
2256
+ lookup: { heat: 0, cool: 1 },
2257
+ cluster: "genOnOffSwitchCfg",
2258
+ attribute: "switchActions",
2259
+ description: "Heat or cool",
2260
+ }),
2071
2261
  m.binary({
2072
2262
  name: "enabling_humidity_control",
2073
2263
  cluster: "msRelativeHumidity",
@@ -2099,11 +2289,12 @@ exports.definitions = [
2099
2289
  description: "Humidity high turn-on limit",
2100
2290
  }),
2101
2291
  m.enumLookup({
2102
- name: "switch_actions",
2103
- lookup: { off: 0, on: 1 },
2292
+ name: "humidity_actions",
2293
+ endpointName: "2",
2294
+ lookup: { wet: 0, dry: 1 },
2104
2295
  cluster: "genOnOffSwitchCfg",
2105
2296
  attribute: "switchActions",
2106
- description: "Actions switch",
2297
+ description: "Wet or dry",
2107
2298
  }),
2108
2299
  ],
2109
2300
  ota: true,
@@ -2297,5 +2488,69 @@ exports.definitions = [
2297
2488
  meta: {},
2298
2489
  ota: true,
2299
2490
  },
2491
+ {
2492
+ zigbeeModel: ["QS-Zigbee-SEC02-Mod"],
2493
+ model: "QS-Zigbee-SEC02-Mod",
2494
+ vendor: "Svetomaniya",
2495
+ description: "Smart light switch module 2 gang",
2496
+ extend: [
2497
+ m.deviceEndpoints({ endpoints: { "1": 1, "2": 2 } }),
2498
+ m.onOff({ powerOnBehavior: true, endpointNames: ["1", "2"] }),
2499
+ m.commandsOnOff({ endpointNames: ["1", "2"] }),
2500
+ localActionExtend({ endpointNames: ["1", "2"] }),
2501
+ m.enumLookup({
2502
+ name: "switch_actions",
2503
+ endpointName: "1",
2504
+ lookup: { off: 0, on: 1 },
2505
+ cluster: "genOnOffSwitchCfg",
2506
+ attribute: "switchActions",
2507
+ description: "Actions switch 1",
2508
+ }),
2509
+ m.enumLookup({
2510
+ name: "switch_actions",
2511
+ endpointName: "2",
2512
+ lookup: { off: 0, on: 1 },
2513
+ cluster: "genOnOffSwitchCfg",
2514
+ attribute: "switchActions",
2515
+ description: "Actions switch 2",
2516
+ }),
2517
+ m.enumLookup({
2518
+ name: "switch_type",
2519
+ endpointName: "1",
2520
+ lookup: { toggle: 0, momentary: 1, multifunction: 2 },
2521
+ cluster: "genOnOffSwitchCfg",
2522
+ attribute: { ID: 0xf000, type: 0x30 },
2523
+ description: "Switch 1 type",
2524
+ }),
2525
+ m.enumLookup({
2526
+ name: "switch_type",
2527
+ endpointName: "2",
2528
+ lookup: { toggle: 0, momentary: 1, multifunction: 2 },
2529
+ cluster: "genOnOffSwitchCfg",
2530
+ attribute: { ID: 0xf000, type: 0x30 },
2531
+ description: "Switch 2 type",
2532
+ }),
2533
+ m.enumLookup({
2534
+ name: "operation_mode",
2535
+ endpointName: "1",
2536
+ lookup: { control_relay: 0, decoupled: 1 },
2537
+ cluster: "genOnOffSwitchCfg",
2538
+ attribute: { ID: 0xf001, type: 0x30 },
2539
+ reporting: { min: 0, max: 65000, change: 0 },
2540
+ description: "Relay 1 decoupled",
2541
+ }),
2542
+ m.enumLookup({
2543
+ name: "operation_mode",
2544
+ endpointName: "2",
2545
+ lookup: { control_relay: 0, decoupled: 1 },
2546
+ cluster: "genOnOffSwitchCfg",
2547
+ attribute: { ID: 0xf001, type: 0x30 },
2548
+ reporting: { min: 0, max: 65000, change: 0 },
2549
+ description: "Relay 2 decoupled",
2550
+ }),
2551
+ ],
2552
+ meta: { multiEndpoint: true },
2553
+ ota: true,
2554
+ },
2300
2555
  ];
2301
2556
  //# sourceMappingURL=slacky_diy.js.map