Hi, ich hab mal ChatGPT gefragt und das hat mir ein Script erstellt, das ist echt mal Megagenial 
Allerdings geht schreiben nur in einen Nextcloud Kalender und nicht in den Google Kalender.
Um in den Google Kalender zu schreiben benötigt man wohl einen Google Cloud Account und Zugriff auf die Google API, was aber kostenpflichtig ist.
Falls einer das Script möchte, hier ist es.
Es überwacht den Datenpunkt "0_userdata.0.Button" vom Typ Boolean. Wenn dieser "true" wird, wird ein Eintrag im Kalender gemacht.
Es wird auch geprüft ob bereits ein Eintrag gemacht wurde, wenn das der Fall ist wird kein zweiter Eintrag gemacht.
Im Script müssen angepasst werden: calendarUrl, username, password. Und der Eintrag den man machen möchte.
In meinem Beispiel ist das der Text "Medikamente heute eingenommen".
const http = require('http');
const https = require('https');
const url = require('url');
const calendarUrl = '<ANPASSEN>';
const username = '<ANPASSEN>';
const password = '<ANPASSEN>';
const CREATE_ON_CHECK_ERROR = false;
function pad(n){ return n < 10 ? '0' + n : '' + n; }
function caldavDateUTC(d){
return d.getUTCFullYear().toString() +
pad(d.getUTCMonth() + 1) +
pad(d.getUTCDate()) + 'T' +
pad(d.getUTCHours()) +
pad(d.getUTCMinutes()) +
pad(d.getUTCSeconds()) + 'Z';
}
function localDateNoZ(d){
return d.getFullYear().toString() +
pad(d.getMonth() + 1) +
pad(d.getDate()) + 'T' +
pad(d.getHours()) +
pad(d.getMinutes()) +
pad(d.getSeconds());
}
// Allgemeine HTTP-Request-Funktion
function httpRequest(options, body, callback) {
const parsedUrl = url.parse(options.url);
const lib = parsedUrl.protocol === 'https:' ? https : http;
const auth = Buffer.from(options.auth || '').toString('base64');
const reqOptions = {
hostname: parsedUrl.hostname,
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
path: parsedUrl.path,
method: options.method || 'GET',
headers: options.headers || {}
};
if (auth) reqOptions.headers['Authorization'] = 'Basic ' + auth;
const req = lib.request(reqOptions, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => { callback(null, res, data); });
});
req.on('error', (err) => { callback(err); });
if (body) req.write(body);
req.end();
}
// Prüfen, ob heute schon ein Termin existiert
function checkEventToday(callback) {
const now = new Date();
const localStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0,0,0);
const localEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate()+1, 0,0,0);
const timeMin = caldavDateUTC(localStart);
const timeMax = caldavDateUTC(localEnd);
const xml = '<?xml version="1.0" encoding="utf-8"?>' +
'<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">' +
' <D:prop>' +
' <D:getetag/>' +
' <C:calendar-data/>' +
' </D:prop>' +
' <C:filter>' +
' <C:comp-filter name="VCALENDAR">' +
' <C:comp-filter name="VEVENT">' +
' <C:time-range start="' + timeMin + '" end="' + timeMax + '"/>' +
' </C:comp-filter>' +
' </C:comp-filter>' +
' </C:filter>' +
'</C:calendar-query>';
httpRequest({
url: calendarUrl,
method: 'REPORT',
auth: username + ':' + password,
headers: { 'Content-Type': 'application/xml', 'Depth': '1' }
}, xml, function(error, response, body) {
if (error) {
log("❌ Fehler beim Prüfen der Events: " + error, 'error');
return callback(null, CREATE_ON_CHECK_ERROR ? false : true);
}
const status = response ? response.statusCode : 'no-response';
log("DEBUG: REPORT Status: " + status, 'debug');
if (status < 200 || status >= 300) {
log("⚠️ Ungewöhnlicher REPORT-Status: " + status, 'warn');
return callback(null, CREATE_ON_CHECK_ERROR ? false : true);
}
let caldata = body.toString().replace(/\r\n[ \t]/g, '').replace(/\r\n/g, '\n');
const summaryRegex = /(^|\n)SUMMARY(?:;[^:]*)?:\s*Medikamente heute eingenommen(\n|$)/i;
const exists = summaryRegex.test(caldata);
callback(null, exists);
});
}
// Event erstellen
function createEvent() {
const now = new Date();
const uid = Date.now() + '@iobroker';
const startLocal = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 6,0,0);
const endLocal = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 20,0,0);
const dtstamp = caldavDateUTC(new Date());
const dtStartLocal = localDateNoZ(startLocal);
const dtEndLocal = localDateNoZ(endLocal);
const ics =
"BEGIN:VCALENDAR\n" +
"VERSION:2.0\n" +
"PRODID:-//ioBroker//DE\n" +
"BEGIN:VEVENT\n" +
"UID:" + uid + "\n" +
"DTSTAMP:" + dtstamp + "\n" +
"DTSTART;TZID=Europe/Berlin:" + dtStartLocal + "\n" +
"DTEND;TZID=Europe/Berlin:" + dtEndLocal + "\n" +
"SUMMARY:Medikamente heute eingenommen\n" +
"END:VEVENT\n" +
"END:VCALENDAR";
const filename = encodeURIComponent("medikamente-" + uid + ".ics");
const eventUrl = calendarUrl + filename;
httpRequest({
url: eventUrl,
method: 'PUT',
auth: username + ':' + password,
headers: { 'Content-Type': 'text/calendar; charset=utf-8' }
}, ics, function(error, response) {
if (error) {
log("❌ Fehler beim Erstellen des Events: " + error, 'error');
return;
}
const status = response ? response.statusCode : 'no-response';
log("DEBUG: PUT Status: " + status, 'debug');
if (status >= 200 && status < 300) {
log("✅ Termin erfolgreich erstellt", 'info');
} else {
log("⚠️ Unerwartete Antwort beim Erstellen: " + status, 'warn');
}
});
}
// Button überwachen
on({id: '0_userdata.0.Button', change: 'any'}, function(obj) {
if (obj.state.val === true) {
checkEventToday(function(err, exists) {
if (exists) {
log("ℹ️ Heute existiert bereits ein 'Medikamente heute eingenommen'-Termin — kein neuer Eintrag.", 'info');
} else {
createEvent();
}
});
}
});