zigbee-herdsman-converters 23.13.0 → 23.14.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.
@@ -0,0 +1,1643 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.definitions = void 0;
37
+ const fz = __importStar(require("../converters/fromZigbee"));
38
+ const tz = __importStar(require("../converters/toZigbee"));
39
+ const exposes = __importStar(require("../lib/exposes"));
40
+ const m = __importStar(require("../lib/modernExtend"));
41
+ const reporting = __importStar(require("../lib/reporting"));
42
+ const globalStore = __importStar(require("../lib/store"));
43
+ const utils = __importStar(require("../lib/utils"));
44
+ const e = exposes.presets;
45
+ const ea = exposes.access;
46
+ const defaultReporting = { min: 0, max: 300, change: 0 };
47
+ const co2Reporting = { min: 10, max: 300, change: 0.000001 };
48
+ const batteryReporting = { min: 3600, max: 0, change: 0 };
49
+ const model_r01 = "Tuya_Thermostat_r01";
50
+ const model_r02 = "Tuya_Thermostat_r02";
51
+ const model_r03 = "Tuya_Thermostat_r03";
52
+ const model_r04 = "Tuya_Thermostat_r04";
53
+ const model_r05 = "Tuya_Thermostat_r05";
54
+ const model_r06 = "Tuya_Thermostat_r06";
55
+ const model_r07 = "Tuya_Thermostat_r07";
56
+ const model_r08 = "Tuya_Thermostat_r08";
57
+ const attrThermSensorUser = 0xf000;
58
+ const attrThermFrostProtect = 0xf001;
59
+ const attrThermHeatProtect = 0xf002;
60
+ const attrThermEcoMode = 0xf003;
61
+ const attrThermEcoModeHeatTemperature = 0xf004;
62
+ const attrThermFrostProtectOnOff = 0xf005;
63
+ const attrThermSettingsReset = 0xf006;
64
+ const attrThermScheduleMode = 0xf007;
65
+ const attrThermSound = 0xf008;
66
+ const attrThermLevel = 0xf009;
67
+ const attrThermInversion = 0xf00a;
68
+ const attrThermEcoModeCoolTemperature = 0xf00b;
69
+ const attrThermExtTemperatureCalibration = 0xf00c;
70
+ const attrFanCtrlControl = 0xf000;
71
+ const switchSensorUsed = ["Inner (IN)", "All (AL)", "Outer (OU)"];
72
+ const attrElCityMeterModelPreset = 0xf000;
73
+ const attrElCityMeterAddressPreset = 0xf001;
74
+ const attrElCityMeterMeasurementPreset = 0xf002;
75
+ const attrElCityMeterDateRelease = 0xf003;
76
+ const attrElCityMeterModelName = 0xf004;
77
+ const attrElCityMeterPasswordPreset = 0xf005;
78
+ const fzLocal = {
79
+ thermostat_custom_fw: {
80
+ cluster: "hvacThermostat",
81
+ type: ["attributeReport", "readResponse"],
82
+ convert: (model, msg, publish, options, meta) => {
83
+ const result = {};
84
+ if (msg.data[attrThermSensorUser] !== undefined) {
85
+ const lookup = { 0: "Inner (IN)", 1: "All (AL)", 2: "Outer (OU)" };
86
+ result.sensor = utils.getFromLookup(msg.data[attrThermSensorUser], lookup);
87
+ }
88
+ if (msg.data.minSetpointDeadBand !== undefined) {
89
+ let data;
90
+ if (model.model === model_r06) {
91
+ data = Number.parseFloat(msg.data.minSetpointDeadBand) / 10;
92
+ result.histeresis_temperature = data;
93
+ }
94
+ else {
95
+ data = Number.parseInt(msg.data.minSetpointDeadBand);
96
+ result.deadzone_temperature = data;
97
+ }
98
+ }
99
+ if (msg.data[attrThermFrostProtect] !== undefined) {
100
+ const data = Number.parseInt(msg.data[attrThermFrostProtect]) / 100;
101
+ result.frost_protect = data;
102
+ }
103
+ if (msg.data[attrThermHeatProtect] !== undefined) {
104
+ const data = Number.parseInt(msg.data[attrThermHeatProtect]) / 100;
105
+ result.heat_protect = data;
106
+ }
107
+ if (msg.data[attrThermEcoMode] !== undefined) {
108
+ result.eco_mode = msg.data[attrThermEcoMode] === 1 ? "On" : "Off";
109
+ }
110
+ if (msg.data[attrThermEcoModeCoolTemperature] !== undefined) {
111
+ const data = Number.parseInt(msg.data[attrThermEcoModeCoolTemperature]) / 100;
112
+ result.eco_mode_cool_temperature = data;
113
+ }
114
+ if (msg.data[attrThermEcoModeHeatTemperature] !== undefined) {
115
+ const data = Number.parseInt(msg.data[attrThermEcoModeHeatTemperature]) / 100;
116
+ result.eco_mode_heat_temperature = data;
117
+ }
118
+ if (msg.data[attrThermFrostProtectOnOff] !== undefined) {
119
+ result.frost_protect_on_off = msg.data[attrThermFrostProtectOnOff] === 1 ? "On" : "Off";
120
+ }
121
+ if (msg.data[attrThermLevel] !== undefined) {
122
+ const lookup = { 0: "Off", 1: "Low", 2: "Medium", 3: "High" };
123
+ result.brightness_level = utils.getFromLookup(msg.data[attrThermLevel], lookup);
124
+ }
125
+ if (msg.data[attrThermSound] !== undefined) {
126
+ result.sound = msg.data[attrThermSound] === 1 ? "On" : "Off";
127
+ }
128
+ if (msg.data[attrThermInversion] !== undefined) {
129
+ result.inversion = msg.data[attrThermInversion] === 1 ? "On" : "Off";
130
+ }
131
+ if (msg.data[attrThermScheduleMode] !== undefined) {
132
+ const lookup = { 0: "Off", 1: "5+2", 2: "6+1", 3: "7" };
133
+ result.schedule_mode = utils.getFromLookup(msg.data[attrThermScheduleMode], lookup);
134
+ }
135
+ if (msg.data[attrThermExtTemperatureCalibration] !== undefined) {
136
+ const data = Number.parseInt(msg.data[attrThermExtTemperatureCalibration]) / 10;
137
+ result.external_temperature_calibration = data;
138
+ }
139
+ return result;
140
+ },
141
+ },
142
+ thermostat_schedule: {
143
+ cluster: "hvacThermostat",
144
+ type: ["commandSetWeeklySchedule"],
145
+ convert: (model, msg, publish, options, meta) => {
146
+ const result = {};
147
+ const { data } = msg;
148
+ const daysOfWeekNums = [...Array.from(Array(7).keys()).filter((x) => (2 ** x) & data.dayofweek)];
149
+ // biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
150
+ const schedule = `${data.transitions.map((t) => `${String(Math.floor(t.transitionTime / 60)).padStart(2, "0")}:${String(t.transitionTime % 60).padStart(2, "0")}/${t.heatSetpoint / 100.0}°C`).join(" ")}`;
151
+ const daysOfWeek = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
152
+ return Object.fromEntries(daysOfWeekNums.map((d) => [`schedule_${daysOfWeek[d]}`, schedule]));
153
+ },
154
+ },
155
+ fancontrol_control: {
156
+ cluster: "hvacFanCtrl",
157
+ type: ["attributeReport", "readResponse"],
158
+ convert: (model, msg, publish, options, meta) => {
159
+ const result = {};
160
+ if (msg.data[attrFanCtrlControl] !== undefined) {
161
+ result.fan_control = msg.data[attrFanCtrlControl] === 1 ? "On" : "Off";
162
+ }
163
+ return result;
164
+ },
165
+ },
166
+ display_brightness: {
167
+ cluster: "genLevelCtrl",
168
+ type: ["attributeReport", "readResponse"],
169
+ convert: (model, msg, publish, options, meta) => {
170
+ const result = {};
171
+ if (msg.data.currentLevel !== undefined) {
172
+ const property = `brightness_${utils.getEndpointName(msg, model, meta)}`;
173
+ //logger.info('property: ' + property);
174
+ return { [property]: msg.data.currentLevel };
175
+ }
176
+ return result;
177
+ },
178
+ },
179
+ };
180
+ const tzLocal = {
181
+ display_brightness: {
182
+ key: ["brightness", "brightness_day", "brightness_night"],
183
+ options: [exposes.options.transition()],
184
+ convertSet: async (entity, key, value, meta) => {
185
+ await entity.command("genLevelCtrl", "moveToLevel", { level: value, transtime: 0 }, utils.getOptions(meta.mapped, entity));
186
+ return { state: { brightness: value } };
187
+ },
188
+ convertGet: async (entity, key, meta) => {
189
+ await entity.read("genLevelCtrl", ["currentLevel"]);
190
+ },
191
+ },
192
+ thermostat_sensor_used: {
193
+ key: ["sensor"],
194
+ convertSet: async (entity, key, value, meta) => {
195
+ const endpoint = meta.device.getEndpoint(1);
196
+ const lookup = { "Inner (IN)": 0, "All (AL)": 1, "Outer (OU)": 2 };
197
+ await endpoint.write("hvacThermostat", { [attrThermSensorUser]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
198
+ return {
199
+ state: { [key]: value },
200
+ };
201
+ },
202
+ convertGet: async (entity, key, meta) => {
203
+ await entity.read("hvacThermostat", [attrThermSensorUser]);
204
+ },
205
+ },
206
+ thermostat_deadzone: {
207
+ key: ["deadzone_temperature"],
208
+ convertSet: async (entity, key, value, meta) => {
209
+ const minSetpointDeadBand = Number.parseInt(value, 10);
210
+ await entity.write("hvacThermostat", { minSetpointDeadBand });
211
+ return { readAfterWriteTime: 250, state: { minSetpointDeadBand: value } };
212
+ },
213
+ convertGet: async (entity, key, meta) => {
214
+ await entity.read("hvacThermostat", ["minSetpointDeadBand"]);
215
+ },
216
+ },
217
+ thermostat_deadzone_10: {
218
+ key: ["histeresis_temperature"],
219
+ convertSet: async (entity, key, value, meta) => {
220
+ const minSetpointDeadBand = Number.parseFloat(value) * 10;
221
+ await entity.write("hvacThermostat", { minSetpointDeadBand });
222
+ return { readAfterWriteTime: 250, state: { minSetpointDeadBand: value } };
223
+ },
224
+ convertGet: async (entity, key, meta) => {
225
+ await entity.read("hvacThermostat", ["minSetpointDeadBand"]);
226
+ },
227
+ },
228
+ thermostat_frost_protect: {
229
+ key: ["frost_protect"],
230
+ convertSet: async (entity, key, value, meta) => {
231
+ if (!utils.isInRange(0, 10, Number(value)))
232
+ throw new Error(`Invalid value: ${value} (expected ${0} to ${10})`);
233
+ const frost_protect = Number.parseInt(value, 10) * 100;
234
+ await entity.write("hvacThermostat", { [attrThermFrostProtect]: { value: frost_protect, type: 0x29 } });
235
+ return { readAfterWriteTime: 250, state: { frost_protect: value } };
236
+ },
237
+ convertGet: async (entity, key, meta) => {
238
+ await entity.read("hvacThermostat", [attrThermFrostProtect]);
239
+ },
240
+ },
241
+ thermostat_heat_protect: {
242
+ key: ["heat_protect"],
243
+ convertSet: async (entity, key, value, meta) => {
244
+ if (!utils.isInRange(25, 70, Number(value)))
245
+ throw new Error(`Invalid value: ${value} (expected ${25} to ${70})`);
246
+ const heat_protect = Number.parseInt(value, 10) * 100;
247
+ await entity.write("hvacThermostat", { [attrThermHeatProtect]: { value: heat_protect, type: 0x29 } });
248
+ return { readAfterWriteTime: 250, state: { heat_protect: value } };
249
+ },
250
+ convertGet: async (entity, key, meta) => {
251
+ await entity.read("hvacThermostat", [attrThermHeatProtect]);
252
+ },
253
+ },
254
+ thermostat_setpoint_raise_lower: {
255
+ key: ["setpoint_raise_lower"],
256
+ convertSet: async (entity, key, value, meta) => {
257
+ if (!utils.isInRange(-5, 5, Number(value)))
258
+ throw new Error(`Invalid value: ${value} (expected ${-5} to ${5})`);
259
+ const setpoint_raise_lower = Number.parseInt(value, 10) * 10; //Step 0.1°C. 5°C - 50, 1°C - 10 etc.
260
+ await entity.command("hvacThermostat", "setpointRaiseLower", { mode: 0, amount: setpoint_raise_lower });
261
+ return { readAfterWriteTime: 250, state: { setpoint_raise_lower: value } };
262
+ },
263
+ },
264
+ fancontrol_control: {
265
+ key: ["fan_control"],
266
+ convertSet: async (entity, key, value, meta) => {
267
+ const fan_control = Number(value === "On");
268
+ await entity.write("hvacFanCtrl", { [attrFanCtrlControl]: { value: fan_control, type: 0x10 } });
269
+ return { readAfterWriteTime: 250, state: { fan_control: value } };
270
+ },
271
+ convertGet: async (entity, key, meta) => {
272
+ await entity.read("hvacFanCtrl", [attrFanCtrlControl]);
273
+ },
274
+ },
275
+ thermostat_eco_mode: {
276
+ key: ["eco_mode"],
277
+ convertSet: async (entity, key, value, meta) => {
278
+ const eco_mode = Number(value === "On");
279
+ await entity.write("hvacThermostat", { [attrThermEcoMode]: { value: eco_mode, type: 0x30 } });
280
+ return { readAfterWriteTime: 250, state: { eco_mode: value } };
281
+ },
282
+ convertGet: async (entity, key, meta) => {
283
+ await entity.read("hvacThermostat", [attrThermEcoMode]);
284
+ },
285
+ },
286
+ thermostat_eco_mode_cool_temperature: {
287
+ key: ["eco_mode_cool_temperature"],
288
+ convertSet: async (entity, key, value, meta) => {
289
+ if (!utils.isInRange(5, 45, Number(value)))
290
+ throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
291
+ const eco_mode_cool_temperature = Number.parseInt(value, 10) * 100;
292
+ await entity.write("hvacThermostat", { [attrThermEcoModeCoolTemperature]: { value: eco_mode_cool_temperature, type: 0x29 } });
293
+ return { readAfterWriteTime: 250, state: { eco_mode_cool_temperature: value } };
294
+ },
295
+ convertGet: async (entity, key, meta) => {
296
+ await entity.read("hvacThermostat", [attrThermEcoModeCoolTemperature]);
297
+ },
298
+ },
299
+ thermostat_eco_mode_heat_temperature: {
300
+ key: ["eco_mode_heat_temperature"],
301
+ convertSet: async (entity, key, value, meta) => {
302
+ if (!utils.isInRange(5, 45, Number(value)))
303
+ throw new Error(`Invalid value: ${value} (expected ${5} to ${45})`);
304
+ const eco_mode_heat_temperature = Number.parseInt(value, 10) * 100;
305
+ await entity.write("hvacThermostat", { [attrThermEcoModeHeatTemperature]: { value: eco_mode_heat_temperature, type: 0x29 } });
306
+ return { readAfterWriteTime: 250, state: { eco_mode_heat_temperature: value } };
307
+ },
308
+ convertGet: async (entity, key, meta) => {
309
+ await entity.read("hvacThermostat", [attrThermEcoModeHeatTemperature]);
310
+ },
311
+ },
312
+ thermostat_frost_protect_onoff: {
313
+ key: ["frost_protect_on_off"],
314
+ convertSet: async (entity, key, value, meta) => {
315
+ const frost_protect_on_off = Number(value === "On");
316
+ await entity.write("hvacThermostat", { [attrThermFrostProtectOnOff]: { value: frost_protect_on_off, type: 0x10 } });
317
+ return { readAfterWriteTime: 250, state: { frost_protect_on_off: value } };
318
+ },
319
+ convertGet: async (entity, key, meta) => {
320
+ await entity.read("hvacThermostat", [attrThermFrostProtectOnOff]);
321
+ },
322
+ },
323
+ thermostat_sound: {
324
+ key: ["sound"],
325
+ convertSet: async (entity, key, value, meta) => {
326
+ const sound = Number(value === "On");
327
+ await entity.write("hvacThermostat", { [attrThermSound]: { value: sound, type: 0x10 } });
328
+ return { readAfterWriteTime: 250, state: { sound: value } };
329
+ },
330
+ convertGet: async (entity, key, meta) => {
331
+ await entity.read("hvacThermostat", [attrThermSound]);
332
+ },
333
+ },
334
+ thermostat_brightness_level: {
335
+ key: ["brightness_level"],
336
+ convertSet: async (entity, key, value, meta) => {
337
+ const lookup = { Off: 0, Low: 1, Medium: 2, High: 3 };
338
+ await entity.write("hvacThermostat", { [attrThermLevel]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
339
+ return { state: { brightness_level: value } };
340
+ },
341
+ convertGet: async (entity, key, meta) => {
342
+ await entity.read("hvacThermostat", [attrThermLevel]);
343
+ },
344
+ },
345
+ thermostat_inversion: {
346
+ key: ["inversion"],
347
+ convertSet: async (entity, key, value, meta) => {
348
+ const inversion = Number(value === "On");
349
+ await entity.write("hvacThermostat", { [attrThermInversion]: { value: inversion, type: 0x10 } });
350
+ return { readAfterWriteTime: 250, state: { inversion: value } };
351
+ },
352
+ convertGet: async (entity, key, meta) => {
353
+ await entity.read("hvacThermostat", [attrThermInversion]);
354
+ },
355
+ },
356
+ thermostat_schedule_mode: {
357
+ key: ["schedule_mode"],
358
+ convertSet: async (entity, key, value, meta) => {
359
+ const lookup = { Off: 0, "5+2": 1, "6+1": 2, "7": 3 };
360
+ await entity.write("hvacThermostat", { [attrThermScheduleMode]: { value: utils.getFromLookup(value, lookup), type: 0x30 } });
361
+ return { state: { schedule_mode: value } };
362
+ },
363
+ convertGet: async (entity, key, meta) => {
364
+ await entity.read("hvacThermostat", [attrThermScheduleMode]);
365
+ },
366
+ },
367
+ thermostat_settings_reset: {
368
+ key: ["settings_reset"],
369
+ convertSet: async (entity, key, value, meta) => {
370
+ const settings_reset = Number(value === "Default");
371
+ await entity.write("hvacThermostat", { [attrThermSettingsReset]: { value: settings_reset, type: 0x10 } });
372
+ return { readAfterWriteTime: 250, state: { settings_reset: value } };
373
+ },
374
+ },
375
+ thermostat_ext_temperature_calibration: {
376
+ key: ["external_temperature_calibration"],
377
+ convertSet: async (entity, key, value, meta) => {
378
+ if (!utils.isInRange(-9, 9, Number(value)))
379
+ throw new Error(`Invalid value: ${value} (expected ${-9} to ${9})`);
380
+ const external_temperature_calibration = Number.parseInt(value, 10) * 10;
381
+ await entity.write("hvacThermostat", { [attrThermExtTemperatureCalibration]: { value: external_temperature_calibration, type: 0x28 } });
382
+ return { readAfterWriteTime: 250, state: { external_temperature_calibration: value } };
383
+ },
384
+ convertGet: async (entity, key, meta) => {
385
+ await entity.read("hvacThermostat", [attrThermExtTemperatureCalibration]);
386
+ },
387
+ },
388
+ };
389
+ const localFromZigbeeThermostat = [
390
+ fz.ignore_basic_report,
391
+ fz.thermostat,
392
+ fz.fan,
393
+ fz.namron_hvac_user_interface,
394
+ fz.thermostat_weekly_schedule,
395
+ fzLocal.thermostat_custom_fw,
396
+ fzLocal.thermostat_schedule,
397
+ fzLocal.display_brightness,
398
+ fzLocal.fancontrol_control,
399
+ ];
400
+ const localToZigbeeThermostat = [
401
+ tz.thermostat_local_temperature,
402
+ tz.thermostat_outdoor_temperature,
403
+ tz.thermostat_system_mode,
404
+ tz.thermostat_occupied_heating_setpoint,
405
+ tz.thermostat_running_state,
406
+ tz.thermostat_local_temperature_calibration,
407
+ tz.thermostat_min_heat_setpoint_limit,
408
+ tz.thermostat_max_heat_setpoint_limit,
409
+ tz.thermostat_programming_operation_mode,
410
+ tz.namron_thermostat_child_lock,
411
+ tz.thermostat_weekly_schedule,
412
+ tz.fan_mode,
413
+ tzLocal.display_brightness,
414
+ tzLocal.thermostat_sensor_used,
415
+ tzLocal.thermostat_deadzone,
416
+ tzLocal.thermostat_deadzone_10,
417
+ tzLocal.thermostat_setpoint_raise_lower,
418
+ tzLocal.thermostat_frost_protect,
419
+ tzLocal.thermostat_heat_protect,
420
+ tzLocal.thermostat_eco_mode,
421
+ tzLocal.thermostat_eco_mode_cool_temperature,
422
+ tzLocal.thermostat_eco_mode_heat_temperature,
423
+ tzLocal.thermostat_frost_protect_onoff,
424
+ tzLocal.thermostat_brightness_level,
425
+ tzLocal.thermostat_sound,
426
+ tzLocal.thermostat_inversion,
427
+ tzLocal.thermostat_schedule_mode,
428
+ tzLocal.thermostat_settings_reset,
429
+ tzLocal.thermostat_ext_temperature_calibration,
430
+ tzLocal.fancontrol_control,
431
+ ];
432
+ async function configureCommon(device, coordinatorEndpoint, definition) {
433
+ //logger.info(definition.model);
434
+ const endpoint1 = device.getEndpoint(1);
435
+ const endpoint2 = device.getEndpoint(2);
436
+ await endpoint1.read("hvacUserInterfaceCfg", ["keypadLockout"]);
437
+ await endpoint1.read("genLevelCtrl", ["currentLevel"]);
438
+ await endpoint2.read("genLevelCtrl", ["currentLevel"]);
439
+ await endpoint1.read("hvacThermostat", ["localTemp"]);
440
+ await endpoint1.read("hvacThermostat", ["outdoorTemp"]);
441
+ await endpoint1.read("hvacThermostat", ["absMinHeatSetpointLimit"]);
442
+ await endpoint1.read("hvacThermostat", ["absMaxHeatSetpointLimit"]);
443
+ await endpoint1.read("hvacThermostat", ["minHeatSetpointLimit"]);
444
+ await endpoint1.read("hvacThermostat", ["maxHeatSetpointLimit"]);
445
+ await endpoint1.read("hvacThermostat", ["localTemperatureCalibration"]);
446
+ await endpoint1.read("hvacThermostat", ["occupiedHeatingSetpoint"]);
447
+ await endpoint1.read("hvacThermostat", ["programingOperMode"]);
448
+ await endpoint1.read("hvacThermostat", ["systemMode"]);
449
+ await endpoint1.read("hvacThermostat", ["runningState"]);
450
+ await endpoint1.read("hvacThermostat", ["minSetpointDeadBand"]);
451
+ await endpoint1.read("hvacThermostat", [attrThermSensorUser]);
452
+ await endpoint1.read("hvacThermostat", [attrThermFrostProtect]);
453
+ await endpoint1.read("hvacThermostat", [attrThermHeatProtect]);
454
+ await endpoint1.read("hvacThermostat", [attrThermEcoMode]);
455
+ await endpoint1.read("hvacThermostat", [attrThermEcoModeCoolTemperature]);
456
+ await endpoint1.read("hvacThermostat", [attrThermEcoModeHeatTemperature]);
457
+ await endpoint1.read("hvacThermostat", [attrThermFrostProtectOnOff]);
458
+ await endpoint1.read("hvacThermostat", [attrThermScheduleMode]);
459
+ await endpoint1.read("hvacThermostat", [attrThermSound]);
460
+ await endpoint1.read("hvacThermostat", [attrThermLevel]);
461
+ await endpoint1.read("hvacThermostat", [attrThermInversion]);
462
+ await endpoint1.read("hvacThermostat", [attrThermExtTemperatureCalibration]);
463
+ await endpoint1.read("hvacFanCtrl", ["fanMode"]);
464
+ await endpoint1.read("hvacFanCtrl", [attrFanCtrlControl]);
465
+ await reporting.bind(endpoint1, coordinatorEndpoint, ["hvacThermostat", "hvacUserInterfaceCfg", "hvacFanCtrl"]);
466
+ if (definition.model === model_r03 || definition.model === model_r04) {
467
+ await reporting.bind(endpoint1, coordinatorEndpoint, ["genLevelCtrl"]);
468
+ const payloadCurrentLevel = [
469
+ { attribute: { ID: 0x0000, type: 0x20 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
470
+ ];
471
+ await endpoint1.configureReporting("genLevelCtrl", payloadCurrentLevel);
472
+ if (definition.model === model_r03) {
473
+ await reporting.bind(endpoint2, coordinatorEndpoint, ["genLevelCtrl"]);
474
+ await endpoint2.configureReporting("genLevelCtrl", payloadCurrentLevel);
475
+ }
476
+ }
477
+ await reporting.thermostatTemperature(endpoint1, { min: 0, max: 3600, change: 0 });
478
+ await reporting.thermostatOccupiedHeatingSetpoint(endpoint1, { min: 0, max: 3600, change: 0 });
479
+ await reporting.thermostatRunningState(endpoint1, { min: 0, max: 3600, change: 0 });
480
+ await reporting.thermostatSystemMode(endpoint1, { min: 0, max: 3600, change: 0 });
481
+ await reporting.thermostatTemperatureCalibration(endpoint1, { min: 0, max: 3600, change: 0 });
482
+ await reporting.thermostatKeypadLockMode(endpoint1, { min: 0, max: 3600, change: 0 });
483
+ const payload_oper_mode = [{ attribute: "programingOperMode", minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
484
+ await endpoint1.configureReporting("hvacThermostat", payload_oper_mode);
485
+ const payload_sensor_used = [
486
+ { attribute: { ID: attrThermSensorUser, type: 0x30 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
487
+ ];
488
+ await endpoint1.configureReporting("hvacThermostat", payload_sensor_used);
489
+ const payload_deadzone = [{ attribute: { ID: 0x0019, type: 0x28 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
490
+ await endpoint1.configureReporting("hvacThermostat", payload_deadzone);
491
+ const payload_min = [{ attribute: { ID: 0x0015, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
492
+ await endpoint1.configureReporting("hvacThermostat", payload_min);
493
+ const payload_max = [{ attribute: { ID: 0x0016, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
494
+ await endpoint1.configureReporting("hvacThermostat", payload_max);
495
+ if (definition.model !== model_r01 && definition.model !== model_r06) {
496
+ const payload_outdoor = [{ attribute: { ID: 0x0001, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 }];
497
+ await endpoint1.configureReporting("hvacThermostat", payload_outdoor);
498
+ }
499
+ const payload_frost_protect = [
500
+ {
501
+ attribute: { ID: attrThermFrostProtect, type: 0x29 },
502
+ minimumReportInterval: 0,
503
+ maximumReportInterval: 3600,
504
+ reportableChange: 0,
505
+ },
506
+ ];
507
+ await endpoint1.configureReporting("hvacThermostat", payload_frost_protect);
508
+ const payload_heat_protect = [
509
+ { attribute: { ID: attrThermHeatProtect, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
510
+ ];
511
+ await endpoint1.configureReporting("hvacThermostat", payload_heat_protect);
512
+ if (definition.model === model_r03 || definition.model === model_r04 || definition.model === model_r07) {
513
+ const payload_eco_mode = [
514
+ { attribute: { ID: attrThermEcoMode, type: 0x30 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
515
+ ];
516
+ await endpoint1.configureReporting("hvacThermostat", payload_eco_mode);
517
+ const payload_eco_mode_heat_temp = [
518
+ {
519
+ attribute: { ID: attrThermEcoModeHeatTemperature, type: 0x29 },
520
+ minimumReportInterval: 0,
521
+ maximumReportInterval: 3600,
522
+ reportableChange: 0,
523
+ },
524
+ ];
525
+ await endpoint1.configureReporting("hvacThermostat", payload_eco_mode_heat_temp);
526
+ if (definition.model === model_r07) {
527
+ const payload_eco_mode_cool_temp = [
528
+ {
529
+ attribute: { ID: attrThermEcoModeCoolTemperature, type: 0x29 },
530
+ minimumReportInterval: 0,
531
+ maximumReportInterval: 3600,
532
+ reportableChange: 0,
533
+ },
534
+ ];
535
+ await endpoint1.configureReporting("hvacThermostat", payload_eco_mode_cool_temp);
536
+ const payload_fan_control = [
537
+ { attribute: { ID: attrFanCtrlControl, type: 0x10 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
538
+ ];
539
+ await endpoint1.configureReporting("hvacFanCtrl", payload_fan_control);
540
+ await reporting.fanMode(endpoint1, { min: 0, max: 3600, change: 0 });
541
+ }
542
+ }
543
+ if (definition.model === model_r06) {
544
+ const payload_frost_protect_onoff = [
545
+ { attribute: { ID: attrThermFrostProtectOnOff, type: 0x10 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
546
+ ];
547
+ await endpoint1.configureReporting("hvacThermostat", payload_frost_protect_onoff);
548
+ const payload_sound = [
549
+ { attribute: { ID: attrThermSound, type: 0x10 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
550
+ ];
551
+ await endpoint1.configureReporting("hvacThermostat", payload_sound);
552
+ const payload_inversion = [
553
+ { attribute: { ID: attrThermInversion, type: 0x10 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
554
+ ];
555
+ await endpoint1.configureReporting("hvacThermostat", payload_inversion);
556
+ const payload_level = [
557
+ { attribute: { ID: attrThermLevel, type: 0x30 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
558
+ ];
559
+ await endpoint1.configureReporting("hvacThermostat", payload_level);
560
+ const payload_schedule_mode = [
561
+ { attribute: { ID: attrThermScheduleMode, type: 0x30 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
562
+ ];
563
+ await endpoint1.configureReporting("hvacThermostat", payload_schedule_mode);
564
+ }
565
+ if (definition.model === model_r08) {
566
+ const payload_eco_mode = [
567
+ { attribute: { ID: attrThermEcoMode, type: 0x30 }, minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0 },
568
+ ];
569
+ await endpoint1.configureReporting("hvacThermostat", payload_eco_mode);
570
+ const payload_ext_temp_calibration = [
571
+ {
572
+ attribute: { ID: attrThermExtTemperatureCalibration, type: 0x28 },
573
+ minimumReportInterval: 0,
574
+ maximumReportInterval: 3600,
575
+ reportableChange: 0,
576
+ },
577
+ ];
578
+ await endpoint1.configureReporting("hvacThermostat", payload_ext_temp_calibration);
579
+ }
580
+ }
581
+ const electricityMeterExtend = {
582
+ elMeter: () => {
583
+ const exposes = [
584
+ e.numeric("energy_tier_1", ea.STATE_GET).withUnit("kWh").withDescription("Energy consumed at Tier 1"),
585
+ e.numeric("energy_tier_2", ea.STATE_GET).withUnit("kWh").withDescription("Energy consumed at Tier 2"),
586
+ e.numeric("energy_tier_3", ea.STATE_GET).withUnit("kWh").withDescription("Energy consumed at Tier 3"),
587
+ e.numeric("energy_tier_4", ea.STATE_GET).withUnit("kWh").withDescription("Energy consumed at Tier 4"),
588
+ e.text("model_name", ea.STATE_GET).withDescription("Meter Model Name"),
589
+ e.text("serial_number", ea.STATE_GET).withDescription("Meter Serial Number"),
590
+ e.text("date_release", ea.STATE_GET).withDescription("Meter Date Release"),
591
+ e.numeric("battery_life", ea.STATE_GET).withUnit("%").withDescription("Battery Life"),
592
+ e.binary("tamper", ea.STATE, true, false).withDescription("Tamper"),
593
+ e.binary("battery_low", ea.STATE, true, false).withDescription("Battery Low"),
594
+ e.numeric("device_address_preset", ea.STATE_SET).withDescription("Device Address").withValueMin(1).withValueMax(9999999),
595
+ e.text("device_password_preset", ea.STATE_SET).withDescription("Meter Password"),
596
+ e.numeric("device_measurement_preset", ea.ALL).withDescription("Measurement Period").withValueMin(1).withValueMax(255),
597
+ ];
598
+ const toZigbee = [
599
+ {
600
+ key: ["energy_tier_1", "energy_tier_2", "energy_tier_3", "energy_tier_4"],
601
+ convertGet: async (entity, key, meta) => {
602
+ await entity.read("seMetering", [
603
+ "currentTier1SummDelivered",
604
+ "currentTier2SummDelivered",
605
+ "currentTier3SummDelivered",
606
+ "currentTier4SummDelivered",
607
+ ]);
608
+ },
609
+ convertSet: async (entity, key, value, meta) => {
610
+ return await null;
611
+ },
612
+ },
613
+ {
614
+ key: ["model_name"],
615
+ convertGet: async (entity, key, meta) => {
616
+ await entity.read("seMetering", [attrElCityMeterModelName]);
617
+ },
618
+ convertSet: async (entity, key, value, meta) => {
619
+ return await null;
620
+ },
621
+ },
622
+ {
623
+ key: ["serial_number"],
624
+ convertGet: async (entity, key, meta) => {
625
+ await entity.read("seMetering", ["meterSerialNumber"]);
626
+ },
627
+ convertSet: async (entity, key, value, meta) => {
628
+ return await null;
629
+ },
630
+ },
631
+ {
632
+ key: ["date_release"],
633
+ convertGet: async (entity, key, meta) => {
634
+ await entity.read("seMetering", [attrElCityMeterDateRelease]);
635
+ },
636
+ convertSet: async (entity, key, value, meta) => {
637
+ return await null;
638
+ },
639
+ },
640
+ {
641
+ key: ["battery_life"],
642
+ convertGet: async (entity, key, meta) => {
643
+ await entity.read("seMetering", ["remainingBattLife"]);
644
+ },
645
+ convertSet: async (entity, key, value, meta) => {
646
+ return await null;
647
+ },
648
+ },
649
+ {
650
+ key: ["device_address_preset"],
651
+ convertSet: async (entity, key, value, meta) => {
652
+ const device_address_preset = Number.parseInt(value, 10);
653
+ await entity.write("seMetering", { [attrElCityMeterAddressPreset]: { value: device_address_preset, type: 0x23 } });
654
+ return { readAfterWriteTime: 250, state: { device_address_preset: value } };
655
+ },
656
+ },
657
+ {
658
+ key: ["device_password_preset"],
659
+ convertSet: async (entity, key, value, meta) => {
660
+ const device_password_preset = value.toString();
661
+ await entity.write("seMetering", { [attrElCityMeterPasswordPreset]: { value: device_password_preset, type: 0x41 } });
662
+ return { readAfterWriteTime: 250, state: { device_password_preset: value } };
663
+ },
664
+ },
665
+ {
666
+ key: ["device_measurement_preset"],
667
+ convertSet: async (entity, key, value, meta) => {
668
+ const device_measurement_preset = Number.parseInt(value, 10);
669
+ await entity.write("seMetering", { [attrElCityMeterMeasurementPreset]: { value: device_measurement_preset, type: 0x20 } });
670
+ return { readAfterWriteTime: 250, state: { device_measurement_preset: value } };
671
+ },
672
+ convertGet: async (entity, key, meta) => {
673
+ await entity.read("seMetering", [attrElCityMeterMeasurementPreset]);
674
+ },
675
+ },
676
+ ];
677
+ const fromZigbee = [
678
+ {
679
+ cluster: "seMetering",
680
+ type: ["attributeReport", "readResponse"],
681
+ convert: (model, msg, publish, options, meta) => {
682
+ const result = {};
683
+ if (msg.data.divisor !== undefined) {
684
+ const energyDivisor = Number.parseInt(msg.data.divisor);
685
+ globalStore.putValue(meta.device, "energyDivisor", energyDivisor);
686
+ result.e_divisor = energyDivisor;
687
+ }
688
+ return result;
689
+ },
690
+ },
691
+ {
692
+ cluster: "seMetering",
693
+ type: ["attributeReport", "readResponse"],
694
+ convert: (model, msg, publish, options, meta) => {
695
+ const result = {};
696
+ if (msg.data.multiplier !== undefined) {
697
+ const energyMultiplier = Number.parseInt(msg.data.multiplier);
698
+ globalStore.putValue(meta.device, "energyMultiplier", energyMultiplier);
699
+ result.e_multiplier = energyMultiplier;
700
+ }
701
+ return result;
702
+ },
703
+ },
704
+ {
705
+ cluster: "seMetering",
706
+ type: ["attributeReport", "readResponse"],
707
+ convert: (model, msg, publish, options, meta) => {
708
+ const result = {};
709
+ if (msg.data.currentTier1SummDelivered !== undefined) {
710
+ let energyDivisor = globalStore.getValue(meta.device, "energyDivisor");
711
+ let energyMultiplier = globalStore.getValue(meta.device, "energyMultiplier");
712
+ if (energyDivisor === undefined) {
713
+ energyDivisor = 1;
714
+ }
715
+ if (energyMultiplier === undefined) {
716
+ energyMultiplier = 1;
717
+ }
718
+ const data = msg.data.currentTier1SummDelivered;
719
+ result.energy_tier_1 = (Number.parseInt(data) / energyDivisor) * energyMultiplier;
720
+ }
721
+ return result;
722
+ },
723
+ },
724
+ {
725
+ cluster: "seMetering",
726
+ type: ["attributeReport", "readResponse"],
727
+ convert: (model, msg, publish, options, meta) => {
728
+ const result = {};
729
+ if (msg.data.currentTier2SummDelivered !== undefined) {
730
+ let energyDivisor = globalStore.getValue(meta.device, "energyDivisor");
731
+ let energyMultiplier = globalStore.getValue(meta.device, "energyMultiplier");
732
+ if (energyDivisor === undefined) {
733
+ energyDivisor = 1;
734
+ }
735
+ if (energyMultiplier === undefined) {
736
+ energyMultiplier = 1;
737
+ }
738
+ const data = msg.data.currentTier2SummDelivered;
739
+ result.energy_tier_2 = (Number.parseInt(data) / energyDivisor) * energyMultiplier;
740
+ }
741
+ return result;
742
+ },
743
+ },
744
+ {
745
+ cluster: "seMetering",
746
+ type: ["attributeReport", "readResponse"],
747
+ convert: (model, msg, publish, options, meta) => {
748
+ const result = {};
749
+ if (msg.data.currentTier3SummDelivered !== undefined) {
750
+ let energyDivisor = globalStore.getValue(meta.device, "energyDivisor");
751
+ let energyMultiplier = globalStore.getValue(meta.device, "energyMultiplier");
752
+ if (energyDivisor === undefined) {
753
+ energyDivisor = 1;
754
+ }
755
+ if (energyMultiplier === undefined) {
756
+ energyMultiplier = 1;
757
+ }
758
+ const data = msg.data.currentTier3SummDelivered;
759
+ result.energy_tier_3 = (Number.parseInt(data) / energyDivisor) * energyMultiplier;
760
+ }
761
+ return result;
762
+ },
763
+ },
764
+ {
765
+ cluster: "seMetering",
766
+ type: ["attributeReport", "readResponse"],
767
+ convert: (model, msg, publish, options, meta) => {
768
+ const result = {};
769
+ if (msg.data.currentTier4SummDelivered !== undefined) {
770
+ let energyDivisor = globalStore.getValue(meta.device, "energyDivisor");
771
+ let energyMultiplier = globalStore.getValue(meta.device, "energyMultiplier");
772
+ if (energyDivisor === undefined) {
773
+ energyDivisor = 1;
774
+ }
775
+ if (energyMultiplier === undefined) {
776
+ energyMultiplier = 1;
777
+ }
778
+ const data = msg.data.currentTier4SummDelivered;
779
+ result.energy_tier_4 = (Number.parseInt(data) / energyDivisor) * energyMultiplier;
780
+ }
781
+ return result;
782
+ },
783
+ },
784
+ {
785
+ cluster: "seMetering",
786
+ type: ["attributeReport", "readResponse"],
787
+ convert: (model, msg, publish, options, meta) => {
788
+ const result = {};
789
+ if (msg.data[attrElCityMeterModelName] !== undefined) {
790
+ const data = msg.data[attrElCityMeterModelName];
791
+ result.model_name = data.toString();
792
+ }
793
+ return result;
794
+ },
795
+ },
796
+ {
797
+ cluster: "seMetering",
798
+ type: ["attributeReport", "readResponse"],
799
+ convert: (model, msg, publish, options, meta) => {
800
+ const result = {};
801
+ if (msg.data.meterSerialNumber !== undefined) {
802
+ const data = msg.data.meterSerialNumber;
803
+ result.serial_number = data.toString();
804
+ }
805
+ return result;
806
+ },
807
+ },
808
+ {
809
+ cluster: "seMetering",
810
+ type: ["attributeReport", "readResponse"],
811
+ convert: (model, msg, publish, options, meta) => {
812
+ const result = {};
813
+ if (msg.data[attrElCityMeterDateRelease] !== undefined) {
814
+ const data = msg.data[attrElCityMeterDateRelease];
815
+ result.date_release = data.toString();
816
+ }
817
+ return result;
818
+ },
819
+ },
820
+ {
821
+ cluster: "seMetering",
822
+ type: ["attributeReport", "readResponse"],
823
+ convert: (model, msg, publish, options, meta) => {
824
+ const result = {};
825
+ if (msg.data.status !== undefined) {
826
+ const data = msg.data.status;
827
+ const value = Number.parseInt(data);
828
+ return {
829
+ battery_low: (value & (1 << 1)) > 0,
830
+ tamper: (value & (1 << 2)) > 0,
831
+ };
832
+ }
833
+ return result;
834
+ },
835
+ },
836
+ {
837
+ cluster: "seMetering",
838
+ type: ["attributeReport", "readResponse"],
839
+ convert: (model, msg, publish, options, meta) => {
840
+ const result = {};
841
+ if (msg.data.remainingBattLife !== undefined) {
842
+ const data = Number.parseInt(msg.data.remainingBattLife);
843
+ result.battery_life = data;
844
+ }
845
+ return result;
846
+ },
847
+ },
848
+ {
849
+ cluster: "seMetering",
850
+ type: ["readResponse"],
851
+ convert: (model, msg, publish, options, meta) => {
852
+ const result = {};
853
+ if (msg.data[attrElCityMeterMeasurementPreset] !== undefined) {
854
+ const data = Number.parseInt(msg.data[attrElCityMeterMeasurementPreset]);
855
+ result.device_measurement_preset = data;
856
+ }
857
+ return result;
858
+ },
859
+ },
860
+ ];
861
+ return {
862
+ exposes,
863
+ fromZigbee,
864
+ toZigbee,
865
+ isModernExtend: true,
866
+ };
867
+ },
868
+ };
869
+ function waterPreset() {
870
+ const exposes = [
871
+ e
872
+ .composite("preset", "preset", ea.SET)
873
+ .withFeature(e
874
+ .numeric("hot_water_preset", ea.SET)
875
+ .withValueMin(0)
876
+ .withValueMax(99999999)
877
+ .withValueStep(1)
878
+ .withUnit("L")
879
+ .withDescription("Preset hot water"))
880
+ .withFeature(e
881
+ .numeric("cold_water_preset", ea.SET)
882
+ .withValueMin(0)
883
+ .withValueMax(99999999)
884
+ .withValueStep(1)
885
+ .withUnit("L")
886
+ .withDescription("Preset cold water"))
887
+ .withFeature(e
888
+ .numeric("step_water_preset", ea.SET)
889
+ .withValueMin(1)
890
+ .withValueMax(100)
891
+ .withValueStep(1)
892
+ .withUnit("L")
893
+ .withDescription("Preset step water")),
894
+ ];
895
+ const toZigbee = [
896
+ {
897
+ key: ["preset"],
898
+ convertSet: async (entity, key, value, meta) => {
899
+ const endpoint = meta.device.getEndpoint(3);
900
+ const values = {
901
+ // biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
902
+ hot_water: value.hot_water_preset,
903
+ // biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
904
+ cold_water: value.cold_water_preset,
905
+ // biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
906
+ step_water: value.step_water_preset,
907
+ };
908
+ if (values.hot_water !== undefined && values.hot_water >= 0) {
909
+ const hot_water_preset = Number.parseInt(values.hot_water);
910
+ await endpoint.write("seMetering", { 61440: { value: hot_water_preset, type: 0x23 } });
911
+ }
912
+ if (values.cold_water !== undefined && values.cold_water >= 0) {
913
+ const cold_water_preset = Number.parseInt(values.cold_water);
914
+ await endpoint.write("seMetering", { 61441: { value: cold_water_preset, type: 0x23 } });
915
+ }
916
+ if (values.step_water !== undefined && values.step_water >= 0) {
917
+ const step_water_preset = Number.parseInt(values.step_water);
918
+ await endpoint.write("seMetering", { 61442: { value: step_water_preset, type: 0x21 } });
919
+ }
920
+ },
921
+ },
922
+ ];
923
+ return { toZigbee, exposes, isModernExtend: true };
924
+ }
925
+ exports.definitions = [
926
+ {
927
+ zigbeeModel: ["Tuya_CO2Sensor_r01"],
928
+ model: "SLACKY_DIY_CO2_SENSOR_R01",
929
+ vendor: "Slacky-DIY",
930
+ description: "Tuya CO2 sensor with custom Firmware",
931
+ extend: [m.co2({ reporting: co2Reporting })],
932
+ ota: true,
933
+ },
934
+ {
935
+ zigbeeModel: ["Watermeter_TLSR8258"],
936
+ model: "Watermeter_TLSR8258",
937
+ vendor: "Slacky-DIY",
938
+ description: "Water Meter",
939
+ configure: async (device, coordinatorEndpoint, logger) => {
940
+ const thirdEndpoint = device.getEndpoint(3);
941
+ await thirdEndpoint.read("seMetering", [0xf000, 0xf001, 0xf002]);
942
+ },
943
+ extend: [
944
+ m.deviceEndpoints({
945
+ endpoints: {
946
+ "1": 1,
947
+ "2": 2,
948
+ "3": 3,
949
+ "4": 4,
950
+ "5": 5,
951
+ },
952
+ }),
953
+ m.iasZoneAlarm({ zoneType: "water_leak", zoneAttributes: ["alarm_1"] }),
954
+ m.battery({
955
+ voltage: true,
956
+ voltageReporting: true,
957
+ percentageReportingConfig: batteryReporting,
958
+ voltageReportingConfig: batteryReporting,
959
+ }),
960
+ m.enumLookup({
961
+ name: "switch_actions",
962
+ endpointName: "4",
963
+ lookup: { on_off: 0, off_on: 1, toggle: 2 },
964
+ cluster: "genOnOffSwitchCfg",
965
+ attribute: "switchActions",
966
+ description: "Actions switch 1",
967
+ }),
968
+ m.enumLookup({
969
+ name: "switch_actions",
970
+ endpointName: "5",
971
+ lookup: { on_off: 0, off_on: 1, toggle: 2 },
972
+ cluster: "genOnOffSwitchCfg",
973
+ attribute: "switchActions",
974
+ description: "Actions switch 2",
975
+ }),
976
+ m.numeric({
977
+ name: "volume",
978
+ endpointNames: ["1"],
979
+ access: "STATE_GET",
980
+ cluster: "seMetering",
981
+ attribute: "currentSummDelivered",
982
+ reporting: { min: 0, max: 300, change: 0 },
983
+ unit: "L",
984
+ description: "Hot water",
985
+ }),
986
+ m.numeric({
987
+ name: "volume",
988
+ endpointNames: ["2"],
989
+ access: "STATE_GET",
990
+ cluster: "seMetering",
991
+ attribute: "currentSummDelivered",
992
+ reporting: { min: 0, max: 300, change: 0 },
993
+ unit: "L",
994
+ description: "Cold water",
995
+ }),
996
+ waterPreset(),
997
+ ],
998
+ ota: true,
999
+ meta: { multiEndpoint: true },
1000
+ },
1001
+ {
1002
+ zigbeeModel: ["Smoke_Sensor_TLSR8258"],
1003
+ model: "Smoke Sensor TLSR8258",
1004
+ vendor: "Slacky-DIY",
1005
+ description: "Smoke Sensor on Rubezh IP 212-50M2 base",
1006
+ extend: [
1007
+ m.iasZoneAlarm({ zoneType: "smoke", zoneAttributes: ["alarm_1", "tamper", "battery_low"] }),
1008
+ m.battery({
1009
+ voltage: true,
1010
+ voltageReporting: true,
1011
+ percentageReportingConfig: batteryReporting,
1012
+ voltageReportingConfig: batteryReporting,
1013
+ }),
1014
+ m.commandsOnOff(),
1015
+ m.enumLookup({
1016
+ access: "STATE",
1017
+ name: "switch_type",
1018
+ lookup: { toggle: 0 },
1019
+ cluster: "genOnOffSwitchCfg",
1020
+ attribute: "switchType",
1021
+ description: "Type switch",
1022
+ }),
1023
+ m.enumLookup({
1024
+ name: "switch_actions",
1025
+ lookup: { on_off: 0, off_on: 1, toggle: 2 },
1026
+ cluster: "genOnOffSwitchCfg",
1027
+ attribute: "switchActions",
1028
+ description: "Actions switch",
1029
+ }),
1030
+ ],
1031
+ ota: true,
1032
+ },
1033
+ {
1034
+ zigbeeModel: ["ElectricityMeter_DIY"],
1035
+ model: "Electricity Meter TLSR8258",
1036
+ vendor: "Slacky-DIY",
1037
+ description: "Electricity Meter via optical port",
1038
+ configure: async (device, coordinatorEndpoint, logger) => {
1039
+ const endpoint1 = device.getEndpoint(1);
1040
+ await endpoint1.read("seMetering", ["remainingBattLife", "status", attrElCityMeterMeasurementPreset]);
1041
+ await endpoint1.read("seMetering", ["divisor"]);
1042
+ await endpoint1.read("seMetering", ["multiplier"]);
1043
+ await endpoint1.read("seMetering", ["currentTier1SummDelivered"]);
1044
+ await endpoint1.read("seMetering", ["currentTier2SummDelivered"]);
1045
+ await endpoint1.read("seMetering", ["currentTier3SummDelivered"]);
1046
+ await endpoint1.read("seMetering", ["currentTier4SummDelivered"]);
1047
+ await endpoint1.read("seMetering", ["currentSummDelivered"]);
1048
+ await endpoint1.read("seMetering", ["meterSerialNumber"]);
1049
+ await endpoint1.read("seMetering", [attrElCityMeterMeasurementPreset]);
1050
+ await endpoint1.read("seMetering", [attrElCityMeterModelName]);
1051
+ // await endpoint1.read("haElectricalMeasurement", ["acVoltageDivisor"]);
1052
+ // await endpoint1.read("haElectricalMeasurement", ["acVoltageMultiplier"]);
1053
+ // await endpoint1.read("haElectricalMeasurement", ["rmsVoltage"]);
1054
+ // await endpoint1.read("haElectricalMeasurement", ["acCurrentDivisor"]);
1055
+ // await endpoint1.read("haElectricalMeasurement", ["acCurrentMultiplier"]);
1056
+ // await endpoint1.read("haElectricalMeasurement", ["instantaneousLineCurrent"]);
1057
+ // await endpoint1.read("haElectricalMeasurement", ["acPowerDivisor"]);
1058
+ // await endpoint1.read("haElectricalMeasurement", ["acPowerMultiplier"]);
1059
+ // await endpoint1.read("haElectricalMeasurement", ["apparentPower"]);
1060
+ await reporting.bind(endpoint1, coordinatorEndpoint, ["seMetering", "haElectricalMeasurement", "genDeviceTempCfg"]);
1061
+ const payload_tier1 = [{ attribute: { ID: 0x0100, type: 0x25 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 }];
1062
+ await endpoint1.configureReporting("seMetering", payload_tier1);
1063
+ const payload_tier2 = [{ attribute: { ID: 0x0102, type: 0x25 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 }];
1064
+ await endpoint1.configureReporting("seMetering", payload_tier2);
1065
+ const payload_tier3 = [{ attribute: { ID: 0x0104, type: 0x25 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 }];
1066
+ await endpoint1.configureReporting("seMetering", payload_tier3);
1067
+ const payload_tier4 = [{ attribute: { ID: 0x0106, type: 0x25 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 }];
1068
+ await endpoint1.configureReporting("seMetering", payload_tier4);
1069
+ await reporting.currentSummDelivered(endpoint1, { min: 0, max: 300, change: 0 });
1070
+ const payload_status = [{ attribute: { ID: 0x0200, type: 0x18 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 }];
1071
+ await endpoint1.configureReporting("seMetering", payload_status);
1072
+ const payload_battery_life = [
1073
+ { attribute: { ID: 0x0201, type: 0x20 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 },
1074
+ ];
1075
+ await endpoint1.configureReporting("seMetering", payload_battery_life);
1076
+ const payload_serial_number = [
1077
+ { attribute: { ID: 0x0308, type: 0x41 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 },
1078
+ ];
1079
+ await endpoint1.configureReporting("seMetering", payload_serial_number);
1080
+ const payload_date_release = [
1081
+ { attribute: { ID: attrElCityMeterDateRelease, type: 0x41 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 },
1082
+ ];
1083
+ await endpoint1.configureReporting("seMetering", payload_date_release);
1084
+ const payload_model_name = [
1085
+ { attribute: { ID: attrElCityMeterModelName, type: 0x41 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 },
1086
+ ];
1087
+ await endpoint1.configureReporting("seMetering", payload_model_name);
1088
+ // await reporting.rmsVoltage(endpoint1, {min: 0, max: 300, change: 0});
1089
+ // const payload_current = [
1090
+ // {attribute: {ID: 0x0501, type: 0x21}, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0},
1091
+ // ];
1092
+ // await endpoint1.configureReporting("haElectricalMeasurement", payload_current);
1093
+ // await reporting.apparentPower(endpoint1, {min: 0, max: 300, change: 0});
1094
+ const payload_temperature = [
1095
+ { attribute: { ID: 0x0000, type: 0x29 }, minimumReportInterval: 0, maximumReportInterval: 300, reportableChange: 0 },
1096
+ ];
1097
+ await endpoint1.configureReporting("genDeviceTempCfg", payload_temperature);
1098
+ },
1099
+ extend: [
1100
+ m.deviceTemperature(),
1101
+ m.electricityMeter(),
1102
+ electricityMeterExtend.elMeter(),
1103
+ m.enumLookup({
1104
+ name: "device_model_preset",
1105
+ lookup: {
1106
+ "No Device": 0,
1107
+ "KASKAD-1-MT (MIRTEK)": 1,
1108
+ "KASKAD-11-C1": 2,
1109
+ "MERCURY-206": 3,
1110
+ "ENERGOMERA-CE102M": 4,
1111
+ "ENERGOMERA-CE208BY": 5,
1112
+ "NEVA-MT124": 6,
1113
+ "NARTIS-100": 7,
1114
+ },
1115
+ cluster: "seMetering",
1116
+ attribute: { ID: attrElCityMeterModelPreset, type: 0x30 },
1117
+ description: "Device Model",
1118
+ }),
1119
+ ],
1120
+ ota: true,
1121
+ },
1122
+ {
1123
+ zigbeeModel: ["Tuya_Thermostat_r01"],
1124
+ model: "THERM_SLACKY_DIY_R01",
1125
+ vendor: "Slacky-DIY",
1126
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1127
+ endpoint: (device) => {
1128
+ return { day: 1, night: 2 };
1129
+ },
1130
+ fromZigbee: localFromZigbeeThermostat,
1131
+ toZigbee: localToZigbeeThermostat,
1132
+ configure: configureCommon,
1133
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1134
+ exposes: [
1135
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1136
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1137
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1138
+ e
1139
+ .numeric("deadzone_temperature", ea.ALL)
1140
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1141
+ .withUnit("°C")
1142
+ .withValueMin(1)
1143
+ .withValueMax(5)
1144
+ .withValueStep(1),
1145
+ e
1146
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1147
+ .withDescription("Maximum Heating set point limit")
1148
+ .withUnit("°C")
1149
+ .withValueMin(15)
1150
+ .withValueMax(45)
1151
+ .withValueStep(1),
1152
+ e
1153
+ .climate()
1154
+ .withLocalTemperature()
1155
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 1)
1156
+ .withLocalTemperatureCalibration(-9, 9, 1)
1157
+ .withSystemMode(["off", "heat"])
1158
+ .withRunningState(["idle", "heat"], ea.STATE)
1159
+ .withWeeklySchedule(["heat"], ea.ALL),
1160
+ e.text("schedule_monday", ea.STATE).withDescription("Schedule for the working week"),
1161
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1162
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1163
+ ],
1164
+ meta: {},
1165
+ ota: true,
1166
+ },
1167
+ {
1168
+ zigbeeModel: ["Tuya_Thermostat_r02"],
1169
+ model: "THERM_SLACKY_DIY_R02",
1170
+ vendor: "Slacky-DIY",
1171
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1172
+ endpoint: (device) => {
1173
+ return { day: 1, night: 2 };
1174
+ },
1175
+ fromZigbee: localFromZigbeeThermostat,
1176
+ toZigbee: localToZigbeeThermostat,
1177
+ configure: configureCommon,
1178
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1179
+ exposes: [
1180
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1181
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1182
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1183
+ e
1184
+ .numeric("deadzone_temperature", ea.ALL)
1185
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1186
+ .withUnit("°C")
1187
+ .withValueMin(1)
1188
+ .withValueMax(5)
1189
+ .withValueStep(1),
1190
+ e
1191
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1192
+ .withUnit("°C")
1193
+ .withDescription("Minimum Heating set point limit")
1194
+ .withValueMin(5)
1195
+ .withValueMax(15)
1196
+ .withValueStep(1),
1197
+ e
1198
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1199
+ .withDescription("Maximum Heating set point limit")
1200
+ .withUnit("°C")
1201
+ .withValueMin(15)
1202
+ .withValueMax(45)
1203
+ .withValueStep(1),
1204
+ e
1205
+ .numeric("frost_protect", ea.ALL)
1206
+ .withUnit("°C")
1207
+ .withDescription("Protection against minimum freezing temperature")
1208
+ .withValueMin(0)
1209
+ .withValueMax(10)
1210
+ .withValueStep(1),
1211
+ e
1212
+ .numeric("heat_protect", ea.ALL)
1213
+ .withUnit("°C")
1214
+ .withDescription("Protection against maximum heating temperature")
1215
+ .withValueMin(25)
1216
+ .withValueMax(70)
1217
+ .withValueStep(1),
1218
+ e.numeric("outdoor_temperature", ea.STATE_GET).withUnit("°C").withDescription("Current temperature measured from the floor outer sensor"),
1219
+ e
1220
+ .climate()
1221
+ .withLocalTemperature()
1222
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1223
+ .withLocalTemperatureCalibration(-9, 9, 1)
1224
+ .withSystemMode(["off", "heat"])
1225
+ .withRunningState(["idle", "heat"], ea.STATE)
1226
+ .withWeeklySchedule(["heat"], ea.ALL),
1227
+ e.text("schedule_monday", ea.STATE).withDescription("Monday's schedule"),
1228
+ e.text("schedule_tuesday", ea.STATE).withDescription("Tuesday's schedule"),
1229
+ e.text("schedule_wednesday", ea.STATE).withDescription("Wednesday's schedule"),
1230
+ e.text("schedule_thursday", ea.STATE).withDescription("Thursday's schedule"),
1231
+ e.text("schedule_friday", ea.STATE).withDescription("Friday's schedule"),
1232
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1233
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1234
+ ],
1235
+ meta: {},
1236
+ ota: true,
1237
+ },
1238
+ {
1239
+ zigbeeModel: ["Tuya_Thermostat_r03"],
1240
+ model: "THERM_SLACKY_DIY_R03",
1241
+ vendor: "Slacky-DIY",
1242
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1243
+ endpoint: (device) => {
1244
+ return { day: 1, night: 2 };
1245
+ },
1246
+ fromZigbee: localFromZigbeeThermostat,
1247
+ toZigbee: localToZigbeeThermostat,
1248
+ configure: configureCommon,
1249
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1250
+ exposes: [
1251
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1252
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1253
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1254
+ e
1255
+ .numeric("deadzone_temperature", ea.ALL)
1256
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1257
+ .withUnit("°C")
1258
+ .withValueMin(1)
1259
+ .withValueMax(5)
1260
+ .withValueStep(1),
1261
+ e
1262
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1263
+ .withUnit("°C")
1264
+ .withDescription("Minimum Heating set point limit")
1265
+ .withValueMin(5)
1266
+ .withValueMax(15)
1267
+ .withValueStep(1),
1268
+ e
1269
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1270
+ .withDescription("Maximum Heating set point limit")
1271
+ .withUnit("°C")
1272
+ .withValueMin(15)
1273
+ .withValueMax(45)
1274
+ .withValueStep(1),
1275
+ e
1276
+ .numeric("frost_protect", ea.ALL)
1277
+ .withUnit("°C")
1278
+ .withDescription("Protection against minimum freezing temperature")
1279
+ .withValueMin(0)
1280
+ .withValueMax(10)
1281
+ .withValueStep(1),
1282
+ e
1283
+ .numeric("heat_protect", ea.ALL)
1284
+ .withUnit("°C")
1285
+ .withDescription("Protection against maximum heating temperature")
1286
+ .withValueMin(25)
1287
+ .withValueMax(70)
1288
+ .withValueStep(1),
1289
+ e.numeric("brightness", ea.ALL).withValueMin(0).withValueMax(8).withDescription("Screen brightness 06:00 - 22:00").withEndpoint("day"),
1290
+ e.numeric("brightness", ea.ALL).withValueMin(0).withValueMax(8).withDescription("Screen brightness 22:00 - 06:00").withEndpoint("night"),
1291
+ e.binary("eco_mode", ea.ALL, "On", "Off").withDescription("On/Off Eco Mode"),
1292
+ e
1293
+ .numeric("eco_mode_heat_temperature", ea.ALL)
1294
+ .withUnit("°C")
1295
+ .withDescription("Set heat temperature in eco mode")
1296
+ .withValueMin(5)
1297
+ .withValueMax(45)
1298
+ .withValueStep(1),
1299
+ e.numeric("outdoor_temperature", ea.STATE_GET).withUnit("°C").withDescription("Current temperature measured from the floor outer sensor"),
1300
+ e
1301
+ .climate()
1302
+ .withLocalTemperature()
1303
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1304
+ .withLocalTemperatureCalibration(-9, 9, 1)
1305
+ .withSystemMode(["off", "heat"])
1306
+ .withRunningState(["idle", "heat"], ea.STATE)
1307
+ .withWeeklySchedule(["heat"], ea.ALL),
1308
+ e.text("schedule_monday", ea.STATE).withDescription("Monday's schedule"),
1309
+ e.text("schedule_tuesday", ea.STATE).withDescription("Tuesday's schedule"),
1310
+ e.text("schedule_wednesday", ea.STATE).withDescription("Wednesday's schedule"),
1311
+ e.text("schedule_thursday", ea.STATE).withDescription("Thursday's schedule"),
1312
+ e.text("schedule_friday", ea.STATE).withDescription("Friday's schedule"),
1313
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1314
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1315
+ ],
1316
+ meta: {},
1317
+ ota: true,
1318
+ },
1319
+ {
1320
+ zigbeeModel: ["Tuya_Thermostat_r04"],
1321
+ model: "THERM_SLACKY_DIY_R04",
1322
+ vendor: "Slacky-DIY",
1323
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1324
+ endpoint: (device) => {
1325
+ return { day: 1, night: 2 };
1326
+ },
1327
+ fromZigbee: localFromZigbeeThermostat,
1328
+ toZigbee: localToZigbeeThermostat,
1329
+ configure: configureCommon,
1330
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1331
+ exposes: [
1332
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1333
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1334
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1335
+ e
1336
+ .numeric("deadzone_temperature", ea.ALL)
1337
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1338
+ .withUnit("°C")
1339
+ .withValueMin(1)
1340
+ .withValueMax(5)
1341
+ .withValueStep(1),
1342
+ e
1343
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1344
+ .withUnit("°C")
1345
+ .withDescription("Minimum Heating set point limit")
1346
+ .withValueMin(5)
1347
+ .withValueMax(15)
1348
+ .withValueStep(1),
1349
+ e
1350
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1351
+ .withDescription("Maximum Heating set point limit")
1352
+ .withUnit("°C")
1353
+ .withValueMin(15)
1354
+ .withValueMax(45)
1355
+ .withValueStep(1),
1356
+ e
1357
+ .numeric("frost_protect", ea.ALL)
1358
+ .withUnit("°C")
1359
+ .withDescription("Protection against minimum freezing temperature")
1360
+ .withValueMin(0)
1361
+ .withValueMax(10)
1362
+ .withValueStep(1),
1363
+ e
1364
+ .numeric("heat_protect", ea.ALL)
1365
+ .withUnit("°C")
1366
+ .withDescription("Protection against maximum heating temperature")
1367
+ .withValueMin(25)
1368
+ .withValueMax(70)
1369
+ .withValueStep(1),
1370
+ e.numeric("brightness", ea.ALL).withValueMin(0).withValueMax(9).withDescription("Screen brightness").withEndpoint("day"),
1371
+ e.binary("eco_mode", ea.ALL, "On", "Off").withDescription("On/Off Eco Mode"),
1372
+ e
1373
+ .numeric("eco_mode_heat_temperature", ea.ALL)
1374
+ .withUnit("°C")
1375
+ .withDescription("Set heat temperature in eco mode")
1376
+ .withValueMin(5)
1377
+ .withValueMax(45)
1378
+ .withValueStep(1),
1379
+ e.numeric("outdoor_temperature", ea.STATE_GET).withUnit("°C").withDescription("Current temperature measured from the floor outer sensor"),
1380
+ e
1381
+ .climate()
1382
+ .withLocalTemperature()
1383
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1384
+ .withLocalTemperatureCalibration(-9, 9, 1)
1385
+ .withSystemMode(["off", "heat"])
1386
+ .withRunningState(["idle", "heat"], ea.STATE)
1387
+ .withWeeklySchedule(["heat"], ea.ALL),
1388
+ e.text("schedule_monday", ea.STATE).withDescription("Monday's schedule"),
1389
+ e.text("schedule_tuesday", ea.STATE).withDescription("Tuesday's schedule"),
1390
+ e.text("schedule_wednesday", ea.STATE).withDescription("Wednesday's schedule"),
1391
+ e.text("schedule_thursday", ea.STATE).withDescription("Thursday's schedule"),
1392
+ e.text("schedule_friday", ea.STATE).withDescription("Friday's schedule"),
1393
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1394
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1395
+ ],
1396
+ meta: {},
1397
+ ota: true,
1398
+ },
1399
+ {
1400
+ zigbeeModel: ["Tuya_Thermostat_r05"],
1401
+ model: "THERM_SLACKY_DIY_R05",
1402
+ vendor: "Slacky-DIY",
1403
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1404
+ endpoint: (device) => {
1405
+ return { day: 1, night: 2 };
1406
+ },
1407
+ fromZigbee: localFromZigbeeThermostat,
1408
+ toZigbee: localToZigbeeThermostat,
1409
+ configure: configureCommon,
1410
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1411
+ exposes: [
1412
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1413
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1414
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1415
+ e
1416
+ .numeric("deadzone_temperature", ea.ALL)
1417
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1418
+ .withUnit("°C")
1419
+ .withValueMin(1)
1420
+ .withValueMax(5)
1421
+ .withValueStep(1),
1422
+ e
1423
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1424
+ .withUnit("°C")
1425
+ .withDescription("Minimum Heating set point limit")
1426
+ .withValueMin(5)
1427
+ .withValueMax(15)
1428
+ .withValueStep(1),
1429
+ e
1430
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1431
+ .withDescription("Maximum Heating set point limit")
1432
+ .withUnit("°C")
1433
+ .withValueMin(15)
1434
+ .withValueMax(45)
1435
+ .withValueStep(1),
1436
+ e
1437
+ .numeric("heat_protect", ea.ALL)
1438
+ .withUnit("°C")
1439
+ .withDescription("Protection against maximum heating temperature")
1440
+ .withValueMin(25)
1441
+ .withValueMax(70)
1442
+ .withValueStep(1),
1443
+ e.numeric("outdoor_temperature", ea.STATE_GET).withUnit("°C").withDescription("Current temperature measured from the floor outer sensor"),
1444
+ e
1445
+ .climate()
1446
+ .withLocalTemperature()
1447
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1448
+ .withLocalTemperatureCalibration(-9, 9, 1)
1449
+ .withSystemMode(["off", "heat"])
1450
+ .withRunningState(["idle", "heat"], ea.STATE)
1451
+ .withWeeklySchedule(["heat"], ea.ALL),
1452
+ e.text("schedule_monday", ea.STATE).withDescription("Monday's schedule"),
1453
+ e.text("schedule_tuesday", ea.STATE).withDescription("Tuesday's schedule"),
1454
+ e.text("schedule_wednesday", ea.STATE).withDescription("Wednesday's schedule"),
1455
+ e.text("schedule_thursday", ea.STATE).withDescription("Thursday's schedule"),
1456
+ e.text("schedule_friday", ea.STATE).withDescription("Friday's schedule"),
1457
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1458
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1459
+ ],
1460
+ meta: {},
1461
+ ota: true,
1462
+ },
1463
+ {
1464
+ zigbeeModel: ["Tuya_Thermostat_r06"],
1465
+ model: "THERM_SLACKY_DIY_R06",
1466
+ vendor: "Slacky-DIY",
1467
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1468
+ endpoint: (device) => {
1469
+ return { day: 1, night: 2 };
1470
+ },
1471
+ fromZigbee: localFromZigbeeThermostat,
1472
+ toZigbee: localToZigbeeThermostat,
1473
+ configure: configureCommon,
1474
+ exposes: [
1475
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1476
+ e.binary("sound", ea.ALL, "On", "Off").withDescription("Sound On/Off"),
1477
+ e.binary("inversion", ea.ALL, "On", "Off").withDescription("Inversion of the output"),
1478
+ e.enum("brightness_level", ea.ALL, ["Off", "Low", "Medium", "High"]).withDescription("Screen brightness"),
1479
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1480
+ e.enum("sensor", ea.ALL, switchSensorUsed).withDescription("Select temperature sensor to use"),
1481
+ e
1482
+ .numeric("histeresis_temperature", ea.ALL)
1483
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1484
+ .withUnit("°C")
1485
+ .withValueMin(0.5)
1486
+ .withValueMax(10)
1487
+ .withValueStep(0.5),
1488
+ e
1489
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1490
+ .withDescription("Maximum Heating set point limit")
1491
+ .withUnit("°C")
1492
+ .withValueMin(15)
1493
+ .withValueMax(95)
1494
+ .withValueStep(1),
1495
+ e.binary("frost_protect_on_off", ea.ALL, "On", "Off").withDescription("Frost protection"),
1496
+ e
1497
+ .numeric("heat_protect", ea.ALL)
1498
+ .withUnit("°C")
1499
+ .withDescription("Protection against maximum heating temperature")
1500
+ .withValueMin(35)
1501
+ .withValueMax(60)
1502
+ .withValueStep(1),
1503
+ e
1504
+ .climate()
1505
+ .withLocalTemperature()
1506
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1507
+ .withLocalTemperatureCalibration(-9.9, 9.9, 0.1)
1508
+ .withSystemMode(["off", "heat"])
1509
+ .withRunningState(["idle", "heat"], ea.STATE)
1510
+ .withWeeklySchedule(["heat"], ea.ALL),
1511
+ e.text("schedule_monday", ea.STATE).withDescription("Schedule for the working week"),
1512
+ e.text("schedule_sunday", ea.STATE).withDescription("Weekend schedule"),
1513
+ e.enum("schedule_mode", ea.ALL, ["Off", "5+2", "6+1", "7"]).withDescription("Schedule mode"),
1514
+ e.enum("settings_reset", ea.SET, ["Default"]).withDescription("Default settings"),
1515
+ ],
1516
+ meta: {},
1517
+ ota: true,
1518
+ },
1519
+ {
1520
+ zigbeeModel: ["Tuya_Thermostat_r07"],
1521
+ model: "THERM_SLACKY_DIY_R07",
1522
+ vendor: "Slacky-DIY",
1523
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1524
+ endpoint: (device) => {
1525
+ return { day: 1, night: 2 };
1526
+ },
1527
+ fromZigbee: localFromZigbeeThermostat,
1528
+ toZigbee: localToZigbeeThermostat,
1529
+ configure: configureCommon,
1530
+ // Should be empty, unless device can be controlled (e.g. lights, switches).
1531
+ exposes: [
1532
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1533
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1534
+ e
1535
+ .numeric("deadzone_temperature", ea.ALL)
1536
+ .withDescription("The delta between local_temperature and current_heating_setpoint to trigger activity")
1537
+ .withUnit("°C")
1538
+ .withValueMin(1)
1539
+ .withValueMax(5)
1540
+ .withValueStep(1),
1541
+ e
1542
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1543
+ .withUnit("°C")
1544
+ .withDescription("Minimum Heating set point limit")
1545
+ .withValueMin(5)
1546
+ .withValueMax(15)
1547
+ .withValueStep(1),
1548
+ e
1549
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1550
+ .withDescription("Maximum Heating set point limit")
1551
+ .withUnit("°C")
1552
+ .withValueMin(15)
1553
+ .withValueMax(45)
1554
+ .withValueStep(1),
1555
+ e.binary("eco_mode", ea.ALL, "On", "Off").withDescription("On/Off Eco Mode"),
1556
+ e
1557
+ .numeric("eco_mode_cool_temperature", ea.ALL)
1558
+ .withUnit("°C")
1559
+ .withDescription("Set cool temperature in eco mode")
1560
+ .withValueMin(10)
1561
+ .withValueMax(30)
1562
+ .withValueStep(1),
1563
+ e
1564
+ .numeric("eco_mode_heat_temperature", ea.ALL)
1565
+ .withUnit("°C")
1566
+ .withDescription("Set heat temperature in eco mode")
1567
+ .withValueMin(10)
1568
+ .withValueMax(30)
1569
+ .withValueStep(1),
1570
+ e.binary("fan_control", ea.ALL, "On", "Off").withDescription("On/Off Fan Control"),
1571
+ e
1572
+ .climate()
1573
+ .withLocalTemperature()
1574
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1575
+ .withLocalTemperatureCalibration(-9, 9, 1)
1576
+ .withSystemMode(["off", "heat", "cool", "fan_only"])
1577
+ .withRunningState(["idle", "heat", "cool", "fan_only"], ea.STATE)
1578
+ .withFanMode(["low", "medium", "high", "auto"])
1579
+ .withWeeklySchedule(["cool"], ea.ALL),
1580
+ e.text("schedule_monday", ea.STATE).withDescription("Monday's schedule"),
1581
+ e.text("schedule_tuesday", ea.STATE).withDescription("Tuesday's schedule"),
1582
+ e.text("schedule_wednesday", ea.STATE).withDescription("Wednesday's schedule"),
1583
+ e.text("schedule_thursday", ea.STATE).withDescription("Thursday's schedule"),
1584
+ e.text("schedule_friday", ea.STATE).withDescription("Friday's schedule"),
1585
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1586
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1587
+ ],
1588
+ meta: {},
1589
+ ota: true,
1590
+ },
1591
+ {
1592
+ zigbeeModel: ["Tuya_Thermostat_r08"],
1593
+ model: "THERM_SLACKY_DIY_R08",
1594
+ vendor: "Slacky-DIY",
1595
+ description: "Tuya Thermostat for Floor Heating with custom Firmware",
1596
+ endpoint: (device) => {
1597
+ return { day: 1, night: 2 };
1598
+ },
1599
+ fromZigbee: localFromZigbeeThermostat,
1600
+ toZigbee: localToZigbeeThermostat,
1601
+ configure: configureCommon,
1602
+ exposes: [
1603
+ e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device"),
1604
+ e.programming_operation_mode(["setpoint", "schedule"]).withDescription("Setpoint or Schedule mode"),
1605
+ e
1606
+ .numeric("min_heat_setpoint_limit", ea.ALL)
1607
+ .withUnit("°C")
1608
+ .withDescription("Minimum Heating set point limit")
1609
+ .withValueMin(5)
1610
+ .withValueMax(15)
1611
+ .withValueStep(1),
1612
+ e
1613
+ .numeric("max_heat_setpoint_limit", ea.ALL)
1614
+ .withDescription("Maximum Heating set point limit")
1615
+ .withUnit("°C")
1616
+ .withValueMin(15)
1617
+ .withValueMax(45)
1618
+ .withValueStep(1),
1619
+ e.binary("eco_mode", ea.ALL, "On", "Off").withDescription("On/Off Sleep Mode"),
1620
+ e
1621
+ .numeric("external_temperature_calibration", ea.ALL)
1622
+ .withDescription("External temperature calibration")
1623
+ .withUnit("°C")
1624
+ .withValueMin(-9)
1625
+ .withValueMax(9)
1626
+ .withValueStep(1),
1627
+ e
1628
+ .climate()
1629
+ .withLocalTemperature()
1630
+ .withSetpoint("occupied_heating_setpoint", 5, 45, 0.5)
1631
+ .withLocalTemperatureCalibration(-9.9, 9.9, 1)
1632
+ .withSystemMode(["off", "heat"])
1633
+ .withRunningState(["idle", "heat"], ea.STATE)
1634
+ .withWeeklySchedule(["heat"], ea.ALL),
1635
+ e.text("schedule_monday", ea.STATE).withDescription("Schedule for the working week"),
1636
+ e.text("schedule_saturday", ea.STATE).withDescription("Saturday's schedule"),
1637
+ e.text("schedule_sunday", ea.STATE).withDescription("Sunday's schedule"),
1638
+ ],
1639
+ meta: {},
1640
+ ota: true,
1641
+ },
1642
+ ];
1643
+ //# sourceMappingURL=slacky_diy.js.map