Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. #Stauerkennung #DieAutobahn

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    1.6k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    850

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.1k

#Stauerkennung #DieAutobahn

Geplant Angeheftet Gesperrt Verschoben JavaScript
54 Beiträge 9 Kommentatoren 1.1k Aufrufe 11 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • R Offline
    R Offline
    Rushmed
    Most Active
    schrieb am zuletzt editiert von
    #45

    Ok, danke das funktioniert.
    In anderen JSON kann ich aber einfach über den Baustein:

    grafik.png

    die Informationen extrahieren.

    Bspw diese JSON aus dem Alexa Adapter:

    {"name":"Küche Studio","serialNumber":"G2A0XX47103500JT","summary":"licht aus","creationTime":1767132098880,"domainApplicationId":"","domainApplicationName":"","cardContent":"","card":"","answerText":"","utteranceType":"DEVICE_ARBITRATION","domain":"","intent":"Unknown"}
    

    f7f126c9-ff74-42b9-adba-3fcca5df0f74-grafik.png

    Das ist doch bestimmt so ein Object/String/JSO-was weiß ich was Ding.

    Ich bin begeistert von deinem Script weil es einfach ist!
    Der Radar-Trap Adapter bietet sauviele (für mich zuviele) Informationen die sicher mit einer VIS toll habdlebar sind.
    Ich bekomme dort mit zwei Routen und einem Gebiet 782 DPs und der rüsslt mir 150 MB RAM weg. Das ist Overkill für meine Anwendung.
    Das brauche ich alles nicht.
    Ich möchte hauptsächlich Infos zu Verkehrsproblemen für mein Strecke zuhause --> Arbeit und andersrum haben. Da passt das was dein Script leistet schon gut.

    Was ich brauche ist eine per Blockly gut handlebare JSON.
    Damit kann ich meine Alexa Morgenroutine genauso gut füttern wie eine Telegram Meldung zum Feierabend.

    Wie gesagt, es wäre toll wenn man Richtungen unterscheiden könnte, keine Ahnung ob das geht.

    Die Zeilenumbrüche (\n) brauche ich in der JSON nicht. Gerne können dafür weitere Atrribute dazu kommen, wie im Original mit "description 1....x".

    Die Blitzer Interessieren mich sowiesonicht und meine Strecke besteht zu 90% aus Autobahn.

    Danke vorab und einen guten Rutsch!

    1 Antwort Letzte Antwort
    0
    • R Rushmed

      @hotze
      Wenn ich versuche die JSON per Blockly zu zerlegen.
      Etwa so:
      c71f926e-b1bd-480b-989f-e6b6b47270e6-grafik.png

      Kommt immer:

      javascript.0	19:15:20.474	error	
      Cannot parse "0_userdata.0.Verkehr_JSON": SyntaxError: Unexpected non-whitespace character after JSON at position 1 (line 1 column 2)
      

      Können die Infomeldungen im LOG auch auf Debug umgestellt werden?

      Wenn ichs so probiere kommt immer "undefined":
      befc2179-e8a6-4f61-94ba-30e26c4ef858-grafik.png

      haus-automatisierungH Online
      haus-automatisierungH Online
      haus-automatisierung
      Developer Most Active
      schrieb am zuletzt editiert von
      #46

      @Rushmed sagte in #Stauerkennung #DieAutobahn:

      @hotze
      Wenn ich versuche die JSON per Blockly zu zerlegen.
      Etwa so:
      c71f926e-b1bd-480b-989f-e6b6b47270e6-grafik.png

      Die Objekt ID ist ja ein String (daher ist der Baustein ja auch grün, wie alle Strings). Das ist also kein gültiges JSON. Der state.val wird ja JSON sein. Also "Wert von Objekt ...". So wie Du es unten zeigst.

      @Rushmed sagte in #Stauerkennung #DieAutobahn:

      Ok, danke das funktioniert.
      In anderen JSON kann ich aber einfach über den Baustein:

      grafik.png

      die Informationen extrahieren.

      So ist es richtig. Bitte kein komischen Teilstrings suchen und extrahieren. So arbeitet man nicht mit JSON. Zeig am besten mal das JSON und was Du haben möchtest. Dann kann man auch helfen die Eigenschaften zu extrahieren. Du hast ja nur die Objekt-Definition aus der Objekt-Datenbank geteilt. Nicht den State.

      🧑‍🎓 Autor des beliebten ioBroker-Master-Kurses
      🎥 Tutorials rund um das Thema DIY-Smart-Home: https://haus-automatisierung.com/
      📚 Meine inoffizielle ioBroker Dokumentation

      H 1 Antwort Letzte Antwort
      0
      • haus-automatisierungH haus-automatisierung

        @Rushmed sagte in #Stauerkennung #DieAutobahn:

        @hotze
        Wenn ich versuche die JSON per Blockly zu zerlegen.
        Etwa so:
        c71f926e-b1bd-480b-989f-e6b6b47270e6-grafik.png

        Die Objekt ID ist ja ein String (daher ist der Baustein ja auch grün, wie alle Strings). Das ist also kein gültiges JSON. Der state.val wird ja JSON sein. Also "Wert von Objekt ...". So wie Du es unten zeigst.

        @Rushmed sagte in #Stauerkennung #DieAutobahn:

        Ok, danke das funktioniert.
        In anderen JSON kann ich aber einfach über den Baustein:

        grafik.png

        die Informationen extrahieren.

        So ist es richtig. Bitte kein komischen Teilstrings suchen und extrahieren. So arbeitet man nicht mit JSON. Zeig am besten mal das JSON und was Du haben möchtest. Dann kann man auch helfen die Eigenschaften zu extrahieren. Du hast ja nur die Objekt-Definition aus der Objekt-Datenbank geteilt. Nicht den State.

        H Offline
        H Offline
        Hotze
        schrieb am zuletzt editiert von
        #47

        @haus-automatisierung @rushmed

        Das JSON sieht so aus:

        [
         {
           "road": "A1",
           "title": "A1 | Wuppertal-Langerfeld - Wuppertal-Nord",
           "description": "Beginn: 31.12.25 um 13:40 Uhr\nAngespannte Verkehrslage, seit 31.12.2025, 13:40\nA1: Köln -> Dortmund, zwischen 0.6 km hinter AS Wuppertal-Langerfeld und 3.1 km vor AK Wuppertal-Nord\nIm Stillstand\nDurchschnittsgeschwindigkeit: 43 km/h",
           "start": "2025-12-31T13:40:00+01:00",
           "coordinate": {
             "lat": 51.28829864653024,
             "lon": 7.257013201816567
           },
           "mapLink": "https://www.google.com/maps/@51.28829864653024,7.257013201816567,13.13z"
         },
         {
           "road": "A1",
           "title": "A1 | Münster-Süd - Münsterland",
           "description": "Beginn: 31.12.25 um 11:36 Uhr\nFahrzeug-Hindernis, seit 31.12.2025, 11:36\nA1: Dortmund -> Osnabrück, zwischen 2.7 km hinter AK Münster-Süd und 0.3 km vor Münsterland\nGefahr durch ein defektes Fahrzeug auf der Fahrbahn",
           "start": "2025-12-31T11:36:00+01:00",
           "coordinate": {
             "lat": 51.93859014791594,
             "lon": 7.551148744931167
           },
           "mapLink": "https://www.google.com/maps/@51.93859014791594,7.551148744931167,13.13z"
         }
        ]
        

        Ich habe einen Abschnitt mit zwei meldungen erstellt, denn das kann ja mal vorkommen!
        Was Blocklys an geht bin ich aber auch kein Held!

        Man könnte im Script einstellen für jede meldung einen Datenpunkt zu erzeugen. Oder auch ein Verzeichnis pro Meldung und dort für jeden Punkt im JSON einen Datenpunkt.
        Das würde aber wiederum nicht so sparsam sein wie ich es gerne hätte.

        haus-automatisierungH 1 Antwort Letzte Antwort
        0
        • H Hotze

          @haus-automatisierung @rushmed

          Das JSON sieht so aus:

          [
           {
             "road": "A1",
             "title": "A1 | Wuppertal-Langerfeld - Wuppertal-Nord",
             "description": "Beginn: 31.12.25 um 13:40 Uhr\nAngespannte Verkehrslage, seit 31.12.2025, 13:40\nA1: Köln -> Dortmund, zwischen 0.6 km hinter AS Wuppertal-Langerfeld und 3.1 km vor AK Wuppertal-Nord\nIm Stillstand\nDurchschnittsgeschwindigkeit: 43 km/h",
             "start": "2025-12-31T13:40:00+01:00",
             "coordinate": {
               "lat": 51.28829864653024,
               "lon": 7.257013201816567
             },
             "mapLink": "https://www.google.com/maps/@51.28829864653024,7.257013201816567,13.13z"
           },
           {
             "road": "A1",
             "title": "A1 | Münster-Süd - Münsterland",
             "description": "Beginn: 31.12.25 um 11:36 Uhr\nFahrzeug-Hindernis, seit 31.12.2025, 11:36\nA1: Dortmund -> Osnabrück, zwischen 2.7 km hinter AK Münster-Süd und 0.3 km vor Münsterland\nGefahr durch ein defektes Fahrzeug auf der Fahrbahn",
             "start": "2025-12-31T11:36:00+01:00",
             "coordinate": {
               "lat": 51.93859014791594,
               "lon": 7.551148744931167
             },
             "mapLink": "https://www.google.com/maps/@51.93859014791594,7.551148744931167,13.13z"
           }
          ]
          

          Ich habe einen Abschnitt mit zwei meldungen erstellt, denn das kann ja mal vorkommen!
          Was Blocklys an geht bin ich aber auch kein Held!

          Man könnte im Script einstellen für jede meldung einen Datenpunkt zu erzeugen. Oder auch ein Verzeichnis pro Meldung und dort für jeden Punkt im JSON einen Datenpunkt.
          Das würde aber wiederum nicht so sparsam sein wie ich es gerne hätte.

          haus-automatisierungH Online
          haus-automatisierungH Online
          haus-automatisierung
          Developer Most Active
          schrieb am zuletzt editiert von haus-automatisierung
          #48

          @Hotze sagte in #Stauerkennung #DieAutobahn:

          Was Blocklys an geht bin ich aber auch kein Held!

          Das kann man ja lernen. Soll ja ganz ausführlicher Lerninhalte geben ;)

          Das ist ein Array aus Objekten. Also erstmal über den Index zugreifen: 0.road bzw. 1.road. Alternativ mit einer Schleife über alle Objekte gehen:

          Screenshot 2025-12-31 at 12.55.32.png

          🧑‍🎓 Autor des beliebten ioBroker-Master-Kurses
          🎥 Tutorials rund um das Thema DIY-Smart-Home: https://haus-automatisierung.com/
          📚 Meine inoffizielle ioBroker Dokumentation

          R 1 Antwort Letzte Antwort
          0
          • H Offline
            H Offline
            Hotze
            schrieb am zuletzt editiert von Hotze
            #49

            So!
            Nun hatte ich einige Zeit und habe mal ein echtes Durcheinander veranstaltet, so dass nur der Kern des Eigendlichen Scriptes übrig blieb!

            Ich habe es ordentlich erweitert:

            • Zeitfenster (Uhrzeiten):
              • Startzeitfenster zwischen zwei Uhrzeiten Vormittags und nachmittags, bzw. Fenster 1 und 2
              • Fester Stop für Vormittags und Nachmittags
            • "Jitter" der im gewählten Startzeitsfenster variiert
            • "Jitter" der das Intervall (15min) um +- 30 Sekunden variiert
            • Richtung in der Meldung und den Datenpunkten (im JSON unter subtitel)

            Zumindest lief dieses Script bei mir fehlerfrei durch:

            /* =========================
              Staumelder Skript mit Zeitfenstern und Jitter
              - Startet zufällig im Startfenster (z.B. 04:58..05:02)
              - Stoppt zu festen Zeiten (z.B. 07:30 / 17:00)
              - Intervall: 15 Minuten +/- 30 Sekunden (bei jedem Lauf neu)
              ========================= */
            
            /*
            
            Beschreibung
            
            Dieses Skript überwacht Verkehrswarnungen über die Autobahn‑API für die in der Variable `roadId` konfigurierte Autobahn.
            Es filtert Meldungen nach dem definierten Koordinatenbereich (coordsArea). 
            
            Wichtig: Vor dem ersten Start unbedingt die Variable `roadId` auf die gewünschte Autobahn setzen (z. B. "A45", "A3" etc.).
            
            
            Ausgaben (einzeln schaltbar):
            
            - telegramBasicEnabled    : Telegram‑Nachricht ohne Link
            - telegramWithLinkEnabled : Telegram‑Nachricht mit Google‑Maps‑Link
            - dpAlexaEnabled          : Klartext‑Datenpunkt (z. B. idAlexa) für Alexa, OHNE Maps‑Link
            - dpJsonEnabled           : JSON‑Datenpunkt (z. B. idJSON) für Auswertungen, MIT Maps‑Link 
            
            Verhalten:
            - Datenpunkte werden nur angelegt, wenn der jeweilige Schalter aktiviert ist.
            - Beim Start führt das Skript einmal checkTraffic() aus und wiederholt dann alle 15 Minuten (relativ zur Startzeit).
            - Maps‑Link wird nur erzeugt, wenn Koordinaten vorhanden sind.
            
            Hinweise:
            - Stelle diese Variablen korrekt ein:
              - roadId
              - coordsArea
              - telegramInstance (normalerweise ist es telegram.0)
              - telegramChatId
              - idAlexa 
              - idJSON
            
            - Passe die Schalter an
            */
            
            /* =========================
              Konfiguration
              ========================= */
            
            // Autobahn / Bereich
            const roadId = "A1";
            const coordsArea = {
               minLat: 49.0,   // untere Grenze Breite
               maxLat: 51.2742993,   // obere Grenze Breite
               minLon: 6,    // linke Grenze Länge
               maxLon: 8.3822071     // rechte Grenze Länge
            };
            
            // Ausgabeschalter (0 = aus, 1 = an)
            const telegramBasicEnabled    = 1; // Telegram: Nachricht ohne Link
            const telegramWithLinkEnabled = 1; // Telegram: Nachricht mit Maps-Link
            const dpAlexaEnabled          = 0; // Alexa Klartext-DP
            const dpJsonEnabled           = 1; // JSON-DP
            
            // Telegram-Konfiguration
            const telegramInstance = "telegram.0";
            const telegramChatId   = 123456789;
            
            // Datenpunkt-IDs (falls dpAlexaEnabled / dpJsonEnabled = 1)
            const idAlexa = "0_userdata.0.Verkehr_Alexa";
            const idJSON  = "0_userdata.0.Verkehr_JSON";
            
            /* =========================
              Zeitfenster Konfiguration
              =========================
              Format: "HH:MM" (24h)
            
              - morningStart..morningStartWindowEnd: Startfenster morgens (zufälliger Start)
              - morningStop: feste Stoppzeit morgens
              - afternoonStart..afternoonStartWindowEnd: Startfenster nachmittags (zufälliger Start)
              - afternoonStop: feste Stoppzeit nachmittags
            */
            const morningStart            = "04:58"; // frühester Startzeitpunkt morgens (Startfenster beginnt)
            const morningStartWindowEnd   = "05:02"; // spätester Startzeitpunkt morgens (Startfenster endet)
            const morningStop             = "07:30"; // feste Stoppzeit morgens
            
            const afternoonStart          = "12:58"; // frühester Startzeitpunkt nachmittags (Startfenster beginnt)
            const afternoonStartWindowEnd = "13:02"; // spätester Startzeitpunkt nachmittags (Startfenster endet)
            const afternoonStop           = "16:00"; // feste Stoppzeit nachmittags
            
            /* =========================
              Intervall und Jitter
              =========================
              baseIntervalMs   = 15 Minuten in Millisekunden
              perRunJitterMs   = +/- 30 Sekunden (wird bei jedem Intervall neu berechnet)
            */
            const baseIntervalMs = 15 * 60 * 1000; // 15 Minuten
            const perRunJitterMs = 30 * 1000;      // +/- 30 Sekunden
            
            /* =========================
              Initiale Datenpunkt-Anlage (falls aktiviert)
              ========================= */
            if (dpAlexaEnabled === 1) {
               createState(idAlexa, "", false, {
                   name: "Verkehrsmeldung Klartext",
                   type: "string",
                   role: "value"
               });
            }
            if (dpJsonEnabled === 1) {
               createState(idJSON, "[]", false, {
                   name: "Verkehrsmeldung JSON",
                   type: "string",
                   role: "json"
               });
            }
            
            /* =========================
              API-URL und optionaler axios-Fallback
              ========================= */
            const url = `https://verkehr.autobahn.de/o/autobahn/${roadId}/services/warning`;
            
            let axiosClient = null;
            try {
               axiosClient = require("axios");
            } catch (e) {
               console.warn("axios nicht verfügbar. Falls nötig: npm install axios oder require() im JS-Adapter aktivieren.");
               axiosClient = null;
            }
            
            /* =========================
              Hilfsfunktionen Zeit
              ========================= */
            function parseTimeToMinutes(hhmm) {
               const [h, m] = String(hhmm).split(":").map(Number);
               return (h || 0) * 60 + (m || 0);
            }
            
            function nowInMinutes() {
               const d = new Date();
               return d.getHours() * 60 + d.getMinutes();
            }
            
            // prüft, ob 'now' in [start, stop) liegt; unterstützt stop < start (Über Mitternacht)
            function isNowInWindow(startHHMM, stopHHMM) {
               const start = parseTimeToMinutes(startHHMM);
               const stop  = parseTimeToMinutes(stopHHMM);
               const now   = nowInMinutes();
               if (start <= stop) {
                   return now >= start && now < stop;
               } else {
                   // Fenster über Mitternacht, z.B. 23:00 - 02:00
                   return now >= start || now < stop;
               }
            }
            
            // ms bis zum nächsten Start eines der Fenster (ohne Random-Startoffset)
            function msUntilNextWindowStartSimple(windows) {
               const now = new Date();
               const nowMs = now.getTime();
               const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
               let best = Infinity;
            
               for (const [startHHMM] of windows) {
                   const [sh, sm] = startHHMM.split(":").map(Number);
                   let startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), sh, sm, 0, 0);
                   if (startDate.getTime() <= nowMs) {
                       startDate = new Date(startDate.getTime() + 24 * 3600 * 1000);
                   }
                   const diff = startDate.getTime() - nowMs;
                   if (diff < best) best = diff;
               }
               return best === Infinity ? 0 : best;
            }
            
            // ms bis zum nächsten Start eines der Fenster inklusive zufälligem Startoffset
            // startWindowEnds: Array mit passenden Endzeiten für die Startfenster (z.B. morningStartWindowEnd)
            function msUntilNextWindowStartWithRandomOffset(windows, startWindowEnds) {
               const now = new Date();
               const nowMs = now.getTime();
               const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
               let best = { diff: Infinity, idx: -1, startDate: null };
            
               for (let i = 0; i < windows.length; i++) {
                   const startHHMM = windows[i][0];
                   const [sh, sm] = startHHMM.split(":").map(Number);
                   let startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), sh, sm, 0, 0);
                   if (startDate.getTime() <= nowMs) {
                       // Wenn Start heute bereits vorbei, prüfe ob wir aktuell im Fenster sind
                       const startMin = parseTimeToMinutes(windows[i][0]);
                       const stopMin  = parseTimeToMinutes(windows[i][1]);
                       const nowMin   = nowInMinutes();
                       const inWindow = (startMin <= stopMin) ? (nowMin >= startMin && nowMin < stopMin) : (nowMin >= startMin || nowMin < stopMin);
                       if (inWindow) {
                           return { ms: 0, idx: i, offsetMs: 0 };
                       }
                       // sonst Start morgen
                       startDate = new Date(startDate.getTime() + 24 * 3600 * 1000);
                   }
                   const diff = startDate.getTime() - nowMs;
                   if (diff < best.diff) {
                       best = { diff, idx: i, startDate };
                   }
               }
            
               if (best.idx === -1) return { ms: 0, idx: -1, offsetMs: 0 };
            
               // berechne zufälligen Offset innerhalb des Startfensters für die gewählte Window-Start
               const startHHMM = windows[best.idx][0];
               const endHHMM   = startWindowEnds[best.idx];
               const startMin = parseTimeToMinutes(startHHMM);
               const endMin   = parseTimeToMinutes(endHHMM);
               // Falls end < start (über Mitternacht) behandeln wir das nicht für Startfenster; erwartet end >= start
               const rangeMs = Math.max(0, (endMin - startMin) * 60 * 1000);
               const offsetMs = rangeMs > 0 ? Math.floor(Math.random() * (rangeMs + 1)) : 0;
            
               return { ms: best.diff + offsetMs, idx: best.idx, offsetMs };
            }
            
            /* =========================
              HTTP Helper und checkTraffic
              ========================= */
            async function fetchJson(url) {
               if (axiosClient) {
                   const res = await axiosClient.get(url);
                   return res.data;
               }
               if (typeof fetch === "function") {
                   const res = await fetch(url);
                   return await res.json();
               }
               throw new Error("Kein HTTP-Client verfügbar. Bitte axios installieren oder require() im JS-Adapter aktivieren.");
            }
            
            function isInArea(lat, lon, area) {
               return lat >= area.minLat && lat <= area.maxLat && lon >= area.minLon && lon <= area.maxLon;
            }
            
            function warningHitsArea(w, area) {
               if (w.coordinate && typeof w.coordinate.lat === "number" && typeof w.coordinate.long === "number") {
                   if (isInArea(w.coordinate.lat, w.coordinate.long, area)) return true;
               }
               if (w.geometry && Array.isArray(w.geometry.coordinates)) {
                   for (const c of w.geometry.coordinates) {
                       if (Array.isArray(c) && c.length >= 2) {
                           const lon = c[0], lat = c[1];
                           if (isInArea(lat, lon, area)) return true;
                       }
                   }
               }
               return false;
            }
            
            function buildDescriptionText(desc) {
               if (Array.isArray(desc)) return desc.filter(d => d && String(d).trim() !== "").join("\n");
               return String(desc || "").trim();
            }
            
            async function checkTraffic() {
               try {
                   console.log("Hole Daten von:", url, "Zeit:", new Date().toLocaleString());
                   const data = await fetchJson(url);
                   const warnings = data.warnings || data.warning;
            
                   if (!warnings || !Array.isArray(warnings) || warnings.length === 0) {
                       console.log("Keine Warnungen gefunden.");
                       if (dpAlexaEnabled === 1) setState(idAlexa, "Keine Warnungen auf " + roadId);
                       if (dpJsonEnabled === 1) setState(idJSON, "[]");
                       return;
                   }
            
                   const relevant = warnings.filter(w => warningHitsArea(w, coordsArea));
                   if (!relevant || relevant.length === 0) {
                       console.log("Keine Warnungen im Bereich.");
                       if (dpAlexaEnabled === 1) setState(idAlexa, "Keine Warnungen im Bereich auf " + roadId);
                       if (dpJsonEnabled === 1) setState(idJSON, "[]");
                       return;
                   }
            
                   console.log(`${relevant.length} Warnung(en) im Bereich gefunden.`);
            
                   let alexaText = "";
                   const jsonOut = [];
            
                   for (const w of relevant) {
                       const desc = buildDescriptionText(w.description);
                       let lat = null, lon = null;
                       if (w.coordinate) { lat = w.coordinate.lat; lon = w.coordinate.long; }
                       if ((!lat || !lon) && w.point) {
                           const p = String(w.point).split(",");
                           if (p.length === 2) { lat = p[0]; lon = p[1]; }
                       }
            
                       const mapLink = (lat && lon) ? `https://www.google.com/maps/@${lat},${lon},13.13z` : "";
            
                       if (telegramBasicEnabled === 1) {
                           const msg = `⚠️ Störung auf ${roadId}:\n${w.title}\n${desc}`;
                           sendTo(telegramInstance, "send", { chatId: telegramChatId, text: msg });
                       }
            
                       if (telegramWithLinkEnabled === 1 && mapLink) {
                           const msg = `⚠️ Störung auf ${roadId}:\n${w.title}\n${desc}\n\n📍 ${mapLink}`;
                           sendTo(telegramInstance, "send", { chatId: telegramChatId, text: msg });
                       }
            
                       if (dpAlexaEnabled === 1) {
                           alexaText += `Störung auf ${roadId}: ${w.title}. ${desc}\n\n`;
                       }
            
                       if (dpJsonEnabled === 1) {
                           jsonOut.push({
                               road: roadId,
                               title: w.title,
                               description: desc,
               				subtitle: w.subtitle || null,
                               start: w.startTimestamp || null,
                               coordinate: lat && lon ? { lat: lat, lon: lon } : null,
                               mapLink: mapLink || null
                           });
                       }
                   }
            
                   if (dpAlexaEnabled === 1) setState(idAlexa, alexaText.trim());
                   if (dpJsonEnabled === 1) setState(idJSON, JSON.stringify(jsonOut, null, 2));
            
               } catch (err) {
                   console.error("Fehler beim Abruf:", err && err.message ? err.message : err);
                   if (telegramBasicEnabled === 1 || telegramWithLinkEnabled === 1) {
                       sendTo(telegramInstance, "send", {
                           chatId: telegramChatId,
                           text: `❌ Fehler beim Abruf der Verkehrsdaten: ${err && err.message ? err.message : err}`
                       });
                   }
                   if (dpAlexaEnabled === 1) setState(idAlexa, "Fehler beim Abruf der Verkehrsdaten");
                   if (dpJsonEnabled === 1) setState(idJSON, "[]");
               }
            }
            
            /* =========================
              Scheduler Loop
              ========================= */
            
            // Definiere die aktiven Fenster als Array [start, stop]
            const activeWindows = [
               [morningStart, morningStop],
               [afternoonStart, afternoonStop]
            ];
            // Startfenster-Endzeiten (parallel zu activeWindows, für zufälligen Startoffset)
            const startWindowEnds = [
               morningStartWindowEnd,
               afternoonStartWindowEnd
            ];
            
            async function schedulerLoop() {
               try {
                   const active = activeWindows.some(w => isNowInWindow(w[0], w[1]));
                   if (active) {
                       // innerhalb eines aktiven Fensters: check ausführen
                       await checkTraffic();
                   } else {
                       console.log("Nicht im aktiven Fenster — checkTraffic übersprungen:", new Date().toLocaleString());
                   }
               } catch (e) {
                   console.error("Fehler im SchedulerLoop:", e && e.message ? e.message : e);
               } finally {
                   // nächsten Delay berechnen: baseInterval +/- jitter
                   const jitter = Math.floor(Math.random() * (2 * perRunJitterMs + 1)) - perRunJitterMs; // -perRunJitterMs .. +perRunJitterMs
                   const nextDelay = Math.max(0, baseIntervalMs + jitter);
            
                   // Wenn wir aktuell außerhalb aller Fenster sind, prüfen wir, ob ein Sprung zum nächsten Fenster sinnvoll ist
                   const activeNow = activeWindows.some(w => isNowInWindow(w[0], w[1]));
                   if (!activeNow) {
                       const next = msUntilNextWindowStartWithRandomOffset(activeWindows, startWindowEnds);
                       const msToNextWindowWithOffset = next.ms;
                       if (msToNextWindowWithOffset > 0 && msToNextWindowWithOffset < nextDelay) {
                           console.log(`Außerhalb Fenster. Springe in ${Math.round(msToNextWindowWithOffset/1000)}s zum nächsten Fensterstart (inkl. zufälligem Startoffset ${Math.round(next.offsetMs/1000)}s).`);
                           setTimeout(schedulerLoop, msToNextWindowWithOffset);
                           return;
                       }
                   }
            
                   console.log(`Nächster Scheduler-Lauf in ${Math.round(nextDelay/1000)}s (Jitter ${jitter} ms).`);
                   setTimeout(schedulerLoop, nextDelay);
               }
            }
            
            /* =========================
              Start beim Laden
              ========================= */
            (async () => {
               // Beim Start: wenn aktuell aktiv, sofort check ausführen
               if (activeWindows.some(w => isNowInWindow(w[0], w[1]))) {
                   await checkTraffic();
               } else {
                   const next = msUntilNextWindowStartWithRandomOffset(activeWindows, startWindowEnds);
                   console.log("Beim Start nicht im aktiven Fenster. Nächster Fensterstart in", Math.round(next.ms/1000), "Sekunden (inkl. zufälligem Startoffset).");
               }
               // Loop starten
               schedulerLoop();
            })();
            
            

            Mit der Variation sollten die Abfragen auf die API gut verteilt sein!

            So und nun wird gefeiert! Guten rutsch wünsche ich Euch!

            1 Antwort Letzte Antwort
            1
            • haus-automatisierungH haus-automatisierung

              @Hotze sagte in #Stauerkennung #DieAutobahn:

              Was Blocklys an geht bin ich aber auch kein Held!

              Das kann man ja lernen. Soll ja ganz ausführlicher Lerninhalte geben ;)

              Das ist ein Array aus Objekten. Also erstmal über den Index zugreifen: 0.road bzw. 1.road. Alternativ mit einer Schleife über alle Objekte gehen:

              Screenshot 2025-12-31 at 12.55.32.png

              R Offline
              R Offline
              Rushmed
              Most Active
              schrieb am zuletzt editiert von
              #50

              Frohes Neues meine Herren!

              @haus-automatisierung Was muss ich denn in dem Blockly als Liste setzen?
              So funktionierts schonmal nicht:
              9eb28b56-0988-4956-901d-71b8528af469-grafik.png
              DAnke vorab.

              @hotze Ich beginne heute Abend den Test des neuen Scripts. Danke schonmal!

              haus-automatisierungH 1 Antwort Letzte Antwort
              0
              • R Rushmed

                Frohes Neues meine Herren!

                @haus-automatisierung Was muss ich denn in dem Blockly als Liste setzen?
                So funktionierts schonmal nicht:
                9eb28b56-0988-4956-901d-71b8528af469-grafik.png
                DAnke vorab.

                @hotze Ich beginne heute Abend den Test des neuen Scripts. Danke schonmal!

                haus-automatisierungH Online
                haus-automatisierungH Online
                haus-automatisierung
                Developer Most Active
                schrieb am zuletzt editiert von
                #51

                @Rushmed sagte in #Stauerkennung #DieAutobahn:

                @haus-automatisierung Was muss ich denn in dem Blockly als Liste setzen?

                Na das JSON, welches in ein Objekt gewandelt wurde (unter Konvertierung). Und dann hast Du innerhalb der Schleife jedes Listenelement (ist ja dann auch ein Objekt), von welchem man sich das Attribut holen kann.

                Screenshot 2026-01-01 at 18.36.43.png

                🧑‍🎓 Autor des beliebten ioBroker-Master-Kurses
                🎥 Tutorials rund um das Thema DIY-Smart-Home: https://haus-automatisierung.com/
                📚 Meine inoffizielle ioBroker Dokumentation

                1 Antwort Letzte Antwort
                1
                • R Offline
                  R Offline
                  Rushmed
                  Most Active
                  schrieb am zuletzt editiert von
                  #52

                  Perfekt, das klappt. Danke!

                  1 Antwort Letzte Antwort
                  0
                  • R Offline
                    R Offline
                    Rushmed
                    Most Active
                    schrieb am zuletzt editiert von
                    #53

                    @hotze Hab das Script gestartet.
                    Muss hier etwas angepasst werden:

                      Zeitfenster Konfiguration
                      =========================
                      Format: "HH:MM" (24h)
                     
                      - morningStart..morningStartWindowEnd: Startfenster morgens (zufälliger Start)
                      - morningStop: feste Stoppzeit morgens
                      - afternoonStart..afternoonStartWindowEnd: Startfenster nachmittags (zufälliger Start)
                      - afternoonStop: feste Stoppzeit nachmittags
                    

                    Ich hoffe die Stoppzeiten bedeuten nicht dass von da an keine Meldungen mehr kommen. Sonst müsste ich die anpassen.

                    Können die Infomeldungen im Debug bitte per Schalter im Script auf debug umgestellt werden? Langfristig interessieren mich nur Fehler und Warnungen.

                    Danke vorab.

                    H 1 Antwort Letzte Antwort
                    0
                    • R Rushmed

                      @hotze Hab das Script gestartet.
                      Muss hier etwas angepasst werden:

                        Zeitfenster Konfiguration
                        =========================
                        Format: "HH:MM" (24h)
                       
                        - morningStart..morningStartWindowEnd: Startfenster morgens (zufälliger Start)
                        - morningStop: feste Stoppzeit morgens
                        - afternoonStart..afternoonStartWindowEnd: Startfenster nachmittags (zufälliger Start)
                        - afternoonStop: feste Stoppzeit nachmittags
                      

                      Ich hoffe die Stoppzeiten bedeuten nicht dass von da an keine Meldungen mehr kommen. Sonst müsste ich die anpassen.

                      Können die Infomeldungen im Debug bitte per Schalter im Script auf debug umgestellt werden? Langfristig interessieren mich nur Fehler und Warnungen.

                      Danke vorab.

                      H Offline
                      H Offline
                      Hotze
                      schrieb am zuletzt editiert von
                      #54

                      @Rushmed

                      Der Teil zwischen /* und */ ist Auskommentiert. Was bedeutet, dass nicht ausgeführt wird! Es ist quasi nur die Erklärung:

                      /* =========================
                        Zeitfenster Konfiguration
                        =========================
                        Format: "HH:MM" (24h)
                       
                        - morningStart..morningStartWindowEnd: Startfenster morgens (zufälliger Start)
                        - morningStop: feste Stoppzeit morgens
                        - afternoonStart..afternoonStartWindowEnd: Startfenster nachmittags (zufälliger Start)
                        - afternoonStop: feste Stoppzeit nachmittags
                      */
                      

                      Direkt darunter solltest du etwas eintragen!

                      Zwei Startfenster in denen der 15 Minuten Zyklus random startet.
                      Sowie die jeweiligen Endzeiten.

                      Ich brauche nach 16:00 ihr keine Meldungen bis 5:00 Uhr. Weil ich dann Zuhause bin.
                      Zwischen 7:30 und 13:00 Uhr benötige ich keine Meldungen weil ich auf der Arbeit bin.

                      const morningStart            = "04:58"; // frühester Startzeitpunkt morgens (Startfenster beginnt)
                      const morningStartWindowEnd   = "05:02"; // spätester Startzeitpunkt morgens (Startfenster endet)
                      const morningStop             = "07:30"; // feste Stoppzeit morgens
                       
                      const afternoonStart          = "12:58"; // frühester Startzeitpunkt nachmittags (Startfenster beginnt)
                      const afternoonStartWindowEnd = "13:02"; // spätester Startzeitpunkt nachmittags (Startfenster endet)
                      const afternoonStop           = "16:00"; // feste Stoppzeit nachmittags
                       
                      
                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      657

                      Online

                      32.6k

                      Benutzer

                      82.1k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2025
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe