Metainformationen zur Seite
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| iobroker:countdown_script_fuer_vis1 [06.01.2026] – angelegt kolja | iobroker:countdown_script_fuer_vis1 [12.10.2026] (aktuell) – gelöscht kolja | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | 🔔 Countdown-Widget (ioBroker VIS + MagicMirror) | ||
| - | Dieses Widget zeigt automatisch die zwei nächsten anstehenden Countdowns an | ||
| - | (z. B. Weihnachten, | ||
| - | |||
| - | Abgelaufene Countdowns werden automatisch ausgeblendet. | ||
| - | |||
| - | ⚠️ WICHTIGE HINWEISE (bitte lesen!) | ||
| - | |||
| - | JEDER Countdown muss im versteckten Subscribe-Block stehen | ||
| - | |||
| - | KEINE Einzeiler mit { ... } im JavaScript | ||
| - | |||
| - | Kein Array / kein Objekt-Literal | ||
| - | |||
| - | Code-Formatierung NICHT verändern | ||
| - | |||
| - | Sonst erscheint: | ||
| - | |||
| - | SyntaxError: | ||
| - | |||
| - | 🧩 1. Subscribe-Block (Pflicht!) | ||
| - | |||
| - | Hier meldet VIS alle benötigten Datenpunkte an. | ||
| - | |||
| - | <div style=" | ||
| - | {countdown.0.countdowns.Weihnachten.fullJson} | ||
| - | {countdown.0.countdowns.Silvester.fullJson} | ||
| - | {countdown.0.countdowns.SommerurlaubItalien.fullJson} | ||
| - | </ | ||
| - | |||
| - | |||
| - | 👉 Für jeden neuen Countdown MUSS hier eine Zeile ergänzt werden! | ||
| - | |||
| - | 🖼️ 2. Anzeige-HTML (2 Slots) | ||
| - | <div style=" | ||
| - | <div id=" | ||
| - | Lade... | ||
| - | </ | ||
| - | |||
| - | <div style=" | ||
| - | |||
| - | <div id=" | ||
| - | Lade... | ||
| - | </ | ||
| - | </ | ||
| - | |||
| - | |||
| - | Die IDs bleiben absichtlich so – sie sind MagicMirror-erprobt. | ||
| - | |||
| - | 🧠 3. JavaScript – Finale Version | ||
| - | |||
| - | ⚠️ NICHT kürzen, NICHT umformatieren | ||
| - | |||
| - | < | ||
| - | (function () | ||
| - | { | ||
| - | /* ========================================================== | ||
| - | | ||
| - | | ||
| - | |||
| - | const OID_1 = " | ||
| - | const OID_2 = " | ||
| - | const OID_3 = " | ||
| - | |||
| - | const EMPTY_TEXT = " | ||
| - | |||
| - | /* ========================================================== | ||
| - | | ||
| - | | ||
| - | |||
| - | function safeNum(x, fallback) | ||
| - | { | ||
| - | const n = Number(x); | ||
| - | if (Number.isFinite(n)) return n; | ||
| - | return fallback; | ||
| - | } | ||
| - | |||
| - | function parseFullJson(val) | ||
| - | { | ||
| - | if (val === null || val === undefined || val === "" | ||
| - | |||
| - | try | ||
| - | { | ||
| - | let t = val; | ||
| - | |||
| - | if (typeof t === " | ||
| - | { | ||
| - | t = t.trim(); | ||
| - | if (t.startsWith('"' | ||
| - | return JSON.parse(t); | ||
| - | } | ||
| - | |||
| - | return t; | ||
| - | } | ||
| - | catch (e) | ||
| - | { | ||
| - | return null; | ||
| - | } | ||
| - | } | ||
| - | |||
| - | function subline(s) | ||
| - | { | ||
| - | return "< | ||
| - | } | ||
| - | |||
| - | function dayWord(n) | ||
| - | { | ||
| - | if (n === 1) return " | ||
| - | return " | ||
| - | } | ||
| - | |||
| - | function hourWord(n) | ||
| - | { | ||
| - | if (n === 1) return " | ||
| - | return " | ||
| - | } | ||
| - | |||
| - | /* ========================================================== | ||
| - | | ||
| - | | ||
| - | |||
| - | function remainingSeconds(val) | ||
| - | { | ||
| - | const d = parseFullJson(val); | ||
| - | if (!d) return 999999999; | ||
| - | |||
| - | if (d.total && d.total.seconds !== undefined) | ||
| - | { | ||
| - | return safeNum(d.total.seconds, | ||
| - | } | ||
| - | |||
| - | const days = safeNum((d.total && d.total.days | ||
| - | const hours = safeNum((d.total && d.total.hours !== undefined) ? d.total.hours : d.hours, 0); | ||
| - | const mins = safeNum((d.total && d.total.minutes !== undefined) ? d.total.minutes : d.minutes, 0); | ||
| - | const secs = safeNum((d.total && d.total.seconds !== undefined) ? d.total.seconds : d.seconds, 0); | ||
| - | |||
| - | return (days * 86400) + (hours * 3600) + (mins * 60) + secs; | ||
| - | } | ||
| - | |||
| - | function isExpired(val) | ||
| - | { | ||
| - | return remainingSeconds(val) <= 0; | ||
| - | } | ||
| - | |||
| - | /* ========================================================== | ||
| - | | ||
| - | | ||
| - | |||
| - | function renderWeihnachten(val) | ||
| - | { | ||
| - | const data = parseFullJson(val); | ||
| - | const now = new Date(); | ||
| - | |||
| - | if (now.getMonth() === 11 && now.getDate() >= 24 && now.getDate() <= 26) | ||
| - | { | ||
| - | return "🎄 Frohe Weihnachten 🎄< | ||
| - | } | ||
| - | |||
| - | if (!data) return EMPTY_TEXT; | ||
| - | |||
| - | const days = safeNum(data.total.days, | ||
| - | const hours = safeNum(data.total.hours, | ||
| - | |||
| - | return "🎁 Weihnachten in " + days + " " + dayWord(days) + | ||
| - | " | ||
| - | } | ||
| - | |||
| - | function renderSilvester(val) | ||
| - | { | ||
| - | const data = parseFullJson(val); | ||
| - | const now = new Date(); | ||
| - | |||
| - | if (now.getMonth() === 11 && now.getDate() === 31) | ||
| - | { | ||
| - | return "🎇 Silvester heute"; | ||
| - | } | ||
| - | |||
| - | if (!data) return EMPTY_TEXT; | ||
| - | |||
| - | const days = safeNum(data.total.days, | ||
| - | const hours = safeNum(data.total.hours, | ||
| - | |||
| - | return "🕛 Silvester in " + days + " " + dayWord(days) + | ||
| - | " | ||
| - | } | ||
| - | |||
| - | function renderGeneric(val, | ||
| - | { | ||
| - | const data = parseFullJson(val); | ||
| - | if (!data) return EMPTY_TEXT; | ||
| - | |||
| - | const days = safeNum(data.total.days, | ||
| - | const hours = safeNum(data.total.hours, | ||
| - | |||
| - | return emoji + " " + title + " in " + days + " " + dayWord(days) + | ||
| - | " | ||
| - | } | ||
| - | |||
| - | /* ========================================================== | ||
| - | | ||
| - | | ||
| - | |||
| - | const E1_OID = OID_1; | ||
| - | const E2_OID = OID_2; | ||
| - | const E3_OID = OID_3; | ||
| - | |||
| - | function renderEvent(i, | ||
| - | { | ||
| - | if (i === 1) return renderWeihnachten(val); | ||
| - | if (i === 2) return renderSilvester(val); | ||
| - | if (i === 3) return renderGeneric(val, | ||
| - | return EMPTY_TEXT; | ||
| - | } | ||
| - | |||
| - | function pickTwo() | ||
| - | { | ||
| - | let b1 = -1; | ||
| - | let b2 = -1; | ||
| - | let r1 = 999999999; | ||
| - | let r2 = 999999999; | ||
| - | |||
| - | let r; | ||
| - | |||
| - | r = remainingSeconds(vis.states.attr(E1_OID + " | ||
| - | if (!isExpired(vis.states.attr(E1_OID + " | ||
| - | { | ||
| - | r2 = r1; b2 = b1; | ||
| - | r1 = r; b1 = 1; | ||
| - | } | ||
| - | |||
| - | r = remainingSeconds(vis.states.attr(E2_OID + " | ||
| - | if (!isExpired(vis.states.attr(E2_OID + " | ||
| - | { | ||
| - | r2 = r1; b2 = b1; | ||
| - | r1 = r; b1 = 2; | ||
| - | } | ||
| - | |||
| - | r = remainingSeconds(vis.states.attr(E3_OID + " | ||
| - | if (!isExpired(vis.states.attr(E3_OID + " | ||
| - | { | ||
| - | b2 = 3; | ||
| - | } | ||
| - | |||
| - | return String(b1) + " | ||
| - | } | ||
| - | |||
| - | function start() | ||
| - | { | ||
| - | const el1 = document.getElementById(" | ||
| - | const el2 = document.getElementById(" | ||
| - | |||
| - | function update() | ||
| - | { | ||
| - | const p = pickTwo().split(" | ||
| - | |||
| - | const v1 = vis.states.attr((p[0] === " | ||
| - | const v2 = vis.states.attr((p[1] === " | ||
| - | |||
| - | el1.innerHTML = renderEvent(Number(p[0]), | ||
| - | el2.innerHTML = renderEvent(Number(p[1]), | ||
| - | } | ||
| - | |||
| - | vis.states.bind(E1_OID + " | ||
| - | vis.states.bind(E2_OID + " | ||
| - | vis.states.bind(E3_OID + " | ||
| - | |||
| - | update(); | ||
| - | } | ||
| - | |||
| - | if (document.readyState === " | ||
| - | { | ||
| - | start(); | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | window.addEventListener(" | ||
| - | } | ||
| - | |||
| - | })(); | ||
| - | </ | ||
| - | |||
| - | ➕ Neuen Countdown hinzufügen (Checkliste) | ||
| - | Beispiel: countdown.0.countdowns.Herbsturlaub.fullJson | ||
| - | ✅ Schritt 1 – Subscribe-Block | ||
| - | {countdown.0.countdowns.Herbsturlaub.fullJson} | ||
| - | |||
| - | ✅ Schritt 2 – OID definieren | ||
| - | const OID_4 = " | ||
| - | |||
| - | ✅ Schritt 3 – Renderfunktion ergänzen | ||
| - | if (i === 4) return renderGeneric(val, | ||
| - | |||
| - | ✅ Schritt 4 – remainingSeconds / pickTwo erweitern | ||
| - | |||
| - | (analog zu Event 3) | ||