Skip to content

Skripten / Logik

Hilfe zu JavaScript, Blockly, TypeScript, Node-RED, Scenes und text2command

16.5k Themen 212.8k Beiträge

NEWS

Unterkategorien


  • Hilfe für Skripterstellung mit JavaScript

    2k 49k
    2k Themen
    49k Beiträge
    S
    Hallo zusammen, da wetter.com die alten API-Versionen abschaltet, habe ich ein neues Skript für die API v4.0 (Meteonomiqs) erstellt. (und weil es keinen Adapter dafür gibt) Das Skript ist darauf ausgelegt, "Plug & Play" zu funktionieren, die Daten sauber in 0_userdata.0 zu strukturieren und dabei die Limits des Free-Accounts (100 Abrufe/Monat) im Blick zu behalten. Features API v4.0 Support: Nutzt die aktuellen Endpunkte von Meteonomiqs/wetter.com. Automatische Struktur: Legt alle benötigten Ordner und Datenpunkte unter 0_userdata.0.wetter_com selbständig an. Standort-Automatik: Liest Breiten- und Längengrad direkt aus den ioBroker-Systemeinstellungen. Fallback/Override: Manuelle Koordinaten können im Skript hinterlegt werden (z.B. für Ferienhäuser). Limit-Wächter: Überwacht die Anzahl der API-Abrufe (täglich und monatlich). Bei Fehler 429 (Limit erreicht) wird eine Warnung ausgegeben und der Abruf gestoppt, statt das Log vollzuschreiben. Server-Schutz (Random Cron): Um die API nicht zu überlasten, wenn viele User das Skript nutzen, werden die Abrufzeiten bei jedem Skriptstart zufällig innerhalb sinnvoller Zeitfenster (morgens 00:02–05:00 Uhr und nachmittags 13:02–17:00 Uhr) generiert. Cleanup: Wenn man die Anzahl der Vorhersage-Tage reduziert, werden überflüssige Datenpunkte automatisch gelöscht. Datenpunkte: Datum Min/Max Temperatur Wetterzustand (Text & Code für Icons) Regenwahrscheinlichkeit & Menge Sonnenstunden Wind (Geschwindigkeit & Richtung) Voraussetzungen API Key: Ihr benötigt einen kostenlosen API-Key von Meteonomiqs/wetter.com. (Free-Paket wählen). https://www.meteonomiqs.com/de/wetter-api/#heading_PricePackages/ Koordinaten: Sollten in den ioBroker Haupteinstellungen (System -> Einstellungen) hinterlegt sein. (Kann im Skript, im Bereich "STANDORT KONFIGURATION", angepasst/geändert werden) Installation & Konfiguration Neues JS-Skript im ioBroker anlegen. Code hineinkopieren. Im Bereich --- KONFIGURATION --- euren API_KEY eintragen. Optional: FORECAST_DAYS anpassen (Standard: 7 Tage). info-Datenpunkt Unter 0_userdata.0.wetter_com.info findet ihr Datenpunkte wie requests_month oder next_schedules, die ihr in der VIS anzeigen könnt, um euren Verbrauch zu überwachen. Spoiler /** * ioBroker Script: Wetter.com Forecast API v4.0 * API: https://doc.meteonomiqs.com/doc/forecast_v4_0.html * * Changelog: * 1.4.6: Feature: Manuelle Standort-Konfiguration (Fallback & Override) hinzugefügt. * 1.4.5: FIX: Syntax-Fehler im Header behoben. * 1.4.4: Anpassung an Monatslimit (100 Requests). * 1.4.3: Korrektur "last_sync" Formatierung. * 1.4.1: Randomisierung der Abrufzeiten. * 1.4.0: Info-Datenpunkte hinzugefügt. * * free API-Key anfordern: https://www.meteonomiqs.com/de/wetter-api/#heading_PricePackages/ */ // --- KONFIGURATION --- const API_KEY = 'DEIN_API_KEY_HIER'; // <-- BITTE HIER DEINEN API-KEY EINTRAGEN const BASE_URL = 'https://forecast.meteonomiqs.com/v4_0'; const DP_PATH = '0_userdata.0.wetter_com'; const LANGUAGE = 'de-de'; const FORECAST_DAYS = 7; // --- STANDORT KONFIGURATION --- // Hier Koordinaten eintragen für Fallback oder spezifischen Standort (z.B. '52.520') const MANUAL_LATITUDE = ''; const MANUAL_LONGITUDE = ''; // true = Nutze IMMER die manuellen Koordinaten (Ignoriert ioBroker-Einstellungen) // false = Nutze manuelle Koordinaten nur als Fallback, falls im System keine hinterlegt sind const FORCE_MANUAL_LOCATION = false; // --- RANDOMISIERUNG DER ZEITEN --- /** * Erzeugt eine zufällige Cron-Zeit innerhalb eines Fensters * @param {number} startHour * @param {number} endHour * @param {number} minMinute (optional, z.B. 2 für 00:02) */ function getRandomCron(startHour, endHour, minMinute = 0) { const hour = Math.floor(Math.random() * (endHour - startHour + 1)) + startHour; let minute; if (hour === startHour) { minute = Math.floor(Math.random() * (60 - minMinute)) + minMinute; } else if (hour === endHour) { minute = 0; } else { minute = Math.floor(Math.random() * 60); } return `${minute} ${hour} * * *`; } // Zeitfenster 1: 00:02 bis 05:00 const cron1 = getRandomCron(0, 5, 2); // Zeitfenster 2: 13:02 bis 17:00 const cron2 = getRandomCron(13, 17, 2); console.log(`[Wetter.com] Schedules für heute gesetzt auf: "${cron1}" und "${cron2}"`); // --- HILFSFUNKTIONEN --- /** * Formatiert ein Datum manuell in deutsches Format: "DD.MM.YYYY" */ function formatToGermanDate(dateStr) { if (!dateStr) return ''; const date = new Date(dateStr); if (isNaN(date.getTime())) return dateStr; const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = date.getFullYear(); return `${day}.${month}.${year}`; } /** * Ermittelt die Koordinaten basierend auf Konfiguration und System-Einstellungen */ async function getCoordinates() { // 1. Override: Manuelle Koordinaten erzwingen if (FORCE_MANUAL_LOCATION && MANUAL_LATITUDE && MANUAL_LONGITUDE) { console.log(`[Wetter.com] Nutze manuell konfigurierte Koordinaten (Override).`); return { lat: parseFloat(MANUAL_LATITUDE).toFixed(3), lon: parseFloat(MANUAL_LONGITUDE).toFixed(3) }; } // 2. System: Versuche ioBroker Einstellungen zu lesen const systemCoords = await new Promise((resolve) => { getObject('system.config', (err, obj) => { if (!err && obj && obj.common && obj.common.latitude && obj.common.longitude) { resolve({ lat: parseFloat(obj.common.latitude).toFixed(3), lon: parseFloat(obj.common.longitude).toFixed(3) }); } else { resolve(null); } }); }); if (systemCoords) return systemCoords; // 3. Fallback: Nutze manuelle Koordinaten, falls System fehlschlug if (MANUAL_LATITUDE && MANUAL_LONGITUDE) { console.log('[Wetter.com] Warnung: Keine System-Koordinaten gefunden. Nutze Fallback-Koordinaten aus Skript.'); return { lat: parseFloat(MANUAL_LATITUDE).toFixed(3), lon: parseFloat(MANUAL_LONGITUDE).toFixed(3) }; } return null; } /** * Erstellt die Struktur inkl. Info-Datenpunkten */ async function ensureStructure(path, index, isInfo = false) { if (isInfo) { await createStateAsync(`${DP_PATH}.info.last_sync`, '', false, { name: 'Letztes erfolgreiches Update', type: 'string', role: 'text' }); await createStateAsync(`${DP_PATH}.info.requests_today`, 0, false, { name: 'Anfragen heute', type: 'number', role: 'value' }); await createStateAsync(`${DP_PATH}.info.requests_month`, 0, false, { name: 'Anfragen aktueller Monat', type: 'number', role: 'value' }); await createStateAsync(`${DP_PATH}.info.next_schedules`, '', false, { name: 'Geplante Abrufe', type: 'string', role: 'text' }); return; } const states = { 'date': { name: 'Datum', type: 'string', role: 'text', def: '' }, 'temp_max': { name: 'Max Temperatur', type: 'number', unit: '°C', role: 'value.temperature.max', def: 0 }, 'temp_min': { name: 'Min Temperatur', type: 'number', unit: '°C', role: 'value.temperature.min', def: 0 }, 'weather_text': { name: 'Wetterzustand', type: 'string', role: 'weather.state', def: '' }, 'weather_code': { name: 'Wetter Code', type: 'number', role: 'value', def: 0 }, 'prec_probability': { name: 'Regenrisiko', type: 'number', unit: '%', role: 'value.precipitation.probability', def: 0 }, 'prec_sum': { name: 'Regenmenge', type: 'number', unit: 'mm', role: 'value.precipitation', def: 0 }, 'sun_hours': { name: 'Sonnenstunden', type: 'number', unit: 'h', role: 'value.sunshine', def: 0 }, 'wind_speed_max': { name: 'Windböen Max', type: 'number', unit: 'km/h', role: 'value.speed.wind.gust', def: 0 }, 'wind_direction': { name: 'Windrichtung', type: 'string', role: 'weather.direction', def: '' } }; for (const [id, config] of Object.entries(states)) { const fullId = `${path}.${id}`; await createStateAsync(fullId, config.def, false, { name: `Tag ${index}: ${config.name}`, type: config.type, role: config.role, unit: config.unit || '', read: true, write: false }); } } async function performRequest(url, options) { return new Promise((resolve, reject) => { httpGet(url, options, (error, response) => { if (error) return reject(new Error(error)); if (response.statusCode === 429) return reject(new Error('LIMIT_REACHED')); if (response.statusCode !== 200) return reject(new Error(`HTTP Status ${response.statusCode}`)); resolve(response); }); }); } async function cleanupObsoleteDays() { const channels = $(`${DP_PATH}.day_*`); channels.each(function(id) { const parts = id.split('.'); const lastPart = parts[parts.length - 1]; const dayIndex = parseInt(lastPart.replace('day_', '')); if (!isNaN(dayIndex) && dayIndex >= FORECAST_DAYS) { deleteObject(id, true); } }); } /** * Aktualisiert die Info-Datenpunkte (Zähler und Zeitstempel) */ async function updateUsageInfo() { const now = new Date(); // Manuelle Formatierung const day = String(now.getDate()).padStart(2, '0'); const month = String(now.getMonth() + 1).padStart(2, '0'); const year = now.getFullYear(); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0'); const timestamp = `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`; await setStateAsync(`${DP_PATH}.info.last_sync`, String(timestamp), true); // Tageszähler erhöhen const currentCountState = await getStateAsync(`${DP_PATH}.info.requests_today`); const currentCount = currentCountState ? (currentCountState.val || 0) : 0; await setStateAsync(`${DP_PATH}.info.requests_today`, currentCount + 1, true); // Monatszähler erhöhen const currentMonthState = await getStateAsync(`${DP_PATH}.info.requests_month`); const currentMonthCount = currentMonthState ? (currentMonthState.val || 0) : 0; await setStateAsync(`${DP_PATH}.info.requests_month`, currentMonthCount + 1, true); const s1 = cron1.split(' '); const s2 = cron2.split(' '); await setStateAsync(`${DP_PATH}.info.next_schedules`, `${s1[1].padStart(2,'0')}:${s1[0].padStart(2,'0')} Uhr & ${s2[1].padStart(2,'0')}:${s2[0].padStart(2,'0')} Uhr`, true); } // --- LOGIK --- async function fetchWeatherData() { try { const coords = await getCoordinates(); if (!coords) { console.error('[Wetter.com] Fehler: Keine Koordinaten gefunden (Weder System noch Fallback)!'); return; } const url = `${BASE_URL}/forecast/${coords.lat}/${coords.lon}/summary`; const options = { headers: { 'x-api-key': API_KEY, 'Accept-Language': LANGUAGE } }; try { const response = await performRequest(url, options); const data = JSON.parse(response.data); if (data && data.items) { await processForecastData(data.items); await cleanupObsoleteDays(); await updateUsageInfo(); } } catch (err) { if (err.message === 'LIMIT_REACHED') { console.error('[Wetter.com] Fehler 429: Das monatliche Abruflimit (100 Anfragen) wurde erreicht.'); } else { console.error(`[Wetter.com] Fehler: ${err.message}`); } } } catch (e) { console.error(`[Wetter.com] Script-Fehler: ${e.message}`); } } async function processForecastData(items) { await ensureStructure('', 0, true); const daysToProcess = Math.min(items.length, FORECAST_DAYS); for (let i = 0; i < daysToProcess; i++) { const day = items[i]; const dayPath = `${DP_PATH}.day_${i}`; await ensureStructure(dayPath, i); await setStateAsync(`${dayPath}.date`, formatToGermanDate(day.date), true); await setStateAsync(`${dayPath}.temp_max`, day.temperature?.max ?? 0, true); await setStateAsync(`${dayPath}.temp_min`, day.temperature?.min ?? 0, true); await setStateAsync(`${dayPath}.weather_text`, day.weather?.text || '', true); await setStateAsync(`${dayPath}.weather_code`, day.weather?.state ?? 0, true); await setStateAsync(`${dayPath}.prec_probability`, day.prec?.probability ?? 0, true); await setStateAsync(`${dayPath}.prec_sum`, day.prec?.sum ?? 0, true); await setStateAsync(`${dayPath}.sun_hours`, day.sunHours ?? 0, true); await setStateAsync(`${dayPath}.wind_speed_max`, day.wind?.max ?? 0, true); await setStateAsync(`${dayPath}.wind_direction`, day.wind?.direction || '', true); } console.log(`[Wetter.com] Update von ${daysToProcess} Tagen abgeschlossen.`); } // Zähler jeden Tag um Mitternacht zurücksetzen schedule("0 0 * * *", () => { setState(`${DP_PATH}.info.requests_today`, 0, true); }); // Zähler jeden Monat (am 1. um 00:00) zurücksetzen schedule("0 0 1 * *", () => { setState(`${DP_PATH}.info.requests_month`, 0, true); }); schedule(cron1, fetchWeatherData); schedule(cron2, fetchWeatherData); ensureStructure('', 0, true).then(() => { fetchWeatherData(); });
  • Hilfe für Skripterstellung mit Blockly

    7k 79k
    7k Themen
    79k Beiträge
    K
    Viel einfacher: Ich nehme nehme den Wert von BSH_Common_Root_SelectedProgram und steuere damit BSH_Common_Root_ActiveProgram Somit wird die Maschine mit dem zuvor gewählten Programm gestartet. Habe jetzt nur noch ein Problem mit dem Trigger. Ich triggere auf BSH_Common_Status_RemoteControlStartAllowed=true, dann soll (für meinen Test) die Maschine ab einer bestimmten Uhrzeit starten. Das klappt mit folgendem Blockly aber nicht: [image: 1767878224143-bildschirmfoto-vom-2026-01-08-14-16-42-resized.png] Wenn ich einen Zeittrigger nehme, geht es ohne Probleme. Was mache ich hier falsch?
  • Hilfe für Skripterstellung mit Node-RED

    953 13k
    953 Themen
    13k Beiträge
    Thomas BraunT
    Für Portscans von extern verwende ich immer https://www.grc.com/x/ne.dll?bh0bkyd2
  • [gelöst] Anwesenheit mit OWFS und Homematic

    Verschoben
    4
    0 Stimmen
    4 Beiträge
    452 Aufrufe
    paul53P
    @Nassi: Aber warum so? ` Buttons änderen ihren Wert (true) nicht, sondern aktualisieren nur den Zeitstempel. on("owfs.0.wires.iButtonLila",... triggert nur bei Wertänderung. on({id: "owfs.0.wires.iButtonLila"},... triggert bei jeder Aktualisierung auch ohne Wertänderung.
  • Shelly Licht am, Vordach steuern

    Verschoben
    5
    1
    0 Stimmen
    5 Beiträge
    704 Aufrufe
    D
    Ok, hab den oberen Teil nachgebaut und das Licht selbst eingeschaltet. Mal sehen ob es von alleine ausgeht nachher.
  • Empfang mit mehreren 433MHz Empfänger

    Verschoben
    1
    0 Stimmen
    1 Beiträge
    259 Aufrufe
    Niemand hat geantwortet
  • Daten bzw. einzelne Datenpunkte auf externem FTP Server speichern

    Verschoben
    9
    0 Stimmen
    9 Beiträge
    2k Aufrufe
    S
    @BulldogISL@gmx.de, vielen Dank für Deine Mühe. Ich werde mir das mal zu gemüte führen und auf meinen Bedarf umstricken. Danke Christian
  • Remote Skript Debugging mit VSCode

    Verschoben
    3
    0 Stimmen
    3 Beiträge
    729 Aufrufe
    ruhr70R
    Vielleicht hilft das: viewtopic.php?f=20&t=4564&p=187360&hili … gen#p61477
  • Python Script in Exec ausführen

    Verschoben
    1
    0 Stimmen
    1 Beiträge
    319 Aufrufe
    Niemand hat geantwortet
  • Scripte funktionieren plötzlich teilweise nicht mehr

    Verschoben
    6
    0 Stimmen
    6 Beiträge
    530 Aufrufe
    apollon77A
    Zeig mal bitte das generierte Javascript
  • Display ansteuern über I2C-Bus

    Verschoben
    1
    0 Stimmen
    1 Beiträge
    178 Aufrufe
    Niemand hat geantwortet
  • [erledigt] Astro wird nur teilweise ausgeführt

    Verschoben
    9
    4
    0 Stimmen
    9 Beiträge
    911 Aufrufe
    S
    Also für mich ist das eher ein Problem mit Astro…gibt ja mehrere Threads dazu. Aber gut. Ich mach jetzt ne Zeitsteuerung, hab jetzt ewig probiert und es ist nur der Christbaum draußen.
  • Kapazitiver Füllstandsmesser an-pingen

    Verschoben
    5
    0 Stimmen
    5 Beiträge
    395 Aufrufe
    S
    Hallo Paul, ja, das könnte ich machen…...müsste den Zeitraum mal ausmessen von LOWBAT Signal erhalten bis keine Reaktion mehr kommt. Die Batterien halten insgesamt ca. 1/2 Jahr und das erste LOWBAT Signal kommt so vermutlich ca. nach 3-4 Monaten.....:( Jemand noch ne andere Idee? Kann man die nicht irgendwie an-ping’en? Vielen Dank für jede Hilfe!
  • [gelöst] Frage zu Intervall als Wartezeit

    Verschoben
    42
    0 Stimmen
    42 Beiträge
    5k Aufrufe
    S
    Kämpfe auch schon seit ner weile mit nem Script, mit ganz ähnlicher Funktion. Kann mal jemand darüber schauen ob das überhaupt so funktionieren kann .. :roll: Log sagt folgendes: javascript.0 2018-12-09 19:22:34.140 error Error by subscription: empty ID defined. All states matched. 6131_unbenannt.png
  • Skript ASUS benutzte RAM in % berechnen

    Verschoben
    3
    1
    0 Stimmen
    3 Beiträge
    310 Aufrufe
    hananH
    Habe mal etwas gefunden und probiert, leider noch ohne Erfolg… const idQuelle = "rpi2.0.uptime.uptime", idZiel = "hm-rega.0.3998"; function formatminutes(idQuelle) { function form(x) { return ((x > 9) ? x :"0" + x); } var minutes = Math.floor(idQuelle/60000); var days = Math.floor(minutes /1440); minutes = minutes - days * 1440; var hours = Math.floor(minutes / 60); minutes = minutes - hours * 60; return ((days !== 0)? days + " days, ") + form(hours) + ":" + form(minutes); } Wie kann ich die Millisekunden aus dem Datenpunkt holen, umrechnen in Tag, h:m und dieses in die SV Typ Zeichenkette schreiben.
  • Vorlage angepasst, funktioniert nicht

    Verschoben
    2
    0 Stimmen
    2 Beiträge
    267 Aufrufe
    N
    Keiner?
  • Ifttt Abfrage als Trigger zum schalten.

    Verschoben
    3
    1
    0 Stimmen
    3 Beiträge
    345 Aufrufe
    paul53P
    Es fehlt der Trigger ! [image: 493_blockly_ifttt_trigger.jpg] value ist eine vordefinierte Variable, die den Wert des Trigger-Datenpunktes enthält.
  • Anfängerfrage: keine Node-red Objekte / Vis

    Verschoben
    1
    0 Stimmen
    1 Beiträge
    267 Aufrufe
    Niemand hat geantwortet
  • Batteriezustand aller Geräte

    Verschoben
    8
    1
    0 Stimmen
    8 Beiträge
    2k Aufrufe
    B
    Hallo, sorry, dass ich das hier noch mal aufmache, das war as Beste was ich zu dem Thema gefunden habe. Ich hab seit gestern ioB am laufen und einige ZigBee Sensoren integriert. Nun würde ich gerne den Zustand aller Batterie in einem Diagram darstellen (ebenso später alle Temperaturen, Bewegungen, … in je einem anderen, eigenen Diagram ). Mit Flot habe ich das für einzelne Werte (bzw. mehrere einzeln hinzugefügt) schon hinbekommen. Leider unterstützt Flot keine Wildcards im Sinne von zigbee.0.*.battery. Hat Jemand eine Tipp wie ich das am besten realisiere, bzw wo ich das aus dem ersten Eintrag: "als function unter Aufzählungen habe ich manuell die funktion "Batterie" angelegt" eingebe. ? Vielen Dank, Peter 14246_2018-12-09_11_12_45-flot_edit.png 14246_2018-12-09_11_13_47-objects_-_iobroker.png
  • Anfängerfrage An/Aus

    Verschoben
    4
    0 Stimmen
    4 Beiträge
    337 Aufrufe
    Homer.J.H
    Morgen, Versuch es mal so. ! if (msg.payload === "false"||msg.payload === "off"){ ! msg.payload = false; ! } else { ! msg.payload = true; ! } ! return msg; 5373_screenshot_2018-12-09_node-red-0_-_iobroker.png
  • Werte in Objekte zusammen rechnen

    Verschoben
    7
    0 Stimmen
    7 Beiträge
    804 Aufrufe
    L
    Doch, hast du [image: 1564_2018-12-08.png]
  • Mein erstes Skript

    Verschoben
    4
    1
    0 Stimmen
    4 Beiträge
    445 Aufrufe
    J
    Na die Einträge im Zeitpaln mit Klammer und dem ganzen Zeug das hier nicht hingehört. OK, sehe gerade, dass das nun mit dem neuen Javascrit auch möglich ist. Kannte ich so noch nicht.
  • [gelöst] Zeitgesteuertes Ausschalten, nur wie?

    Verschoben
    2
    1
    0 Stimmen
    2 Beiträge
    302 Aufrufe
    Beliar_666B
    HHabs grad selber hinbekommen. Zumindest hat es jetzt mal so funktioniert. [image: 9141_timer2.png]

867

Online

32.6k

Benutzer

81.9k

Themen

1.3m

Beiträge