UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

672 lines 34.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.definitions = void 0; const fz = __importStar(require("../converters/fromZigbee")); const tz = __importStar(require("../converters/toZigbee")); const exposes = __importStar(require("../lib/exposes")); const legacy = __importStar(require("../lib/legacy")); const m = __importStar(require("../lib/modernExtend")); const reporting = __importStar(require("../lib/reporting")); const globalStore = __importStar(require("../lib/store")); const tuya = __importStar(require("../lib/tuya")); const utils = __importStar(require("../lib/utils")); const e = exposes.presets; const ea = exposes.access; const fzLocal = { // biome-ignore lint/style/useNamingConvention: ignored using `--suppress` FB20002_on: { cluster: "genOnOff", type: "commandTuyaAction", convert: (model, msg, publish, options, meta) => { return { action: "on" }; }, }, }; const valueConverterLocal = { wateringState: { from: (value, meta, options, publish) => { const result = { state: value ? "ON" : "OFF", ...(value ? {} : { // ensure time_left is set to zero when it's OFF time_left: 0, }), }; // prepare the time reporting for water scheduler // indications when the watering was triggered by scheduler: // - scheduling is enabled // - current state is on // - time_left wasn't reported before and is 0 // - current hour & minute matches scheduling period if (meta.state.schedule_mode !== "OFF" && result.state === "ON" && meta.state.time_left === 0 && !globalStore.hasValue(meta.device, "watering_timer_active_time_slot")) { const now = new Date(); const timeslot = [1, 2, 3, 4, 5, 6] .map((slotNumber) => utils.getObjectProperty(meta.state, `schedule_slot_${slotNumber}`, {})) // @ts-expect-error ignore .find((ts) => ts.state === "ON" && ts.start_hour === now.getHours() && ts.start_minute === now.getMinutes() && ts.timer > 0); if (timeslot) { // @ts-expect-error ignore const iterationDuration = timeslot.timer + timeslot.pause; // automatic watering detected globalStore.putValue(meta.device, "watering_timer_active_time_slot", { timeslot_start_timestamp: now.getTime(), // end of last watering excluding last pause // @ts-expect-error ignore timeslot_end_timestamp: now.getTime() + (timeslot.iterations * iterationDuration - timeslot.pause) * 60 * 1000, // @ts-expect-error ignore timer: timeslot.timer, iteration_inverval: null, // will be set in the next step iteration_start_timestamp: 0, // will be set in the next step }); } } // setup time reporting for water scheduler when necessary if (globalStore.hasValue(meta.device, "watering_timer_active_time_slot")) { const ts = globalStore.getValue(meta.device, "watering_timer_active_time_slot"); if ( // time slot execution is already completed Date.now() > ts.timeslot_end_timestamp - 5000 || // scheduling was interrupted by turning watering on manually // @ts-expect-error ignore (result.state === "ON" && result.state !== meta.state.state && meta.state.time_left > 0)) { // reporting is no longer necessary clearInterval(ts.iteration_inverval); globalStore.clearValue(meta.device, "watering_timer_active_time_slot"); } else if (result.state === "OFF" && result.state !== meta.state.state) { // turned off --> disable reporting for this iteration only clearInterval(ts.iteration_inverval); ts.iteration_inverval = null; } else if (result.state === "ON" && result.state !== meta.state.state && meta.state.time_left === 0) { // automatic scheduling detected (reported as ON, but without any info about duration) ts.iteration_report = true; ts.iteration_start_timestamp = Date.now(); if (ts.timer > 1) { // report every minute ts.iteration_inverval = setInterval(() => { const now = Date.now(); const wateringEndTime = ts.iteration_start_timestamp + ts.timer * 60 * 1000; const timeLeftInMinutes = Math.round((wateringEndTime - now) / 1000 / 60); if (timeLeftInMinutes > 0) { if (timeLeftInMinutes === 1) { clearInterval(ts.iteration_inverval); } publish({ time_left: timeLeftInMinutes, }); } }, 60 * 1000); } // initial reporting result.time_left = ts.timer; } } return result; }, }, wateringScheduleMode: { from: (value) => { const [scheduleMode, scheduleValue] = value; const isWeekday = scheduleMode === 0; return { schedule_mode: scheduleValue === 0 ? "OFF" : isWeekday ? "WEEKDAY" : "PERIODIC", schedule_periodic: !isWeekday ? scheduleValue : 0, schedule_weekday: ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"].reduce((scheduleMap, dayName, index) => ({ // biome-ignore lint/performance/noAccumulatingSpread: ignored using `--suppress` ...scheduleMap, [dayName]: isWeekday && (scheduleValue & (1 << index)) > 0 ? "ON" : "OFF", }), {}), }; }, }, wateringSchedulePeriodic: { to: (value) => { if (!utils.isInRange(0, 7, value)) throw new Error(`Invalid value: ${value} (expected ${0} to ${7})`); // Note: mode value of 0 switches to disabled weekday scheduler const scheduleMode = value > 0 ? 1 : 0; return [scheduleMode, value]; }, }, wateringScheduleWeekday: { to: (value, meta) => { // map each day to ON/OFF and use current state as default to allow partial updates const dayValues = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] // @ts-expect-error ignore .map((dayName) => utils.getObjectProperty(value, dayName, utils.getObjectProperty(meta.state.schedule_weekday, dayName, "OFF"))); const scheduleValue = dayValues.reduce((dayConfig, value, index) => { // @ts-expect-error ignore return dayConfig | (value === "ON" ? 1 << index : 0); }, 0); // value of 0 switches to weekday scheduler const scheduleMode = 0; return [scheduleMode, scheduleValue]; }, }, wateringScheduleSlot: (timeSlotNumber) => ({ from: (buffer) => { return { state: buffer.readUInt8(0) === 1 ? "ON" : "OFF", start_hour: utils.numberWithinRange(buffer.readUInt8(1), 0, 23), // device reports non-valid value 255 initially start_minute: utils.numberWithinRange(buffer.readUInt8(2), 0, 59), // device reports non-valid value 255 initially timer: utils.numberWithinRange(buffer.readUInt8(3) * 60 + buffer.readUInt8(4), 1, 599), // device reports non-valid value 0 initially pause: utils.numberWithinRange(buffer.readUInt8(6) * 60 + buffer.readUInt8(7), 0, 599), iterations: utils.numberWithinRange(buffer.readUInt8(9), 1, 9), // device reports non-valid value 0 initially }; }, to: (value, meta) => { // use default values from current config to allow partial updates const timeslot = utils.getObjectProperty(meta.state, `schedule_slot_${timeSlotNumber}`, {}); const state = utils.getObjectProperty(value, "state", timeslot.state ?? false); const startHour = utils.getObjectProperty(value, "start_hour", timeslot.start_hour ?? 23); const startMinute = utils.getObjectProperty(value, "start_minute", timeslot.start_minute ?? 59); const duratonInMin = utils.getObjectProperty(value, "timer", timeslot.timer ?? 1); const iterations = utils.getObjectProperty(value, "iterations", timeslot.iterations ?? 1); const pauseInMin = utils.getObjectProperty(value, "pause", timeslot.pause ?? 0); if (!utils.isInRange(0, 23, startHour)) throw new Error(`Invalid start hour value ${startHour} (expected ${0} to ${23})`); if (!utils.isInRange(0, 59, startMinute)) throw new Error(`Invalid start minute value: ${startMinute} (expected ${0} to ${59})`); if (!utils.isInRange(1, 599, duratonInMin)) throw new Error(`Invalid timer value: ${duratonInMin} (expected ${1} to ${599})`); if (!utils.isInRange(1, 9, iterations)) throw new Error(`Invalid iterations value: ${iterations} (expected ${1} to ${9})`); if (!utils.isInRange(0, 599, pauseInMin)) throw new Error(`Invalid pause value: ${pauseInMin} (expected ${0} to ${599})`); if (iterations > 1 && pauseInMin === 0) throw new Error("Pause value must be at least 1 minute when using multiple iterations"); return [ // @ts-expect-error ignore state === "ON" ? 1 : 0, // time slot enabled or not startHour, // start hour startMinute, // start minute Math.floor(duratonInMin / 60), // duration for n hours duratonInMin % 60, // duration + n minutes 0, // what's this? -> was always reported as 0 Math.floor(pauseInMin / 60), // pause in hours pauseInMin % 60, // pause + n minutes 0, // what's this? -> was always reported as 0 iterations, // iterations ]; }, }), }; exports.definitions = [ { fingerprint: [ { manufacturerName: "_TZ3000_kdi2o9m6" }, // EU { modelID: "TS011F", manufacturerName: "_TZ3000_plyvnuf5" }, // CH { modelID: "TS011F", manufacturerName: "_TZ3000_wamqdr3f" }, // FR { modelID: "TS011F", manufacturerName: "_TZ3000_00mk2xzy" }, // BS { modelID: "TS011F", manufacturerName: "_TZ3000_upjrsxh1" }, // DK { manufacturerName: "_TZ3000_00mk2xzy" }, // BS ], model: "HG06337", vendor: "Lidl", description: "Silvercrest smart plug (EU, CH, FR, BS, DK)", extend: [tuya.modernExtend.tuyaOnOff({ indicatorMode: true })], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(11); await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]); await reporting.onOff(endpoint); }, }, { fingerprint: tuya.fingerprint("TS011F", ["_TZ3000_j1v25l17", "_TZ3000_ynmowqk2", "_TZ3000_3uimvkn6"]), model: "HG08673", vendor: "Lidl", description: "Silvercrest smart plug with power monitoring (EU, FR)", ota: true, extend: [tuya.modernExtend.tuyaOnOff({ electricalMeasurements: true, powerOutageMemory: true, indicatorMode: true, childLock: true })], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await tuya.configureMagicPacket(device, coordinatorEndpoint); await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "haElectricalMeasurement"]); await reporting.rmsVoltage(endpoint, { change: 5 }); await reporting.rmsCurrent(endpoint, { change: 50 }); await reporting.activePower(endpoint, { change: 10 }); // Energy reporting (currentSummDelivered) doesn't work; requires polling: https://github.com/Koenkk/zigbee2mqtt/issues/14356 endpoint.saveClusterAttributeKeyValue("haElectricalMeasurement", { acCurrentDivisor: 1000, acCurrentMultiplier: 1 }); endpoint.saveClusterAttributeKeyValue("seMetering", { divisor: 100, multiplier: 1 }); device.save(); }, options: [exposes.options.measurement_poll_interval().withDescription("Only the energy value is polled for this device.")], onEvent: (type, data, device, options) => tuya.onEventMeasurementPoll(type, data, device, options, false, true), whiteLabel: [tuya.whitelabel("Lidl", "HG08673-BS", "Silvercrest smart plug with power monitoring (BS)", ["_TZ3000_3uimvkn6"])], }, { fingerprint: tuya.fingerprint("TS004F", ["_TZ3000_rco1yzb1"]), model: "HG08164", vendor: "Lidl", description: "Silvercrest smart button", fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_stop, fz.battery, tuya.fz.on_off_action], toZigbee: [], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await endpoint.read("genBasic", [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe]); await endpoint.read("genOnOff", ["tuyaOperationMode"]); try { await endpoint.read(0xe001, [0xd011]); } catch { /* do nothing */ } await endpoint.read("genPowerCfg", ["batteryVoltage", "batteryPercentageRemaining"]); await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]); await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]); await reporting.batteryPercentageRemaining(endpoint); }, exposes: [e.action(["on", "off", "brightness_stop", "brightness_step_up", "brightness_step_down", "single", "double"]), e.battery()], }, { fingerprint: tuya.fingerprint("TS0211", ["_TZ1800_ladpngdx", "_TZ1800_akzvkzqq"]), model: "HG06668", vendor: "Lidl", description: "Silvercrest smart wireless door bell button", fromZigbee: [fz.battery, fz.tuya_doorbell_button, fz.ignore_basic_report], toZigbee: [], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg"]); await reporting.batteryPercentageRemaining(endpoint); }, exposes: [e.battery(), e.action(["pressed"]), e.battery_low(), e.tamper()], }, { fingerprint: tuya.fingerprint("TY0202", ["_TZ1800_fcdjzz3s"]), model: "HG06335/HG07310", vendor: "Lidl", description: "Silvercrest smart motion sensor", extend: [ m.iasZoneAlarm({ zoneType: "occupancy", zoneStatusReporting: true, zoneAttributes: ["alarm_1", "tamper", "battery_low"] }), m.battery(), ], }, { fingerprint: tuya.fingerprint("TY0203", ["_TZ1800_ejwkn2h2", "_TZ1800_ho6i0zk9"]), model: "HG06336", vendor: "Lidl", description: "Silvercrest smart window and door sensor", extend: [m.iasZoneAlarm({ zoneType: "contact", zoneAttributes: ["alarm_1", "tamper"] }), m.battery()], }, { fingerprint: tuya.fingerprint("TS1001", ["_TYZB01_bngwdjsr"]), model: "FB20-002", vendor: "Lidl", description: "Livarno Lux switch and dimming light remote control", exposes: [ e.action(["on", "off", "brightness_stop", "brightness_step_up", "brightness_step_down", "brightness_move_up", "brightness_move_down"]), ], fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fzLocal.FB20002_on], toZigbee: [], }, { fingerprint: tuya.fingerprint("TS1001", ["_TYZB01_hww2py6b"]), model: "FB21-001", vendor: "Lidl", description: "Livarno Lux switch and dimming light remote control", exposes: [ e.action([ "on", "off", "brightness_stop", "brightness_step_up", "brightness_step_down", "brightness_move_up", "brightness_move_down", "switch_scene", ]), ], fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fz.tuya_switch_scene], toZigbee: [], }, { fingerprint: tuya.fingerprint("TS011F", [ "_TZ3000_wzauvbcs", "_TZ3000_oznonj5q", "_TZ3000_1obwwnmq", "_TZ3000_4uf3d0ax", "_TZ3000_vzopcetz", "_TZ3000_vmpbygs5", ]), model: "HG06338", vendor: "Lidl", description: "Silvercrest 3 gang switch, with 4 USB (EU, FR, CZ, BS)", extend: [tuya.modernExtend.tuyaOnOff({ endpoints: ["l1", "l2", "l3"] })], meta: { multiEndpoint: true }, configure: async (device, coordinatorEndpoint) => { await tuya.configureMagicPacket(device, coordinatorEndpoint); for (const ID of [1, 2, 3]) { await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ["genOnOff"]); } }, endpoint: (device) => { return { l1: 1, l2: 2, l3: 3 }; }, }, { fingerprint: tuya.fingerprint("TS0601", ["_TZE200_s8gkrkxk"]), model: "HG06467", vendor: "Lidl", description: "Melinera smart LED string lights", toZigbee: [tz.on_off, legacy.tz.silvercrest_smart_led_string], fromZigbee: [fz.on_off, legacy.fz.silvercrest_smart_led_string], exposes: [e.light_brightness_colorhs().setAccess("brightness", ea.STATE_SET).setAccess("color_hs", ea.STATE_SET)], }, { fingerprint: tuya.fingerprint("TS0504B", ["_TZ3210_sroezl0s"]), model: "14153806L", vendor: "Lidl", description: "Livarno smart LED ceiling light", extend: [tuya.modernExtend.tuyaLight({ colorTemp: { range: [153, 500] }, color: true })], configure: (device, coordinatorEndpoint) => { device.getEndpoint(1).saveClusterAttributeKeyValue("lightingColorCtrl", { colorCapabilities: 29 }); }, }, { fingerprint: tuya.fingerprint("TS0601", ["_TZE200_htnnfasr"]), model: "PSBZS A1", vendor: "Lidl", description: "Parkside smart watering timer", fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.ignore_onoff_report, tuya.fz.datapoints], toZigbee: [tuya.tz.datapoints], onEvent: async (type, data, device) => { await tuya.onEventSetLocalTime(type, data, device); // @ts-expect-error ignore if (type === "deviceInterview" && data.status === "successful") { // dirty hack: reset frost guard & frost alarm to get the initial state // wait 10 seconds to ensure configure is done await utils.sleep(10000); const endpoint = device.getEndpoint(1); try { await tuya.sendDataPointBool(endpoint, 109, false); await tuya.sendDataPointBool(endpoint, 108, false); } catch { // ignore, just prevent any crashes } } }, configure: async (device, coordinatorEndpoint) => { await tuya.configureMagicPacket(device, coordinatorEndpoint); await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ["genOnOff"]); // set reporting interval of genOnOff to max to "disable" it // background: genOnOff reporting does not respect timer or button, that makes the on/off reporting pretty useless // the device is reporting it's state change anyway via tuya DPs await reporting.onOff(device.getEndpoint(1), { max: 0xffff }); }, exposes: [ e.battery(), tuya.exposes.switch(), e .numeric("timer", ea.STATE_SET) .withValueMin(1) .withValueMax(599) .withUnit("min") .withDescription("Auto off after specific time for manual watering."), e.numeric("time_left", ea.STATE).withUnit("min").withDescription("Remaining time until the watering turns off."), e .binary("frost_lock", ea.STATE, "ON", "OFF") .withDescription("Indicates if the frost guard is currently active. " + "If the temperature drops below 5° C, device activates frost guard and disables irrigation. " + "You need to reset the frost guard to activate irrigation again. Note: There is no way to enable frost guard manually."), e.enum("reset_frost_lock", ea.SET, ["RESET"]).withDescription("Resets frost lock to make the device workable again."), e.enum("schedule_mode", ea.STATE, ["OFF", "WEEKDAY", "PERIODIC"]).withDescription("Scheduling mode that is currently in use."), e .numeric("schedule_periodic", ea.STATE_SET) .withValueMin(0) .withValueMax(7) .withUnit("day") .withDescription("Watering by periodic interval: Irrigate every n days"), e .composite("schedule_weekday", "schedule_weekday", ea.STATE_SET) .withDescription("Watering by weekday: Irrigate individually for each day.") .withFeature(e.binary("monday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("tuesday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("wednesday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("thursday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("friday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("saturday", ea.STATE_SET, "ON", "OFF")) .withFeature(e.binary("sunday", ea.STATE_SET, "ON", "OFF")), ...[1, 2, 3, 4, 5, 6].map((timeSlotNumber) => e .composite(`schedule_slot_${timeSlotNumber}`, `schedule_slot_${timeSlotNumber}`, ea.STATE_SET) .withDescription(`Watering time slot ${timeSlotNumber}`) .withFeature(e.binary("state", ea.STATE_SET, "ON", "OFF").withDescription("On/off state of the time slot")) .withFeature(e.numeric("start_hour", ea.STATE_SET).withUnit("h").withValueMin(0).withValueMax(23).withDescription("Starting time (hour)")) .withFeature(e .numeric("start_minute", ea.STATE_SET) .withUnit("min") .withValueMin(0) .withValueMax(59) .withDescription("Starting time (minute)")) .withFeature(e .numeric("timer", ea.STATE_SET) .withUnit("min") .withValueMin(1) .withValueMax(599) .withDescription("Auto off after specific time for scheduled watering.")) .withFeature(e .numeric("pause", ea.STATE_SET) .withUnit("min") .withValueMin(0) .withValueMax(599) .withDescription("Pause after each iteration.")) .withFeature(e .numeric("iterations", ea.STATE_SET) .withValueMin(1) .withValueMax(9) .withDescription("Number of watering iterations. Works only if there is a pause."))), ], meta: { tuyaDatapoints: [ [1, null, valueConverterLocal.wateringState], // disable optimistic state reporting (device may not turn on when battery is low) [1, "state", tuya.valueConverter.onOff, { optimistic: false }], [5, "timer", tuya.valueConverter.raw], [6, "time_left", tuya.valueConverter.raw], [11, "battery", tuya.valueConverter.raw], [108, "frost_lock", tuya.valueConverter.onOff], // there is no state reporting for reset [109, "reset_frost_lock", tuya.valueConverterBasic.lookup({ RESET: tuya.enum(0) }), { optimistic: false }], [107, null, valueConverterLocal.wateringScheduleMode], [107, "schedule_periodic", valueConverterLocal.wateringSchedulePeriodic], [107, "schedule_weekday", valueConverterLocal.wateringScheduleWeekday], [101, "schedule_slot_1", valueConverterLocal.wateringScheduleSlot(1)], [102, "schedule_slot_2", valueConverterLocal.wateringScheduleSlot(2)], [103, "schedule_slot_3", valueConverterLocal.wateringScheduleSlot(3)], [104, "schedule_slot_4", valueConverterLocal.wateringScheduleSlot(4)], [105, "schedule_slot_5", valueConverterLocal.wateringScheduleSlot(5)], [106, "schedule_slot_6", valueConverterLocal.wateringScheduleSlot(6)], ], }, }, { fingerprint: tuya.fingerprint("TS0101", ["_TZ3000_br3laukf"]), model: "HG06620", vendor: "Lidl", description: "Silvercrest garden spike with 2 sockets", extend: [tuya.modernExtend.tuyaOnOff()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]); await reporting.onOff(endpoint); }, }, { fingerprint: tuya.fingerprint("TS0101", ["_TZ3000_pnzfdr9y"]), model: "HG06619", vendor: "Lidl", description: "Silvercrest outdoor plug", extend: [tuya.modernExtend.tuyaOnOff()], configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff"]); await reporting.onOff(endpoint); }, }, { fingerprint: tuya.fingerprint("TS0505B", ["_TZ3000_lxw3zcdk"]), model: "HG08633", vendor: "Lidl", description: "Livarno gardenspot RGB", extend: [tuya.modernExtend.tuyaLight({ colorTemp: { range: [153, 500] }, color: { modes: ["hs", "xy"] } })], }, { fingerprint: tuya.fingerprint("TS0601", ["_TZE200_chyvmhay", "_TZE200_uiyqstza"]), model: "368308_2010", vendor: "Lidl", description: "Silvercrest radiator valve with thermostat", fromZigbee: [fz.ignore_tuya_set_time, legacy.fromZigbee.zs_thermostat], toZigbee: [ legacy.toZigbee.zs_thermostat_current_heating_setpoint, legacy.toZigbee.zs_thermostat_child_lock, legacy.toZigbee.zs_thermostat_comfort_temp, legacy.toZigbee.zs_thermostat_eco_temp, legacy.toZigbee.zs_thermostat_preset_mode, legacy.toZigbee.zs_thermostat_system_mode, legacy.toZigbee.zs_thermostat_local_temperature_calibration, legacy.toZigbee.zs_thermostat_current_heating_setpoint_auto, legacy.toZigbee.zs_thermostat_openwindow_time, legacy.toZigbee.zs_thermostat_openwindow_temp, legacy.toZigbee.zs_thermostat_binary_one, legacy.toZigbee.zs_thermostat_binary_two, legacy.toZigbee.zs_thermostat_away_setting, legacy.toZigbee.zs_thermostat_local_schedule, ], onEvent: tuya.onEventSetLocalTime, configure: async (device, coordinatorEndpoint) => { const endpoint = device.getEndpoint(1); await reporting.bind(endpoint, coordinatorEndpoint, ["genBasic"]); }, exposes: [ e.child_lock(), e.comfort_temperature(), e.eco_temperature(), e.battery_voltage(), e .numeric("current_heating_setpoint_auto", ea.STATE_SET) .withValueMin(0.5) .withValueMax(29.5) .withValueStep(0.5) .withUnit("°C") .withDescription("Temperature setpoint automatic"), e .climate() .withSetpoint("current_heating_setpoint", 0.5, 29.5, 0.5, ea.STATE_SET) .withLocalTemperature(ea.STATE) .withLocalTemperatureCalibration(-12.5, 5.5, 0.1, ea.STATE_SET) .withSystemMode(["off", "heat", "auto"], ea.STATE_SET) .withPreset(["schedule", "manual", "holiday", "boost"]), e .numeric("detectwindow_temperature", ea.STATE_SET) .withUnit("°C") .withDescription("Open window detection temperature") .withValueMin(-10) .withValueMax(35), e .numeric("detectwindow_timeminute", ea.STATE_SET) .withUnit("min") .withDescription("Open window time in minute") .withValueMin(0) .withValueMax(1000), e.binary("binary_one", ea.STATE_SET, "ON", "OFF").withDescription("Unknown binary one"), e.binary("binary_two", ea.STATE_SET, "ON", "OFF").withDescription("Unknown binary two"), e.binary("away_mode", ea.STATE, "ON", "OFF").withDescription("Away mode"), e .composite("away_setting", "away_setting", ea.STATE_SET) .withFeature(e.away_preset_days()) .setAccess("away_preset_days", ea.ALL) .withFeature(e.away_preset_temperature()) .setAccess("away_preset_temperature", ea.ALL) .withFeature(e.numeric("away_preset_year", ea.ALL).withUnit("year").withDescription("Start away year 20xx")) .withFeature(e.numeric("away_preset_month", ea.ALL).withUnit("month").withDescription("Start away month")) .withFeature(e.numeric("away_preset_day", ea.ALL).withUnit("day").withDescription("Start away day")) .withFeature(e.numeric("away_preset_hour", ea.ALL).withUnit("hour").withDescription("Start away hours")) .withFeature(e.numeric("away_preset_minute", ea.ALL).withUnit("min").withDescription("Start away minutes")), ...["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"].map((day) => { const expose = e.composite(day, day, ea.STATE_SET); // biome-ignore lint/complexity/noForEach: ignored using `--suppress` [1, 2, 3, 4, 5, 6, 7, 8, 9].forEach((i) => { expose.withFeature(e .numeric(`${day}_temp_${i}`, ea.ALL) .withValueMin(0.5) .withValueMax(29.5) .withValueStep(0.5) .withUnit("°C") .withDescription(`Temperature ${i}`)); expose.withFeature(e .enum(`${day}_hour_${i}`, ea.STATE_SET, [ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", ]) .withDescription(`Hour TO for temp ${i}`)); expose.withFeature(e.enum(`${day}_minute_${i}`, ea.STATE_SET, ["00", "15", "30", "45"]).withDescription(`Minute TO for temp ${i}`)); }); return expose; }), ], }, ]; //# sourceMappingURL=lidl.js.map