NEWS
Google Kalender (ICS) für Material Design & Mini-Kalender
-
Einleitung
Für ioBroker gibt es bereits einen Adapter zum Einbinden von Google-Kalendern. Da dieser jedoch einige Funktionen vermissen ließ, die ich für meine Visualisierung benötigte, habe ich ein eigenes Script erstellt. Dieses ist speziell auf die Darstellung in Material Design und meine Anforderungen zugeschnitten.
Das Script liest beliebig viele Google-Kalender über deren private ICS-Adresse ein, verarbeitet wiederkehrende Termine, ergänzt automatisch Feiertage (Deutschland oder Österreich) sowie Sommer- und Winterzeit und erzeugt zwei Datenpunkte für unterschiedliche Darstellungen.

Voraussetzungen
- JavaScript-Adapter
- Installiertes npm-Modul:
node-ical(als zusätzliches NPM-Paket - aktuelle Version: 0.26.1)
- Mindestens ein Google-Kalender mit privater ICS-Adresse
- Material Design (Scrounger 0.5.94) (VIS-1) für großen Kalender
- JSON oder Tabellen Widget für kleinen Kalender
@oliverio hier könntest du eventuell über vis-jsontemplate noch etwas beitragen
Konfiguration
Alle Einstellungen befinden sich übersichtlich am Anfang des Scripts und können ohne Änderungen am eigentlichen Code angepasst werden.
Konstante Beschreibung Mögliche Werte dp_MainDatenpunktpfad für die erzeugten Datenpunkte Beliebiger Datenpunktpfad BASE_URLPfad zu den Icons des Mini-Kalenders URL oder lokaler VIS-Pfad C1_PAST_DAYSVergangene Tage im großen Kalender Zahl ≥ 0 C1_FUTURE_DAYSZukünftige Tage im großen Kalender Zahl ≥ 0 M1_PAST_DAYSVergangene Tage im Mini-Kalender Zahl ≥ 0 M1_FUTURE_DAYSZukünftige Tage im Mini-Kalender Zahl ≥ 0 LANDLand für die Feiertagsberechnung DEoderATBundeslandBundesland für regionale Feiertage DE: BW,BY,BE,BB,HB,HH,HE,MV,NI,NW,RP,SL,SN,ST,SH,TH<br>AT:W,NÖ,OÖ,S,T,V,St,K,BCALENDARSEingebundene Google-Kalender Besitzer, ICS-Adresse, Farbe und Icon KEYWORD_STYLEIndividuelle Farben und Emojis Frei erweiterbar
Kalender konfigurieren
Jeder Google-Kalender wird in der Konstante
CALENDARSeingetragen.Beispiel:
{ owner: "Mama", url: "https://....basic.ics", color: "#a71b1b", img: BASE_URL + "Mama.png" }Bedeutung der einzelnen Einträge
Parameter Beschreibung ownerFrei wählbare Bezeichnung des Kalenders urlPrivate ICS-Adresse des Google-Kalenders colorStandardfarbe für die Darstellung im großen Kalender imgIcon für die Darstellung im Mini-Kalender Es können beliebig viele Kalender eingebunden werden.
Hinweis
Die Bezeichnung aus
ownerwird gleichzeitig als Filter für den Mini-Kalender verwendet.Dadurch können später gezielt Termine einzelner Kalender angezeigt werden, z. B.:
ALLEMamaPapaKindArbeitVerein
Die möglichen Filter entsprechen immer den vergebenen
owner-Namen.
Individuelle Schlüsselwörter
Über
KEYWORD_STYLEkönnen beliebige Schlüsselwörter definiert werden.Wird eines dieser Wörter im Titel eines Kalendereintrags gefunden, wird automatisch:
- eine eigene Farbe verwendet
- optional ein Emoji angehängt
Beispiele:
Schlüsselwort Ergebnis geburt🎂 und definierte Geburtstagsfarbe kiko🐱 und definierte Farbe loki🐱 und definierte Farbe Natürlich können beliebig viele eigene Begriffe ergänzt werden.
Die Erkennung erfolgt unabhängig von Groß- und Kleinschreibung.
Besondere Funktionen
Geburtstage
Geburtstage werden automatisch erkannt und entsprechend hervorgehoben.
Hierfür muss der Titel des Kalendereintrags lediglich das Wort „Geburtstag“ enthalten.
Beispiele:
- Geburtstag Oma
- Geburtstag Max
- Geburtstag Lisa Müller
Das Script erkennt den Begriff automatisch und versieht den Termin mit dem 🎂-Emoji sowie der in
KEYWORD_STYLEdefinierten Farbe.
"In Memory"-Einträge
Auch Gedenktage oder Jahrestage verstorbener Personen können automatisch erkannt werden.
Hierfür muss der Titel des Kalendereintrags den Text „In Memory“ enthalten.
Beispiele:
- In Memory Opa
- In Memory Oma
- In Memory Max Mustermann
Diese Termine werden im großen Kalender automatisch:
- grau dargestellt
- mit einem 🕯️-Emoji versehen
- bewusst dezent hervorgehoben
Im Mini-Kalender werden diese Einträge automatisch ausgeblendet, damit die Terminliste übersichtlich bleibt.
Die Erkennung erfolgt ebenfalls unabhängig von Groß- und Kleinschreibung.
Unterstützte Funktionen
Das Script bietet unter anderem:
- Einbindung beliebig vieler Google-Kalender
- Unterstützung wiederkehrender Termine
- Verarbeitung von Ausnahmen (EXDATE)
- Automatische Erkennung von Geburtstagen
- Automatische Erkennung von "In Memory"-Einträgen
- Gesetzliche Feiertage für Deutschland
- Gesetzliche Feiertage für Österreich
- Regionale Feiertage je Bundesland
- Automatische Anzeige von Sommer- und Winterzeit
- Individuelle Farben pro Kalender
- Individuelle Icons pro Kalender
- Keyword-Erkennung mit eigener Farbzuweisung
- Emoji-Unterstützung
- Transparente Darstellung bereits vergangener Termine
- Besitzerfilter für den Mini-Kalender
- Automatische Aktualisierung alle 5 Minuten
Datenpunkte
Das Script erstellt automatisch folgende Datenpunkte:
Datenpunkt Beschreibung 0_userdata.0.calendar.c1Daten für den großen Kalender (Material Design / Scrounger) 0_userdata.0.calendar.m1Daten für den Mini-Kalender 0_userdata.0.calendar.inhaberFilter für den Mini-Kalender Über den Datenpunkt
0_userdata.0.calendar.inhaberkann jederzeit festgelegt werden, welche Termine im Mini-Kalender angezeigt werden.Beispiele:
ALLEMamaPapaKindArbeitVerein
Die möglichen Werte entsprechen den unter
ownervergebenen Namen.
Feiertage
Das Script ergänzt automatisch gesetzliche Feiertage.
Unterstützt werden:
- Deutschland
- Österreich
Abhängig vom eingestellten Bundesland werden automatisch nur die gültigen regionalen Feiertage angezeigt.
Zusätzlich werden automatisch folgende Termine erzeugt:
- Beginn der Sommerzeit ☀️
- Beginn der Winterzeit ❄️
Anpassungsmöglichkeiten
Folgende Bereiche können jederzeit angepasst werden:
- Kalender hinzufügen oder entfernen
- Farben ändern
- Icons austauschen
- Anzeigezeiträume ändern
- Schlüsselwörter erweitern
- Land wechseln (
DE/AT) - Bundesland ändern
Hinweise
Für den Zugriff auf einen Google-Kalender wird dessen private ICS-Adresse benötigt.
Diese findet ihr in den Einstellungen des jeweiligen Kalenders unter „Geheime Adresse im iCal-Format“.
Die erzeugten Datenpunkte können anschließend direkt in Material Design (Scrounger) oder jeder anderen Visualisierung verwendet werden.
Feedback
Das Script ist aus meinen eigenen Anforderungen entstanden und wird bei Bedarf weiterentwickelt.
Ich freue mich über Verbesserungsvorschläge, Ideen oder Fehlerberichte. Vielleicht ist das Script auch für andere eine interessante Alternative oder Ergänzung zum vorhandenen Google-Kalender-Adapter.
Das Script (Code)
// === Google Kalender (ICS) für Material Design & Mini-Kalender === //Erst-Version 1.0.0 - 18.07.2026 //Ersteller Ro75. //Voraussetzungen (Version 1.0.0 getestet mit) //NodeJS: 22.22.x //Javascript-Adapter: 9.0.18 //Admin-Adapter: 7.8.23 //js-controler: 7.2.2 //********** START KONFIGURATION ********** // @ts-nocheck const dp_Main = "0_userdata.0.calendar."; //Pfad für Datenpunkt const BASE_URL = 'http://192.168.10.99:8082/vis.0/'; //Bildpfad für Kalenderbilder z.B. Familienbilder (Mama, Papa, Kind) const C1_PAST_DAYS = 30; // Anzahl Tage rückwärts für großen Kalender (materialdesign - Scrounger) (Vergangenheit) const C1_FUTURE_DAYS = 120; // Anzahl Tage vorwärts für großen Kalender (materialdesign - Scrounger) (Zukunft) const M1_PAST_DAYS = 0; // Anzahl Tage rückwärts für Minikalender (Vergangenheit) const M1_FUTURE_DAYS = 30; // Anzahl Tage vorwärts für Minikalender (Zukunft) // Deutschland (DE), Österreich (AT) const LAND = "DE"; //dein Land // Deutschland: Süden/Westen: BW (Baden-Württemberg), BY (Bayern), HE (Hessen), RP (Rheinland-Pfalz), SL (Saarland) // Deutschland: Norden/Osten: BE (Berlin), BB (Brandenburg), HB (Bremen), HH (Hamburg), MV (Mecklenburg-Vorpommern), NI (Niedersachsen), NW (Nordrhein-Westfalen), SN (Sachsen), ST (Sachsen-Anhalt), SH (Schleswig-Holstein), TH (Thüringen) // Österreichische Landespatrone: Josef (T,V), Florian (OÖ), Rupert (S), Leopold (W,NÖ), Martin (B), Klemens (K) const Bundesland = "SN"; // dein Bundesland // Liste aller eingebundenen Google-Kalender (jeweils private ICS-Adresse) const CALENDARS = [ { owner: "Mama", // Besitzer/Zuordnung - Nach dieser Bezeichnung kann auch ein Filter ("0_userdata.0.calendar.inhaber") gesetzt werden url: "https://calendar.google.com/calendar/ical/XXXXXXXXXXXXXXXXXXXXXXgmail.com/private-faXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/basic.ics", // private ICS-URL color: "#a71b1b", // Standardfarbe des Kalenders - großer Kalender (materialdesign - Scrounger) img: BASE_URL + "Mama.png" // Icon für Darstellung - kleiner Kalender }, { owner: "Kind", url: "https://calendar.google.com/calendar/ical/t3lYYYYYYYYYYYYYYYYYYYYYYYgroup.calendar.google.com/private-341YYYYYYYYYYYYYYYYYYYYYYYYYYYY/basic.ics", color: "#e4c441", img: BASE_URL + "Kind2.png" }, { owner: "Papa", url: "https://calendar.google.com/calendar/ical/0suZZZZZZZZZZZZZZZZZZZZZZZZ%40group.calendar.google.com/private-9e0ZZZZZZZZZZZZZZZZZZZZZZZZ/basic.ics", color: "#039be5", img: BASE_URL + "Papa.png" } ]; // Stilregeln für bestimmte Schlüsselwörter in Ereignisnamen (z.B. Farbe + Emoji) const KEYWORD_STYLE = { "geburt": { color: "#33B679", emoji: " 🎂" }, // Beispiel: Geburtstage - Ein Kalendereintrag lautet z.B. "Geburtstag Oma Helga" oder "Geburtstag Klaus" "kiko": { color: "#8E24AA", emoji: " 🐱" }, // Beispiel: benutzerdefinierte Namen - Ein Kalendereintrag lautet z.B. "Tierarzt Kiko" "loki": { color: "#8E24AA", emoji: " 🐱" } // Beispiel: benutzerdefinierte Namen - Ein Kalendereintrag lautet z.B. "Tierarzt Loki" }; //********************************** AB HIER KEINE ÄNDERUNGEN MEHR **********************************/ const ical = require('node-ical'); const axios = require('axios'); const DP_C1 = dp_Main + "c1"; const DP_M1 = dp_Main + "m1"; const DP_INHABER = dp_Main + "inhaber"; const HOLIDAYS_BY_STATE = { "Neujahr": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Karfreitag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Ostersonntag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Ostermontag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Tag der Arbeit": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Christi Himmelfahrt": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Pfingstmontag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Tag der Deutschen Einheit": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "1. Weihnachtsfeiertag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "2. Weihnachtsfeiertag": ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"], "Heilige Drei Könige": ["BW","BY","ST"], "Fronleichnam": ["BW","BY","HE","NW","RP","SL"], "Mariä Himmelfahrt": ["SL","BY"], "Reformationstag": ["BB","MV","SN","ST","TH","SH","HH","NI"], "Allerheiligen": ["BW","BY","NW","RP","SL"], "Buß- und Bettag": ["SN"] }; const HOLIDAYS_BY_STATE_AT = { "Neujahr": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Heilige Drei Könige": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Ostersonntag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Ostermontag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Staatsfeiertag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Christi Himmelfahrt": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Pfingstsonntag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Pfingstmontag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Fronleichnam": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Mariä Himmelfahrt": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Nationalfeiertag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Allerheiligen": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Mariä Empfängnis": ["W","NÖ","OÖ","S","T","V","St","K","B"], "1. Weihnachtsfeiertag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "2. Weihnachtsfeiertag": ["W","NÖ","OÖ","S","T","V","St","K","B"], "Josef": ["T","V"], "Florian": ["OÖ"], "Rupert": ["S"], "Leopold": ["W","NÖ"], "Martin": ["B"], "Klemens": ["K"] }; let cachedEvents = []; async function smartCreateState(id, value, common = {}) { if (!existsState(id)) { await createState(id, value, common); } } function setStateIfChanged(id, value) { const state = getState(id); if (!state) return; const old = state.val; const isObject = v => v !== null && typeof v === "object"; if (isObject(value)) { const newStr = JSON.stringify(value); let oldStr = null; if (typeof old === "string") oldStr = old; else if (isObject(old)) oldStr = JSON.stringify(old); if (newStr === oldStr) return; return setState(id, newStr, true); } if (old === value) return; setState(id, value, true); } async function initStates() { await smartCreateState(DP_C1, "[]", {read: true, write: false, type: "string", name: 'Kalender groß'}); await smartCreateState(DP_M1, "[]", {read: true, write: false, type: "string", name: 'Kalender klein'}); await smartCreateState(DP_INHABER, "ALLE", {read: true, write: true, type: "string", name: 'Inhaberfilter'}); } function hexToRgba(hex, alpha = 1) { hex = hex.replace(/^#/, ''); const bigint = parseInt(hex, 16); return `rgba(${(bigint >> 16) & 255}, ${(bigint >> 8) & 255}, ${bigint & 255}, ${alpha})`; } function fadeColor(hex, alpha = 0.25) { hex = hex.replace(/^#/, ''); const bigint = parseInt(hex, 16); let r = (bigint >> 16) & 255; let g = (bigint >> 8) & 255; let b = bigint & 255; r = Math.round(r + (255 - r) * 0.55); g = Math.round(g + (255 - g) * 0.55); b = Math.round(b + (255 - b) * 0.55); return `rgba(${r}, ${g}, ${b}, ${alpha})`; } function getKeywordColorEmoji(event, fallback) { const e = (event || "").toLowerCase(); for (const key in KEYWORD_STYLE) { if (e.includes(key)) return KEYWORD_STYLE[key]; } return { color: fallback, emoji: "" }; } function formatDate(date, format) { const pad = n => n.toString().padStart(2, '0'); const yyyy = date.getFullYear(); const mm = pad(date.getMonth() + 1); const dd = pad(date.getDate()); const HH = pad(date.getHours()); const MM = pad(date.getMinutes()); const f = { "YYYY-MM-DD HH:mm": `${yyyy}-${mm}-${dd} ${HH}:${MM}`, "DD.MM.YYYY HH:mm": `${dd}.${mm}.${yyyy} ${HH}:${MM}`, "DD.MM.YYYY": `${dd}.${mm}.${yyyy}`, "YYYY-MM-DD": `${yyyy}-${mm}-${dd}`, "HH:mm": `${HH}:${MM}` }; return f[format]; } function isInMemoryEvent(norm) { return norm.event.toLowerCase().includes("in memory"); } function lastSunday(year, month) { const d = new Date(year, month + 1, 0); while (d.getDay() !== 0) d.setDate(d.getDate() - 1); return d; } function getEasterDate(year) { const f = Math.floor; const G = year % 19; const C = f(year / 100); const H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30; const I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)); const J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7; const L = I - J; const month = 3 + f((L + 40) / 44); const day = L + 28 - 31 * f(month / 4); return new Date(year, month - 1, day); } function getHolidays(year) { const easter = getEasterDate(year); const add = (date, days) => new Date(date.getTime() + days * 86400000); if (LAND === "DE") { const MAP = HOLIDAYS_BY_STATE; const holidays = [ { name: "Neujahr 🎉", date: new Date(year, 0, 1), states: MAP["Neujahr"] }, { name: "Karfreitag 🎉", date: add(easter, -2), states: MAP["Karfreitag"] }, { name: "Ostersonntag 🎉", date: easter, states: MAP["Ostersonntag"] }, { name: "Ostermontag 🎉", date: add(easter, 1), states: MAP["Ostermontag"] }, { name: "Tag der Arbeit 🎉", date: new Date(year, 4, 1), states: MAP["Tag der Arbeit"] }, { name: "Christi Himmelfahrt 🎉", date: add(easter, 39), states: MAP["Christi Himmelfahrt"] }, { name: "Pfingstmontag 🎉", date: add(easter, 50), states: MAP["Pfingstmontag"] }, { name: "Tag der Deutschen Einheit 🎉", date: new Date(year, 9, 3), states: MAP["Tag der Deutschen Einheit"] }, { name: "1. Weihnachtsfeiertag 🎉", date: new Date(year, 11, 25), states: MAP["1. Weihnachtsfeiertag"] }, { name: "2. Weihnachtsfeiertag 🎉", date: new Date(year, 11, 26), states: MAP["2. Weihnachtsfeiertag"] }, { name: "Heilige Drei Könige 🎉", date: new Date(year, 0, 6), states: MAP["Heilige Drei Könige"] }, { name: "Fronleichnam 🎉", date: add(easter, 60), states: MAP["Fronleichnam"] }, { name: "Mariä Himmelfahrt 🎉", date: new Date(year, 7, 15), states: MAP["Mariä Himmelfahrt"] }, { name: "Reformationstag 🎉", date: new Date(year, 9, 31), states: MAP["Reformationstag"] }, { name: "Allerheiligen 🎉", date: new Date(year, 10, 1), states: MAP["Allerheiligen"] } ]; const bussbettag = (() => { const d = new Date(year, 10, 23); while (d.getDay() !== 3) d.setDate(d.getDate() - 1); return d; })(); holidays.push({ name: "Buß- und Bettag 🎉", date: bussbettag, states: MAP["Buß- und Bettag"] }); return holidays; } else if (LAND === "AT") { const MAP = HOLIDAYS_BY_STATE_AT; const holidays = [ { name: "Neujahr 🎉", date: new Date(year, 0, 1), states: MAP["Neujahr"] }, { name: "Heilige Drei Könige 🎉", date: new Date(year, 0, 6), states: MAP["Heilige Drei Könige"] }, { name: "Ostersonntag 🎉", date: easter, states: MAP["Ostersonntag"] }, { name: "Ostermontag 🎉", date: add(easter, 1), states: MAP["Ostermontag"] }, { name: "Staatsfeiertag 🎉", date: new Date(year, 4, 1), states: MAP["Staatsfeiertag"] }, { name: "Christi Himmelfahrt 🎉", date: add(easter, 39), states: MAP["Christi Himmelfahrt"] }, { name: "Pfingstsonntag 🎉", date: add(easter, 49), states: MAP["Pfingstsonntag"] }, { name: "Pfingstmontag 🎉", date: add(easter, 50), states: MAP["Pfingstmontag"] }, { name: "Fronleichnam 🎉", date: add(easter, 60), states: MAP["Fronleichnam"] }, { name: "Mariä Himmelfahrt 🎉", date: new Date(year, 7, 15), states: MAP["Mariä Himmelfahrt"] }, { name: "Nationalfeiertag 🎉", date: new Date(year, 9, 26), states: MAP["Nationalfeiertag"] }, { name: "Allerheiligen 🎉", date: new Date(year, 10, 1), states: MAP["Allerheiligen"] }, { name: "Mariä Empfängnis 🎉", date: new Date(year, 11, 8), states: MAP["Mariä Empfängnis"] }, { name: "1. Weihnachtsfeiertag 🎉", date: new Date(year, 11, 25), states: MAP["1. Weihnachtsfeiertag"] }, { name: "2. Weihnachtsfeiertag 🎉", date: new Date(year, 11, 26), states: MAP["2. Weihnachtsfeiertag"] }, { name: "Josef 🎉", date: new Date(year, 2, 19), states: MAP["Josef"] }, { name: "Florian 🎉", date: new Date(year, 4, 4), states: MAP["Florian"] }, { name: "Rupert 🎉", date: new Date(year, 8, 24), states: MAP["Rupert"] }, { name: "Leopold 🎉", date: new Date(year, 10, 15), states: MAP["Leopold"] }, { name: "Martin 🎉", date: new Date(year, 10, 11), states: MAP["Martin"] }, { name: "Klemens 🎉", date: new Date(year, 10, 23), states: MAP["Klemens"] } ]; return holidays; } return []; } function createHolidayEvents(year) { const list = getHolidays(year, LAND); const events = []; for (const h of list) { if (!h.states.includes(Bundesland)) continue; const start = new Date(h.date.getFullYear(), h.date.getMonth(), h.date.getDate(), 0, 0); const end = new Date(h.date.getFullYear(), h.date.getMonth(), h.date.getDate(), 23, 59); const norm = normalizeEvent({start, end, summary: h.name, description: "", location: "", datetype: "date"}, "Feiertag", "#880088", ""); events.push(norm); } const sommer = lastSunday(year, 2); { const start = new Date(sommer.getFullYear(), sommer.getMonth(), sommer.getDate(), 0, 0); const end = new Date(sommer.getFullYear(), sommer.getMonth(), sommer.getDate(), 23, 59); const norm = normalizeEvent({start, end, summary: "Beginn der Sommerzeit ☀️", description: "", location: "", datetype: "date"}, "Feiertag", "#ffaa00", ""); events.push(norm); } const winter = lastSunday(year, 9); { const start = new Date(winter.getFullYear(), winter.getMonth(), winter.getDate(), 0, 0); const end = new Date(winter.getFullYear(), winter.getMonth(), winter.getDate(), 23, 59); const norm = normalizeEvent({start, end, summary: "Beginn der Winterzeit ❄️", description: "", location: "", datetype: "date"}, "Feiertag", "#00aaff"); events.push(norm); } return events; } function normalizeEvent(evt, owner, color, img) { let start = evt.start; let end = evt.end; if (evt.datetype === 'date') { start = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0); end = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 23, 59); } return { startTime: start, endTime: end, isFullDay: evt.datetype === 'date', durationHours: (end - start) / 3600000, event: evt.summary || "", section: evt.description || "", location: evt.location || "", calColor: color, classRaw: owner, img: img }; } function renderEventC1(norm) { if (isInMemoryEvent(norm)) { norm.calColor = "#808080"; norm.event += " 🕯️"; } let start = formatDate(norm.startTime, "YYYY-MM-DD HH:mm"); let end = formatDate(norm.endTime, "YYYY-MM-DD HH:mm"); if (norm.isFullDay) { start = formatDate(norm.startTime, "YYYY-MM-DD"); end = formatDate(norm.endTime, "YYYY-MM-DD"); } const isPast = norm.endTime < new Date(); let bg = hexToRgba(norm.calColor, 0.6); let txt = "#ffffff"; if (isPast) { bg = fadeColor(norm.calColor, 0.25); txt = "#dddddd"; } const ce = getKeywordColorEmoji(norm.event, norm.calColor); return {start, end, name: norm.event + " " + norm.section + ce.emoji, color: bg, colorText: txt}; } function renderEventM1(norm, filter) { const owner = norm.classRaw; if (owner === "Feiertag") return null; if (isInMemoryEvent(norm)) return null; if (!(filter === "ALLE" || owner === filter)) return null; let start = formatDate(norm.startTime, "DD.MM.YYYY HH:mm"); let end = formatDate(norm.endTime, "HH:mm"); if (norm.isFullDay) { start = formatDate(norm.startTime, "DD.MM.YYYY"); end = start; } let e = norm.event; if (norm.section) e += ": " + norm.section; return { img: norm.img, zeit: `${start} - ${end}`, ereignis: e, ort: norm.location }; } async function loadICS(url) { try { const res = await axios.get(url); let txt = res.data; txt = txt.replace(/UNTIL=(\d{8})(?!T)/g, "UNTIL=$1T000000Z"); const raw = ical.parseICS(txt); const events = []; const now = new Date(); const rangeStart = new Date(now.getTime() - C1_PAST_DAYS * 86400000); const rangeEnd = new Date(now.getTime() + C1_FUTURE_DAYS * 86400000); for (const key in raw) { const e = raw[key]; if (!e || e.type !== "VEVENT") continue; const summary = e.summary || ""; const isBirthday = /geburtstag/i.test(summary); const isInMemory = /in memory/i.test(summary) || /geb\.\s*opa/i.test(summary); if (isBirthday) { events.push({start: e.start, end: e.end, summary: e.summary, description: e.description, location: e.location, datetype: e.datetype}); continue; } if (e.rrule && !isInMemory) { const opts = e.rrule.origOptions || {}; if (opts.freq === "YEARLY" || opts.freq === 1) { events.push({start: e.start, end: e.end, summary: e.summary, description: e.description, location: e.location, datetype: e.datetype}); continue; } let freq = opts.freq; if (typeof freq === "string") freq = freq.toUpperCase(); if ( freq === "WEEKLY" || freq === "DAILY" || freq === 2 || freq === 3 ) { const weekdayMap = {SU: 0, MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6}; let byweekday = []; const rawWeekdays = opts.byweekday || opts.byDay || []; if (Array.isArray(rawWeekdays)) { byweekday = rawWeekdays .map(w => { if (typeof w === "number") return w; if (typeof w === "string") return weekdayMap[w.toUpperCase()]; if (typeof w === "object" && w.weekday !== undefined) return w.weekday; return null; }) .filter(v => v !== null && v !== undefined); } const start = new Date(e.start); const until = opts.until || rangeEnd; let current = new Date(start); while (current <= until && current <= rangeEnd) { const weekday = current.getDay(); if (byweekday.length && !byweekday.includes(weekday)) { current.setDate(current.getDate() + 1); continue; } if (byweekday.length && (opts.interval || 1) > 1) { const diffDays = Math.floor((current - start) / 86400000); const currentWeek = Math.floor(diffDays / 7); if (currentWeek % opts.interval !== 0) { current.setDate(current.getDate() + 1); continue; } } if (current >= rangeStart) { const instStart = new Date(current); const instEnd = new Date(instStart.getTime() + (e.end - e.start)); const iso = instStart.getFullYear() + "-" + String(instStart.getMonth() + 1).padStart(2, "0") + "-" + String(instStart.getDate()).padStart(2, "0"); if (!(e.exdate && e.exdate[iso])) { events.push({start: instStart, end: instEnd, summary: e.summary, description: e.description, location: e.location, datetype: e.datetype}); } } current.setDate(current.getDate() + 1); } continue; } } events.push({start: e.start, end: e.end, summary: e.summary, description: e.description, location: e.location, datetype: e.datetype}); } return events; } catch (err) { console.error("ICS Fehler >>> " + err.message + " : " + err.stack); return null; } } async function loadAllICS() { let events = []; for (const cal of CALENDARS) { const list = await loadICS(cal.url); if (!list) continue; for (const evt of list) { const norm = normalizeEvent(evt, cal.owner, cal.color, cal.img); const ce = getKeywordColorEmoji(norm.event, norm.calColor); norm.calColor = ce.color; events.push(norm); } } const yearNow = new Date().getFullYear(); const yearNext = yearNow + 1; events.push(...createHolidayEvents(yearNow)); events.push(...createHolidayEvents(yearNext)); events.sort((a, b) => a.startTime - b.startTime); cachedEvents = events; } function applyFilter() { const now = new Date(); const M1_START = new Date(now.getTime() - M1_PAST_DAYS * 86400000); const M1_END = new Date(now.getTime() + M1_FUTURE_DAYS * 86400000); const filter = String(getState(DP_INHABER)?.val || "ALLE").trim(); const m1 = cachedEvents .filter(e => e.endTime >= M1_START && e.startTime <= M1_END) .map(e => renderEventM1(e, filter)) .filter(Boolean); setStateIfChanged(DP_M1, m1); } function updateC1() { const now = new Date(); const C1_START = new Date(now.getTime() - C1_PAST_DAYS * 86400000); const C1_END = new Date(now.getTime() + C1_FUTURE_DAYS * 86400000); const c1 = cachedEvents .filter(e => e.endTime >= C1_START && e.startTime <= C1_END) .map(e => renderEventC1(e)); setStateIfChanged(DP_C1, c1); } async function main() { await initStates(); await loadAllICS(); updateC1(); applyFilter(); } main(); on({ id: DP_INHABER, change: "ne" }, () => applyFilter()); schedule("*/5 * * * *", () => main());Das Kalender-Widget (Scounger materialdesign 0.5.94)
[{"tpl":"tplVis-materialdesign-Calendar","data":{"oid":"0_userdata.0.calendar.c1","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","calendarView":"month","vibrateOnMobilDevices":"50","calendarWeekdays":"1,2,3,4,5,6,0","calendarBorderColor":"#7fb5b5","calendarDayBackgroundColor":"#121212","calendarDayBackgroundOutsideColor":"#404040","calendarHeaderBackground":"#424242","calendarDayLabelFontSize":"14","calendarDayLabelFontFamily":"InterVariable","calendarDayLabelFontColor":"#efd01f","calendarDayLabelPreviousFontColor":"#12abab","calendarDayLabelTodayFontSize":"14","calendarDayLabelTodayFontFamily":"InterVariable","calendarDayLabelTodayFontColor":"#fa9300","calendarWeeksNumbersShow":true,"calendarWeeksNumbersBackground":"#12abab","calendarWeeksNumbersFontSize":"16","calendarWeeksNumbersFont":"InterVariable","calendarWeeksNumbersFontColor":"#ffffff","calendarDayButtonMonthViewGoTo":"week","calendarDayButtonWeekViewGoTo":"day","calendarDayButtonDayViewGoTo":"week","calendarDayButtonRippleEffectColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.button_hover","calendarDayButtonColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.button_background","calendarDayButtonFontSize":"16","calendarDayButtonFontFamily":"InterVariable","calendarDayButtonFontColor":"#ffffff","calendarDayButtonTodayColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.button_background_today","calendarDayButtonTodayFontSize":"16","calendarDayButtonTodayFontFamily":"InterVariable","calendarDayButtonTodayFontColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.button_text_today","controlShow":true,"controlButtonLayout":"outlined","controlPosition":"stretch","controlShowLabel":true,"controlButtonColor":"#a45119","controlButtonRippelEffectColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.control_panel_hover","controlIconColor":"#ffffff","controlTextSize":"15","controlTextFont":"InterVariable","controlTextColor":"#ffffff","calendarTimeAxisBackgroundColor":"#424242","calendarTimeAxisShortIntervals":true,"calendarTimeAxisHeaderBackgroundColor":"#mdwTheme:vis-materialdesign.0.colors.calendar.time_axis_background_header","calendarTimeAxisFontSize":"#mdwTheme:vis-materialdesign.0.fontSizes.calendar.time_axis","calendarTimeAxisFont":"RobotoCondensed-Regular","calendarTimeAxisFontColor":"#fa9300","calendarEventOverlapMode":"stack","calendarEventFontSize":"14","calendarEventFont":"InterVariable","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"calendarShortWeekdays":false,"calendarTimeAxisStartTime":"4","calendarTimeAxisEndTime":"23","calendarTimeAxisIntervalMinutes":"","calendarEventHeight":"25","calendarTimeAxisWidth":"","controlIconSize":"30","g_calendarCustomFormats":false,"clickSoundVolume":"0.5"},"style":{"left":"0px","top":"100px","width":"1918px","height":"894px","z-index":"2","opacity":"{0_userdata.0.HardwareInfo.DashBoard.Opacity}%","text-shadow":"3px 3px 4px #000"},"widgetSet":"materialdesign"}]Das kleine Kalender-Widget (Scounger JSON / TABLE materialdesign 0.5.94)
[{"tpl":"tplVis-materialdesign-Button-State","data":{"oid":"0_userdata.0.calendar.inhaber","g_fixed":false,"g_visibility":true,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":true,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"!=","visibility-val":"ALLE","visibility-groups-action":"hide","buttonStyle":"raised","vibrateOnMobilDevices":"50","buttontext":"","textFontFamily":"RobotoCondensed-Regular","textFontSize":"14","mdwButtonPrimaryColor":"rgba(31, 96, 196, 0.8)","mdwButtonSecondaryColor":"rgba(255,255,255,0.8)","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"value":"ALLE","g_lock":true,"autoLockAfter":"10","lockIconColor":"#mdwTheme:vis-materialdesign.0.colors.button.lock_icon","lockFilterGrayscale":"","labelWidth":"0","clickSoundVolume":"0.5","colorBgTrue":"","mdwButtonColorPress":"rgba(96, 22, 42, 0.8)","lockIconSize":"20","g_icon":true,"image":"/vis.0/Familie.png","iconPosition":"left","iconHeight":"42","visibility-oid":"0_userdata.0.calendar.inhaber"},"style":{"left":"1163px","top":"661px","z-index":"8","width":"44px","height":"44px","box-shadow":"3px 3px 8px 1px rgba(31, 96, 196, 0.45)","border-radius":"180px","border-width":"1px","border-color":"rgba(31, 96, 196, 0.8)","border-style":"solid"},"widgetSet":"materialdesign"},{"tpl":"tplVis-materialdesign-Button-State","data":{"oid":"0_userdata.0.calendar.inhaber","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":true,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"buttonStyle":"raised","vibrateOnMobilDevices":"50","mdwButtonPrimaryColor":"rgba(96, 22, 42, 0.8)","mdwButtonSecondaryColor":"rgba(255,255,255,0.8)","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"value":"Loreen","g_lock":true,"autoLockAfter":"10","lockIconColor":"#mdwTheme:vis-materialdesign.0.colors.button.lock_icon","lockFilterGrayscale":"","clickSoundVolume":"0.5","colorBgTrue":"","mdwButtonColorPress":"rgba(96, 22, 42, 0.8)","lockIconSize":"20","g_icon":true,"image":"/vis.0/Mama.png","iconPosition":"left","iconHeight":"40","visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","g_label":true,"buttontext":"","textFontFamily":"#mdwTheme:vis-materialdesign.0.fonts.button.default.text","textFontSize":"#mdwTheme:vis-materialdesign.0.fontSizes.button.default.text"},"style":{"left":"1220px","top":"661px","z-index":"8","width":"44px","height":"44px","box-shadow":"3px 3px 8px 1px rgba(96, 22, 42, 0.45)","border-radius":"180px","border-width":"1px","border-color":"rgba(96, 22, 42, 0.8)","border-style":"solid"},"widgetSet":"materialdesign"},{"tpl":"tplVis-materialdesign-Button-State","data":{"oid":"0_userdata.0.calendar.inhaber","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":true,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"buttonStyle":"raised","vibrateOnMobilDevices":"50","buttontext":"","textFontFamily":"RobotoCondensed-Regular","textFontSize":"14","mdwButtonPrimaryColor":"rgba(55, 135, 45, 0.8)","mdwButtonSecondaryColor":"rgba(255,255,255,0.8)","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"value":"Yasu","g_lock":true,"autoLockAfter":"10","lockIconColor":"#mdwTheme:vis-materialdesign.0.colors.button.lock_icon","lockFilterGrayscale":"","labelWidth":"0","clickSoundVolume":"0.5","colorBgTrue":"","mdwButtonColorPress":"rgba(96, 22, 42, 0.8)","lockIconSize":"20","g_icon":true,"image":"/vis.0/Kind2.png","iconPosition":"left","iconHeight":"40","visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"1277px","top":"661px","z-index":"8","width":"44px","height":"44px","box-shadow":"3px 3px 8px 1px rgba(55, 135, 45, 0.45)","border-radius":"180px","border-width":"1px","border-color":"rgba(55, 135, 45, 0.8)","border-style":"solid"},"widgetSet":"materialdesign"},{"tpl":"tplVis-materialdesign-Button-State","data":{"oid":"0_userdata.0.calendar.inhaber","g_fixed":false,"g_visibility":false,"g_css_font_text":false,"g_css_background":false,"g_css_shadow_padding":true,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"buttonStyle":"raised","vibrateOnMobilDevices":"50","buttontext":"","textFontFamily":"RobotoCondensed-Regular","textFontSize":"14","mdwButtonPrimaryColor":"rgba(224, 180, 0, 0.8)","mdwButtonSecondaryColor":"rgba(255,255,255,0.8)","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"value":"Ronny","g_lock":true,"autoLockAfter":"10","lockIconColor":"#mdwTheme:vis-materialdesign.0.colors.button.lock_icon","lockFilterGrayscale":"","labelWidth":"0","clickSoundVolume":"0.5","colorBgTrue":"","mdwButtonColorPress":"rgba(96, 22, 42, 0.8)","lockIconSize":"20","g_icon":true,"image":"/vis.0/Papa.png","iconPosition":"left","iconHeight":"40","visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide"},"style":{"left":"1334px","top":"661px","z-index":"8","width":"44px","height":"44px","box-shadow":"3px 3px 8px 1px rgba(224, 180, 0, 0.45)","border-radius":"180px","border-width":"1px","border-color":"rgba(224, 180, 0, 0.8)","border-style":"solid"},"widgetSet":"materialdesign"},{"tpl":"tplVis-materialdesign-Table","data":{"oid":"0_userdata.0.calendar.m1","g_fixed":false,"g_visibility":false,"g_css_font_text":true,"g_css_background":false,"g_css_shadow_padding":false,"g_css_border":false,"g_gestures":false,"g_signals":false,"g_last_change":false,"countCols":"3","tableLayout":"card","showHeader":false,"roundBorder":"true","headerTextSize":"#mdwTheme:vis-materialdesign.0.fontSizes.table.header","headerFontFamily":"#mdwTheme:vis-materialdesign.0.fonts.table.header","colorBackground":"transparent","colorHeaderRowBackground":"","colorHeaderRowText":"","colorRowBackground":"transparent","colorRowBackgroundHover":"transparent","colorRowText":"rgba(255,255,255,0.8)","borderColor":"transparent","dividers":"rgba(110, 70, 62, 0.25)","showColumn0":"true","colType0":"image","textAlign0":"left","colTextSize0":"#mdwTheme:vis-materialdesign.0.fontSizes.table.row","fontFamily0":"#mdwTheme:vis-materialdesign.0.fonts.table.row","showColumn1":"true","colType1":"text","textAlign1":"left","colTextSize1":"14","fontFamily1":"RobotoCondensed-Regular","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"dataJson":"","showColumn2":"true","colType2":"text","textAlign2":"left","colTextSize2":"14","fontFamily2":"RobotoCondensed-Regular","showColumn3":"true","colType3":"text","textAlign3":"left","colTextSize3":"14","fontFamily3":"RobotoCondensed-Regular","showColumn4":"true","colType4":"text","textAlign4":"center","colTextSize4":"#mdwTheme:vis-materialdesign.0.fontSizes.table.row","fontFamily4":"#mdwTheme:vis-materialdesign.0.fonts.table.row","imageSize0":"40","label0":" ","colNoWrap1":false,"columnWidth0":"58","colNoWrap0":true,"fixedHeader":true,"columnWidth1":"110","rowHeight":"55","columnWidth2":"200","visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","padding_left2":"0","padding_right2":"0","padding_left1":"5","padding_right1":"5","padding_left3":"0","padding_right3":"5"},"style":{"left":"664px","top":"695px","width":"732px","height":"284px","z-index":"8","text-shadow":"3px 3px 4px #000"},"widgetSet":"materialdesign"},{"tpl":"tplFrame","data":{"g_fixed":true,"g_visibility":false,"g_css_font_text":true,"g_css_background":true,"g_css_shadow_padding":true,"g_css_border":true,"g_gestures":false,"g_signals":false,"g_last_change":false,"visibility-cond":"==","visibility-val":1,"visibility-groups-action":"hide","title":"Familien - Kalender","title_color":"#ffffff","title_top":"2","title_left":"5","header_height":"23","header_color":"rgba(60, 75, 100, 0.10)","signals-cond-0":"==","signals-val-0":true,"signals-icon-0":"/vis/signals/lowbattery.png","signals-icon-size-0":0,"signals-blink-0":false,"signals-horz-0":0,"signals-vert-0":0,"signals-hide-edit-0":false,"signals-cond-1":"==","signals-val-1":true,"signals-icon-1":"/vis/signals/lowbattery.png","signals-icon-size-1":0,"signals-blink-1":false,"signals-horz-1":0,"signals-vert-1":0,"signals-hide-edit-1":false,"signals-cond-2":"==","signals-val-2":true,"signals-icon-2":"/vis/signals/lowbattery.png","signals-icon-size-2":0,"signals-blink-2":false,"signals-horz-2":0,"signals-vert-2":0,"signals-hide-edit-2":false,"lc-type":"last-change","lc-is-interval":true,"lc-is-moment":false,"lc-format":"","lc-position-vert":"top","lc-position-horz":"right","lc-offset-vert":0,"lc-offset-horz":0,"lc-font-size":"12px","lc-font-family":"","lc-font-style":"","lc-bkg-color":"","lc-color":"","lc-border-width":"0","lc-border-style":"","lc-border-color":"","lc-border-radius":10,"lc-zindex":0,"title_back":"transparent","name":"Rahmen","locked":false,"comment":"","class":"","filterkey":"","title_font":""},"style":{"left":"654px","top":"666px","z-index":"1","width":"750px","height":"319px","border-width":"1px","border-style":"solid","border-color":"rgba(60, 75, 100, 0.10)","border-radius":"10px","opacity":"{0_userdata.0.HardwareInfo.DashBoard.Opacity}%","box-shadow":"15px 18px 62px 0px rgba(0, 0, 0, 0.35)","font-family":"RobotoCondensed-Regular","font-style":"normal","font-variant":"small-caps","font-weight":"lighter","font-size":"medium","background":"#202020","background-color":"#000000","cursor":"","transform":"","color":"","text-shadow":"","line-height":"","letter-spacing":"","word-spacing":""},"widgetSet":"basic"}]Ich wünsche Euch viel Spaß und Erfolg bei der Umsetzung des Projekts.
Ro75.
-
Ist für mich nicht nachvollziehbar. Habe ehrlich gesagt im Moment keine Idee mehr. Was passiert wenn du mal einen Geburtstag, wie beschrieben, in den "normalen Kalender" einträgst. Da die Aktualisierung aller 5 Minuten ist (15:35, 15:40), müsstest du ja dann relativ schnell was sehen.
Ro75.
-
Ist für mich nicht nachvollziehbar. Habe ehrlich gesagt im Moment keine Idee mehr. Was passiert wenn du mal einen Geburtstag, wie beschrieben, in den "normalen Kalender" einträgst. Da die Aktualisierung aller 5 Minuten ist (15:35, 15:40), müsstest du ja dann relativ schnell was sehen.
Ro75.
Ist für mich nicht nachvollziehbar. Habe ehrlich gesagt im Moment keine Idee mehr. Was passiert wenn du mal einen Geburtstag, wie beschrieben, in den "normalen Kalender" einträgst. Da die Aktualisierung aller 5 Minuten ist (15:35, 15:40), müsstest du ja dann relativ schnell was sehen.
Ro75.
Hatte ich gerade schon gemacht

Wird angezeigt.Ich lege die Kalender bei Google mal neu an, mal sehen ob es dann klappt.
-
Fehler wohl gefunden, es liegt an den Einträgen bei Google.
Habe mal einen Geburtstag komplett gelöscht und dann neu angelegt und wieder mit der Angabe jedes Jahr.
Wird jetzt angezeigt, schwere Geburt bzw. keine Ahnung was Google da für ein Problem hatte.
Werde jetzt alle Daten komplett löschen und neu eingeben. -
Super, dass das Problem gefunden wurde. Google ändert hin und wieder was. Das letzte Mal vor ein paar Wochen. Da gab es Änderungen bei wiederkehrenden Terminen. Beim Google Kalender selbst kein Problem, aber es gab geänderte Infos in der ICS. Aber da ist bereits im Script berücksichtigt.
Ro75.
-
Ist echt ein Witz. Jahrelang keine Probleme mit Anzeige und dann ändern die was ohne
das man was mitbekommt. Naja, habe jetzt einige Termine in den jeweiligen Kalendern
gelöscht und eben neu angelegt, jetzt klappt es.Vielen Dank an Dich für die Hilfe.
-
-
Die Hintergrundfarbe für "In Memory", wo finde ich die?
Wenn das jetzt keine separater Kalender ist, dann:
function renderEventC1(norm) { if (isInMemoryEvent(norm)) { norm.calColor = "#808080"; norm.event += " 🕯️"; }Wenn eigenständiger Kalender: dann auch in der Kalender-Konfig
color: "#a71b1b", // Standardfarbe des Kalenders - großer Kalender (materialdesign - Scrounger) img: BASE_URL + "Mama.png" // Icon für Darstellung - kleiner Kalender },schauen.
Ro75.
-
Die Hintergrundfarbe für "In Memory", wo finde ich die?
Wenn das jetzt keine separater Kalender ist, dann:
function renderEventC1(norm) { if (isInMemoryEvent(norm)) { norm.calColor = "#808080"; norm.event += " 🕯️"; }Wenn eigenständiger Kalender: dann auch in der Kalender-Konfig
color: "#a71b1b", // Standardfarbe des Kalenders - großer Kalender (materialdesign - Scrounger) img: BASE_URL + "Mama.png" // Icon für Darstellung - kleiner Kalender },schauen.
Ro75.
@Ro75
Habe jetzt nicht alles gelesen, was ist der Fehler?
Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden 💗
Registrieren Anmelden
.