// ⚙️ Konfiguration const espIP = "192.168.XXX.XXX"; // Deine ESP-IP const variableNames = [ "dval", "dval2", "mval", "mval2", "yval", "yval2", "dcon", "dprod", "mcon" ]; // 📁 Basisordner für Backup-Dateien const backupFolder = "/opt/iobroker/backups"; // <--- ggf. anpassen const fs = require("fs"); // 🟡 Triggerdatenpunkte anlegen (wenn nicht vorhanden) const backupTrigger = "0_userdata.0.LG320Backup.backupTrigger"; const restoreTrigger = "0_userdata.0.LG320Backup.restoreTrigger"; const latestRestoreDP = "0_userdata.0.LG320Backup.latestRestoreCommand"; createTriggerDP(backupTrigger); createTriggerDP(restoreTrigger); createStringDP(latestRestoreDP, ""); // neuer DP für Restore-Befehl // 📦 Backup-Funktion async function backupFromESP() { log("📦 Tasmota-Backup gestartet...", "info"); const now = new Date(); // 📌 Zeitstempel in lokaler Zeit (anstatt UTC) const pad = (n) => n.toString().padStart(2, "0"); const timestamp = now.getFullYear() + "-" + pad(now.getMonth() + 1) + "-" + pad(now.getDate()) + "-" + pad(now.getHours()) + "-" + pad(now.getMinutes()) + "-" + pad(now.getSeconds()); const backupFilePath = `${backupFolder}/lg320_backup_${timestamp}.txt`; const latestFilePath = `${backupFolder}/lg320_backup_latest.txt`; let fileContent = "=== LG320 Backup ===\n"; fileContent += `Datum: ${now.toLocaleString()}\n\n`; const commands = []; for (const varName of variableNames) { const url = `http://${espIP}/cm?cmnd=script?${varName}`; try { const result = await request(url); const json = JSON.parse(result); let value = json?.script?.[varName]; if (value !== undefined) { if (typeof value === "string" && value.trim().startsWith("{") && value.trim().endsWith("}")) { value = value.replace(/,/g, " "); } if (Array.isArray(value)) { value = "{" + value.join(" ") + "}"; } value = value.toString(); const dp = `0_userdata.0.LG320Backup.${varName}`; if (!existsState(dp)) { await createStateAsync(dp, value, { type: "string", role: "text" }); } await setStateAsync(dp, { val: value, ack: true }); log(`✅ Gesichert: ${varName} = ${value}`); fileContent += `${varName} = ${value}\n`; const escaped = value.replace(/\s+/g, " ").trim(); commands.push(`script >${varName}=${escaped};`); } else { log(`⚠️ Kein gültiger Wert für ${varName}`, "warn"); fileContent += `${varName} = [ungültig]\n`; } } catch (e) { log(`⚠️ Fehler bei ${varName}: ${e.message}`, "warn"); fileContent += `${varName} = [Fehler: ${e.message}]\n`; } } let finalCmd = ""; if (commands.length > 0) { finalCmd = "backlog " + commands.join(" ") + " script >svars;"; fileContent += "\n=== Restore-Befehl für ESP-Konsole ===\n"; fileContent += finalCmd + "\n"; } try { if (!fs.existsSync(backupFolder)) { fs.mkdirSync(backupFolder, { recursive: true }); } fs.writeFileSync(backupFilePath, fileContent, "utf8"); fs.writeFileSync(latestFilePath, fileContent, "utf8"); // 📌 Nur den Restore-Befehl ins State schreiben if (finalCmd) { setState(latestRestoreDP, finalCmd, true); } log(`💾 Backup-Dateien gespeichert:\n - ${backupFilePath}\n - ${latestFilePath}`, "info"); } catch (err) { log(`❌ Fehler beim Schreiben der Backup-Datei: ${err.message}`, "error"); } log("✅ Backup abgeschlossen."); } // 🔁 Wiederherstellungs-Funktion (wie gehabt) function restoreToConsole() { log("♻️ Erzeuge Wiederherstellungsbefehl für ESP-Konsole..."); const commands = []; for (const varName of variableNames) { const dp = `0_userdata.0.LG320Backup.${varName}`; const val = getState(dp)?.val; if (val !== undefined && val !== null && val !== "") { const escaped = val.toString().replace(/\s+/g, " ").trim(); const cmd = `script >${varName}=${escaped};`; commands.push(cmd); } } const final = "backlog " + commands.join(" ") + " script >svars;"; log("📥 === Befehl für ESP-Konsole ===\n" + final, "info"); } // 📡 HTTP-Anfrage über iobroker (ohne fetch) function request(url) { return new Promise((resolve, reject) => { require("http").get(url, res => { let data = ""; res.on("data", chunk => data += chunk); res.on("end", () => resolve(data)); }).on("error", reject); }); } // 🛠️ Hilfsfunktionen function createTriggerDP(dp) { if (!existsState(dp)) { createState(dp, false, { name: dp, type: "boolean", role: "button", read: true, write: true }); } } function createStringDP(dp, initial) { if (!existsState(dp)) { createState(dp, initial, { name: dp, type: "string", role: "text", read: true, write: true }); } } // 🎯 Trigger auswerten on({ id: backupTrigger, change: "ne" }, (obj) => { if (obj.state?.val === true) { backupFromESP().then(() => setState(backupTrigger, false, true)); } }); on({ id: restoreTrigger, change: "ne" }, (obj) => { if (obj.state?.val === true) { restoreToConsole(); setState(restoreTrigger, false, true); } });