Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • 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. Visualisierung
  4. Bayrol Webportal

NEWS

  • wichtiges UPDATE für controller 7.2.2 im stable
    HomoranH
    Homoran
    9
    1
    695

  • Neues YouTube-Video: Visualisierung im Devices-Adapter
    BluefoxB
    Bluefox
    16
    1
    3.1k

  • Neuer ioBroker-Blog online: Monatsrückblick März/April 2026
    BluefoxB
    Bluefox
    8
    1
    3.0k

Bayrol Webportal

Geplant Angeheftet Gesperrt Verschoben Visualisierung
105 Beiträge 16 Kommentatoren 23.6k Aufrufe 15 Beobachtet
  • Ä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.
  • M mameier1234

    @hab83
    Bei mir war aktuell auch diese Meldung und seit gestern hat das Script gar keine Daten mehr abgerufen.

    Dann habe ich in einem Browser mal die URL aus dem Script https://www.bayrol-poolaccess.de/webview/index.php direkt aufgerufen.. Da war ein Hinweis für Portugal und Frankreich, dass es ein Update gibt. Einmal die Checkbox "nicht mehr Anzeigen" bestätigt.. seitdem kommen wieder daten.

    OliverIOO Offline
    OliverIOO Offline
    OliverIO
    schrieb am zuletzt editiert von
    #84

    @mameier1234

    Ja, das ist das problematische beim scrapen.
    Sobald sich der bildschirmaufbau nur minimal änder ist das Risiko da das es nicht mehr funktioniert

    Meine Adapter und Widgets
    TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
    Links im Profil

    1 Antwort Letzte Antwort
    0
    • S Offline
      S Offline
      SegaPro
      schrieb am zuletzt editiert von
      #85

      Hallo zusammen,

      danke für die tolle Arbeit. Ich habe das Script nun ein paar Tage eingesetzt und war sehr zufrieden.

      Ich hatte nur das Problem, dass manchmal einfach keine Daten mehr kamen und ich das Script ca. 1 x am Tag neu starten musste. Am Internet kann es nicht liegen, denn ich habe keine Zwangstrennungen.

      Ich hatte dann noch die Idee, dass es ja irgendwie sinnvoll wäre, wenn man die Abfrage ein bisschen an die Pumpenlaufzeit anpasst. Wenn diese nämlich nicht läuft, dann sind die Werte ja ohnehin verfälscht.

      Daher jetzt eine Anpassung des Scripts, welches das Abfrageintervall nach dem Status der Filterpumpe richtet - zudem hoffe ich, dass damit auch die "Hänger" besser werden.

      Und da ich ein ehrlicher Mensch bin: Ich kann nur sehr wenig JavaScript - das Script habe nicht ich gemacht, sondern es ist ein Produkt einer KI. Ich habe das originale Script verwendet und der KI halt noch mitgeteilt, was meine Probleme sind und wie ich es gerne hätte.

      Ohne die tolle Vorarbeit hier wäre das nicht möglich gewesen, weil ich der KI sonst niemals hätte sagen können, was ich eigentlich will. Dafür ein großes Dankeschön!!!

      In Zeile "91" müsst ihr noch den Datenpunkt zur Abfrage des Zustandes der Pumpe eintragen. Bei mir ist es ein openknx-Pfad. Zur besseren Auffindbarkeit, habe ich "openknx.blabla" geschrieben. Und natürlich oben eure Logindaten nicht vergessen.

      const fetch = require('node-fetch');
      
      let user = "USERNAME (Mailadresse)";
      let password = "PASSWORT";
      let dpPH = "0_userdata.0.bayrol.ph";
      let dpMV = "0_userdata.0.bayrol.mv";
      let dpCC = "0_userdata.0.bayrol.cc";
      let requesttimeRunning = 30 * 1000; // 30 Sekunden
      let requesttimeIdle = 15 * 60 * 1000; // 15 Minuten
      
      const useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
      
      let intervalID;
      
      async function main() {
          console.log('Starte das Bayrol-Datenabfrage-Skript...');
          let sessionid = await getSession();
          let cid = await login(user, password, sessionid);
      
          if (cid) {
              console.log('Prüfe den Status der Filterpumpe...');
              checkFilterPumpStatus(sessionid, cid);
          }
      }
      
      async function getSession() {
          try {
              const response = await fetch("https://www.bayrol-poolaccess.de/webview/index.php", {
                  headers: {
                      "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                      "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                      "cache-control": "no-cache",
                      "pragma": "no-cache",
                      "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                      "sec-ch-ua-mobile": "?0",
                      "sec-ch-ua-platform": "\"Windows\"",
                      "sec-fetch-dest": "document",
                      "sec-fetch-mode": "navigate",
                      "sec-fetch-site": "none",
                      "sec-fetch-user": "?1",
                      "upgrade-insecure-requests": "1",
                      "User-Agent": useragent
                  },
                  method: "GET"
              });
              let headers = await response.headers;
              console.log(`Session-ID erhalten: ${getSessionId(headers.get("set-cookie"))}`);
              return getSessionId(headers.get("set-cookie"));
          } catch (error) {
              console.error(`Fehler beim Abrufen der Session-ID: ${error.message}`);
          }
      }
      
      async function login(user, password, sessionid) {
          try {
              let body = `username=${encodeURIComponent(user)}&password=${encodeURIComponent(password)}&login=Anmelden`;
              const response = await fetch("https://www.bayrol-poolaccess.de/webview/p/login.php?r=reg", {
                  headers: {
                      "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                      "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                      "cache-control": "no-cache",
                      "content-type": "application/x-www-form-urlencoded",
                      "pragma": "no-cache",
                      "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                      "sec-ch-ua-mobile": "?0",
                      "sec-ch-ua-platform": "\"Windows\"",
                      "sec-fetch-dest": "document",
                      "sec-fetch-mode": "navigate",
                      "sec-fetch-site": "same-origin",
                      "sec-fetch-user": "?1",
                      "upgrade-insecure-requests": "1",
                      "cookie": `PHPSESSID=${sessionid}`,
                      "Referer": "https://www.bayrol-poolaccess.de/webview/p/login.php",
                      "Referrer-Policy": "strict-origin-when-cross-origin",
                      "User-Agent": useragent
                  },
                  body: body,
                  method: "POST"
              });
              let text = await response.text();
              console.log(`CID erhalten: ${getCID(text)}`);
              return getCID(text);
          } catch (error) {
              console.error(`Fehler beim Login: ${error.message}`);
          }
      }
      
      async function checkFilterPumpStatus(sessionid, cid) {
          try {
              // Hier prüfen wir den Status der Filterpumpe
              const filterPumpStatus = getState('openknx.blabla').val;
              console.log(`Status der Filterpumpe: ${filterPumpStatus}`);
      
              if (filterPumpStatus) {
                  console.log('Filterpumpe läuft. Abfrageintervall auf 30 Sekunden gesetzt.');
                  if (intervalID) clearInterval(intervalID);
                  intervalID = setInterval(() => getData(sessionid, cid), requesttimeRunning);
              } else {
                  console.log('Filterpumpe nicht aktiv. Abfrageintervall auf 15 Minuten gesetzt.');
                  if (intervalID) clearInterval(intervalID);
                  intervalID = setInterval(() => {
                      checkFilterPumpStatus(sessionid, cid); // Erneut den Status prüfen
                  }, requesttimeIdle);
              }
          } catch (error) {
              console.error(`Fehler beim Prüfen des Filterpumpenstatus: ${error.message}`);
          }
      }
      
      async function getData(sessionid, cid) {
          try {
              const response = await fetch(`https://www.bayrol-poolaccess.de/webview/getdata.php?cid=${cid}`, {
                  headers: {
                      "accept": "*/*",
                      "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                      "cache-control": "no-cache",
                      "pragma": "no-cache",
                      "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                      "sec-ch-ua-mobile": "?0",
                      "sec-ch-ua-platform": "\"Windows\"",
                      "sec-fetch-dest": "empty",
                      "sec-fetch-mode": "cors",
                      "sec-fetch-site": "same-origin",
                      "x-requested-with": "XMLHttpRequest",
                      "cookie": `PHPSESSID=${sessionid}`,
                      "Referer": "https://www.bayrol-poolaccess.de/webview/p/plants.php",
                      "Referrer-Policy": "strict-origin-when-cross-origin",
                      "User-Agent": useragent
                  },
                  method: "GET"
              });
              let text = await response.text();
              let data = extractValues(text);
              writeData(data);
              console.log(`Daten erfolgreich abgerufen: ${JSON.stringify(data)}`);
          } catch (error) {
              console.error(`Fehler beim Abrufen der Daten: ${error.message}`);
          }
      }
      
      function writeData(obj) {
          try {
              setState(dpCC, parseFloat(obj.CC));
              setState(dpMV, parseFloat(obj.MV));
              setState(dpPH, parseFloat(obj.PH));
          } catch (error) {
              console.error(`Fehler beim Schreiben der Daten: ${error.message}`);
          }
      }
      
      function extractValues(text) {
          const regexPH = /\[pH\]<\/span><h1>([\d\.]+)<\/h1>/gm;
          const regexMV = /\[mV\]<\/span><h1>([\d\.]+)<\/h1>/gm;
          const regexCC = /\[°C\]<\/span><h1>([\d\.]+)<\/h1>/gm;
          let data = {
              PH: (regexPH.exec(text) || [])[1] || 0,
              MV: (regexMV.exec(text) || [])[1] || 0,
              CC: (regexCC.exec(text) || [])[1] || 0,
          };
          return data;
      }
      
      function getSessionId(setcookie) {
          const match = setcookie.match(/PHPSESSID=([^;]+)/);
          return match ? match[1] : '';
      }
      
      function getCID(html) {
          const match = html.match(/var clients = \[(\d+)\];/);
          return match ? match[1] : null;
      }
      
      // Start des Scripts
      main();
      
      

      Ich hoffe, es hilft dem einen oder anderen. :)

      OliverIOO 1 Antwort Letzte Antwort
      0
      • S SegaPro

        Hallo zusammen,

        danke für die tolle Arbeit. Ich habe das Script nun ein paar Tage eingesetzt und war sehr zufrieden.

        Ich hatte nur das Problem, dass manchmal einfach keine Daten mehr kamen und ich das Script ca. 1 x am Tag neu starten musste. Am Internet kann es nicht liegen, denn ich habe keine Zwangstrennungen.

        Ich hatte dann noch die Idee, dass es ja irgendwie sinnvoll wäre, wenn man die Abfrage ein bisschen an die Pumpenlaufzeit anpasst. Wenn diese nämlich nicht läuft, dann sind die Werte ja ohnehin verfälscht.

        Daher jetzt eine Anpassung des Scripts, welches das Abfrageintervall nach dem Status der Filterpumpe richtet - zudem hoffe ich, dass damit auch die "Hänger" besser werden.

        Und da ich ein ehrlicher Mensch bin: Ich kann nur sehr wenig JavaScript - das Script habe nicht ich gemacht, sondern es ist ein Produkt einer KI. Ich habe das originale Script verwendet und der KI halt noch mitgeteilt, was meine Probleme sind und wie ich es gerne hätte.

        Ohne die tolle Vorarbeit hier wäre das nicht möglich gewesen, weil ich der KI sonst niemals hätte sagen können, was ich eigentlich will. Dafür ein großes Dankeschön!!!

        In Zeile "91" müsst ihr noch den Datenpunkt zur Abfrage des Zustandes der Pumpe eintragen. Bei mir ist es ein openknx-Pfad. Zur besseren Auffindbarkeit, habe ich "openknx.blabla" geschrieben. Und natürlich oben eure Logindaten nicht vergessen.

        const fetch = require('node-fetch');
        
        let user = "USERNAME (Mailadresse)";
        let password = "PASSWORT";
        let dpPH = "0_userdata.0.bayrol.ph";
        let dpMV = "0_userdata.0.bayrol.mv";
        let dpCC = "0_userdata.0.bayrol.cc";
        let requesttimeRunning = 30 * 1000; // 30 Sekunden
        let requesttimeIdle = 15 * 60 * 1000; // 15 Minuten
        
        const useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
        
        let intervalID;
        
        async function main() {
            console.log('Starte das Bayrol-Datenabfrage-Skript...');
            let sessionid = await getSession();
            let cid = await login(user, password, sessionid);
        
            if (cid) {
                console.log('Prüfe den Status der Filterpumpe...');
                checkFilterPumpStatus(sessionid, cid);
            }
        }
        
        async function getSession() {
            try {
                const response = await fetch("https://www.bayrol-poolaccess.de/webview/index.php", {
                    headers: {
                        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                        "cache-control": "no-cache",
                        "pragma": "no-cache",
                        "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                        "sec-ch-ua-mobile": "?0",
                        "sec-ch-ua-platform": "\"Windows\"",
                        "sec-fetch-dest": "document",
                        "sec-fetch-mode": "navigate",
                        "sec-fetch-site": "none",
                        "sec-fetch-user": "?1",
                        "upgrade-insecure-requests": "1",
                        "User-Agent": useragent
                    },
                    method: "GET"
                });
                let headers = await response.headers;
                console.log(`Session-ID erhalten: ${getSessionId(headers.get("set-cookie"))}`);
                return getSessionId(headers.get("set-cookie"));
            } catch (error) {
                console.error(`Fehler beim Abrufen der Session-ID: ${error.message}`);
            }
        }
        
        async function login(user, password, sessionid) {
            try {
                let body = `username=${encodeURIComponent(user)}&password=${encodeURIComponent(password)}&login=Anmelden`;
                const response = await fetch("https://www.bayrol-poolaccess.de/webview/p/login.php?r=reg", {
                    headers: {
                        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                        "cache-control": "no-cache",
                        "content-type": "application/x-www-form-urlencoded",
                        "pragma": "no-cache",
                        "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                        "sec-ch-ua-mobile": "?0",
                        "sec-ch-ua-platform": "\"Windows\"",
                        "sec-fetch-dest": "document",
                        "sec-fetch-mode": "navigate",
                        "sec-fetch-site": "same-origin",
                        "sec-fetch-user": "?1",
                        "upgrade-insecure-requests": "1",
                        "cookie": `PHPSESSID=${sessionid}`,
                        "Referer": "https://www.bayrol-poolaccess.de/webview/p/login.php",
                        "Referrer-Policy": "strict-origin-when-cross-origin",
                        "User-Agent": useragent
                    },
                    body: body,
                    method: "POST"
                });
                let text = await response.text();
                console.log(`CID erhalten: ${getCID(text)}`);
                return getCID(text);
            } catch (error) {
                console.error(`Fehler beim Login: ${error.message}`);
            }
        }
        
        async function checkFilterPumpStatus(sessionid, cid) {
            try {
                // Hier prüfen wir den Status der Filterpumpe
                const filterPumpStatus = getState('openknx.blabla').val;
                console.log(`Status der Filterpumpe: ${filterPumpStatus}`);
        
                if (filterPumpStatus) {
                    console.log('Filterpumpe läuft. Abfrageintervall auf 30 Sekunden gesetzt.');
                    if (intervalID) clearInterval(intervalID);
                    intervalID = setInterval(() => getData(sessionid, cid), requesttimeRunning);
                } else {
                    console.log('Filterpumpe nicht aktiv. Abfrageintervall auf 15 Minuten gesetzt.');
                    if (intervalID) clearInterval(intervalID);
                    intervalID = setInterval(() => {
                        checkFilterPumpStatus(sessionid, cid); // Erneut den Status prüfen
                    }, requesttimeIdle);
                }
            } catch (error) {
                console.error(`Fehler beim Prüfen des Filterpumpenstatus: ${error.message}`);
            }
        }
        
        async function getData(sessionid, cid) {
            try {
                const response = await fetch(`https://www.bayrol-poolaccess.de/webview/getdata.php?cid=${cid}`, {
                    headers: {
                        "accept": "*/*",
                        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                        "cache-control": "no-cache",
                        "pragma": "no-cache",
                        "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
                        "sec-ch-ua-mobile": "?0",
                        "sec-ch-ua-platform": "\"Windows\"",
                        "sec-fetch-dest": "empty",
                        "sec-fetch-mode": "cors",
                        "sec-fetch-site": "same-origin",
                        "x-requested-with": "XMLHttpRequest",
                        "cookie": `PHPSESSID=${sessionid}`,
                        "Referer": "https://www.bayrol-poolaccess.de/webview/p/plants.php",
                        "Referrer-Policy": "strict-origin-when-cross-origin",
                        "User-Agent": useragent
                    },
                    method: "GET"
                });
                let text = await response.text();
                let data = extractValues(text);
                writeData(data);
                console.log(`Daten erfolgreich abgerufen: ${JSON.stringify(data)}`);
            } catch (error) {
                console.error(`Fehler beim Abrufen der Daten: ${error.message}`);
            }
        }
        
        function writeData(obj) {
            try {
                setState(dpCC, parseFloat(obj.CC));
                setState(dpMV, parseFloat(obj.MV));
                setState(dpPH, parseFloat(obj.PH));
            } catch (error) {
                console.error(`Fehler beim Schreiben der Daten: ${error.message}`);
            }
        }
        
        function extractValues(text) {
            const regexPH = /\[pH\]<\/span><h1>([\d\.]+)<\/h1>/gm;
            const regexMV = /\[mV\]<\/span><h1>([\d\.]+)<\/h1>/gm;
            const regexCC = /\[°C\]<\/span><h1>([\d\.]+)<\/h1>/gm;
            let data = {
                PH: (regexPH.exec(text) || [])[1] || 0,
                MV: (regexMV.exec(text) || [])[1] || 0,
                CC: (regexCC.exec(text) || [])[1] || 0,
            };
            return data;
        }
        
        function getSessionId(setcookie) {
            const match = setcookie.match(/PHPSESSID=([^;]+)/);
            return match ? match[1] : '';
        }
        
        function getCID(html) {
            const match = html.match(/var clients = \[(\d+)\];/);
            return match ? match[1] : null;
        }
        
        // Start des Scripts
        main();
        
        

        Ich hoffe, es hilft dem einen oder anderen. :)

        OliverIOO Offline
        OliverIOO Offline
        OliverIO
        schrieb am zuletzt editiert von
        #86

        @segapro

        in zeile 174 siehst du main()
        das ruft die eigentliche funktion auf.
        wenn du sonst nix machst, führt das skript alles genau einmal aus
        und ist dann beendet.

        um es nur zu bestimmten zeiten oder rythmus auszuführen
        musst du das main innerhalb einer schedule funktion aufrufen
        https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#schedule
        mit schedule kannst du dann als pattern die zeitpunkte definieren.
        wenn dann noch ein pumpenstatus dazukommt, dann da mit if auch noch den datenpunk abfragen und mit dem gewünschten status abgleichen.

        im link siehst du ein einfaches beispiel.
        wenn du nicht weiterkommst, dann kannst du hier nochmal fragen

        Meine Adapter und Widgets
        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
        Links im Profil

        S 1 Antwort Letzte Antwort
        0
        • OliverIOO OliverIO

          @segapro

          in zeile 174 siehst du main()
          das ruft die eigentliche funktion auf.
          wenn du sonst nix machst, führt das skript alles genau einmal aus
          und ist dann beendet.

          um es nur zu bestimmten zeiten oder rythmus auszuführen
          musst du das main innerhalb einer schedule funktion aufrufen
          https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#schedule
          mit schedule kannst du dann als pattern die zeitpunkte definieren.
          wenn dann noch ein pumpenstatus dazukommt, dann da mit if auch noch den datenpunk abfragen und mit dem gewünschten status abgleichen.

          im link siehst du ein einfaches beispiel.
          wenn du nicht weiterkommst, dann kannst du hier nochmal fragen

          S Offline
          S Offline
          SegaPro
          schrieb am zuletzt editiert von
          #87

          @oliverio
          Das wundert mich jetzt ein bisschen, denn ich habe es nun seit einigen Stunden erfolgreich laufen.

          Also ich zweifele keinesfalls deine Einwände an - du bist mir um Welten überlegen - und Dein Einwand ist sogar duch mich nachvollziehbar.

          Allerdings läuft das Script:

          javascript.0	18:11:14.976	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"732","CC":"50.0"}
          javascript.0	18:11:44.974	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"732","CC":"50.0"}
          javascript.0	18:12:14.975	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
          javascript.0	18:12:44.976	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
          javascript.0	18:13:15.091	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
          

          Pünktlich alle 30 Sekunden wird abgerufen.

          Einen Temperaturfühler habe ich nicht - daher stehen da 50°C

          Viele Grüße

          OliverIOO 1 Antwort Letzte Antwort
          0
          • S SegaPro

            @oliverio
            Das wundert mich jetzt ein bisschen, denn ich habe es nun seit einigen Stunden erfolgreich laufen.

            Also ich zweifele keinesfalls deine Einwände an - du bist mir um Welten überlegen - und Dein Einwand ist sogar duch mich nachvollziehbar.

            Allerdings läuft das Script:

            javascript.0	18:11:14.976	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"732","CC":"50.0"}
            javascript.0	18:11:44.974	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"732","CC":"50.0"}
            javascript.0	18:12:14.975	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
            javascript.0	18:12:44.976	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
            javascript.0	18:13:15.091	info	script.js.Pool.Bayrol: Daten erfolgreich abgerufen: {"PH":"7.4","MV":"730","CC":"50.0"}
            

            Pünktlich alle 30 Sekunden wird abgerufen.

            Einen Temperaturfühler habe ich nicht - daher stehen da 50°C

            Viele Grüße

            OliverIOO Offline
            OliverIOO Offline
            OliverIO
            schrieb am zuletzt editiert von
            #88

            @segapro
            ja,
            da in der Mitte ist ja ein Intervall
            Die Zeiten sind eigentlich okay. Wenn das Gerät nicht immer antwortet, könntest du die Zeiten mal etwas vergrößern.
            ansonsten sieht doch alles gut aus?

            Meine Adapter und Widgets
            TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
            Links im Profil

            H 1 Antwort Letzte Antwort
            0
            • OliverIOO OliverIO

              @segapro
              ja,
              da in der Mitte ist ja ein Intervall
              Die Zeiten sind eigentlich okay. Wenn das Gerät nicht immer antwortet, könntest du die Zeiten mal etwas vergrößern.
              ansonsten sieht doch alles gut aus?

              H Offline
              H Offline
              Habedere
              schrieb am zuletzt editiert von
              #89

              Hallo,
              hat jemand schon mal die Abfrage lokal über die iP versucht?
              Versuche auch meine Bayrol Relax Power (ohne Umwege) in iObroker zu bekommen.

              Mfg

              Q 1 Antwort Letzte Antwort
              0
              • H Habedere

                Hallo,
                hat jemand schon mal die Abfrage lokal über die iP versucht?
                Versuche auch meine Bayrol Relax Power (ohne Umwege) in iObroker zu bekommen.

                Mfg

                Q Offline
                Q Offline
                qwertz
                schrieb am zuletzt editiert von
                #90

                @habedere Ich habe die Bayrol automatic ph/cl. Ich wüsste nicht, dass die eine lokale API hat. Deine Bayrol Relax Power ist jedoch ein gänzlich anderes Gerät.

                H 1 Antwort Letzte Antwort
                0
                • Q qwertz

                  @habedere Ich habe die Bayrol automatic ph/cl. Ich wüsste nicht, dass die eine lokale API hat. Deine Bayrol Relax Power ist jedoch ein gänzlich anderes Gerät.

                  H Offline
                  H Offline
                  Habedere
                  schrieb am zuletzt editiert von
                  #91

                  @qwertz
                  Wusste ich auch nicht - klappt aber…

                  844d6355-bd36-4f96-8bc2-0f97194a5608-image.png

                  Q 1 Antwort Letzte Antwort
                  0
                  • H Habedere

                    @qwertz
                    Wusste ich auch nicht - klappt aber…

                    844d6355-bd36-4f96-8bc2-0f97194a5608-image.png

                    Q Offline
                    Q Offline
                    qwertz
                    schrieb am zuletzt editiert von
                    #92

                    @habedere wie ist denn die url dieser seite ?

                    OliverIOO Q H 3 Antworten Letzte Antwort
                    0
                    • Q qwertz

                      @habedere wie ist denn die url dieser seite ?

                      OliverIOO Offline
                      OliverIOO Offline
                      OliverIO
                      schrieb am zuletzt editiert von
                      #93

                      @qwertz

                      https://www.bayrol-poolaccess.de

                      Meine Adapter und Widgets
                      TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                      Links im Profil

                      1 Antwort Letzte Antwort
                      0
                      • Q qwertz

                        @habedere wie ist denn die url dieser seite ?

                        Q Offline
                        Q Offline
                        qwertz
                        schrieb am zuletzt editiert von
                        #94

                        @qwertz Ich bezog mich auf die lokale API, die Habedere als Screenshot gezeigt hat.

                        1 Antwort Letzte Antwort
                        0
                        • Q qwertz

                          @habedere wie ist denn die url dieser seite ?

                          H Offline
                          H Offline
                          Habedere
                          schrieb am zuletzt editiert von
                          #95

                          @qwertz
                          Einfach nur die IP im Heimnetz eingeben

                          H 1 Antwort Letzte Antwort
                          0
                          • H Habedere

                            @qwertz
                            Einfach nur die IP im Heimnetz eingeben

                            H Offline
                            H Offline
                            Habedere
                            schrieb am zuletzt editiert von
                            #96

                            @habedere
                            Zur Info - hab die Werte jetzt mit dem Parser ausgelesen.

                            d12bb99f-3dc8-4ba4-ae37-4abc7d16fe50-image.png

                            J 1 Antwort Letzte Antwort
                            0
                            • H Habedere

                              @habedere
                              Zur Info - hab die Werte jetzt mit dem Parser ausgelesen.

                              d12bb99f-3dc8-4ba4-ae37-4abc7d16fe50-image.png

                              J Offline
                              J Offline
                              james4711
                              schrieb am zuletzt editiert von
                              #97

                              @habedere
                              Hast du das als Alternative für das WebPortal-Skript verwendet?
                              Für meine Automatic Salt 7 bekomme ich immer Zugriffsfehler:
                              2025-04-23 17:18:17.820 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:17.821 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:20.855 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:20.856 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:23.930 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:23.931 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:26.797 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                              2025-04-23 17:18:26.798 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80

                              OliverIOO 1 Antwort Letzte Antwort
                              0
                              • J james4711

                                @habedere
                                Hast du das als Alternative für das WebPortal-Skript verwendet?
                                Für meine Automatic Salt 7 bekomme ich immer Zugriffsfehler:
                                2025-04-23 17:18:17.820 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:17.821 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:20.855 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:20.856 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:23.930 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:23.931 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:26.797 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
                                2025-04-23 17:18:26.798 - info: parser.0 (11135) Cannot read link "http://xxx.xxx.xxx.xxx/": Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80

                                OliverIOO Offline
                                OliverIOO Offline
                                OliverIO
                                schrieb am zuletzt editiert von OliverIO
                                #98

                                @james4711

                                lässt sich die seite im browser aufrufen?
                                muss man sich dort zuvor einloggen(am besten mal im inkognito modus prüfen)?

                                der parser adapter hat nur beschränkte möglichkeiten sich wo einzuloggen

                                die fehlermeldung bedeutet das er die verbindung abgelehnt hat. die adresse ist zwar generell erreichbar, aber entweder stimmt was mit dem port oder der anfrage art nicht

                                Meine Adapter und Widgets
                                TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                Links im Profil

                                M 1 Antwort Letzte Antwort
                                0
                                • OliverIOO OliverIO

                                  @james4711

                                  lässt sich die seite im browser aufrufen?
                                  muss man sich dort zuvor einloggen(am besten mal im inkognito modus prüfen)?

                                  der parser adapter hat nur beschränkte möglichkeiten sich wo einzuloggen

                                  die fehlermeldung bedeutet das er die verbindung abgelehnt hat. die adresse ist zwar generell erreichbar, aber entweder stimmt was mit dem port oder der anfrage art nicht

                                  M Offline
                                  M Offline
                                  mameier1234
                                  schrieb am zuletzt editiert von
                                  #99

                                  Falls sich jemand wundert... aktuell kommen keine Daten. Ist bei Bayrol bekannt und sie arbeiten an einer Lösung.

                                  Grüße,

                                  Martin

                                  M 1 Antwort Letzte Antwort
                                  1
                                  • M mameier1234

                                    Falls sich jemand wundert... aktuell kommen keine Daten. Ist bei Bayrol bekannt und sie arbeiten an einer Lösung.

                                    M Offline
                                    M Offline
                                    mameier1234
                                    schrieb am zuletzt editiert von
                                    #100

                                    Wenn man sich auf der Bayrol-poolaccess Seite anmeldet, dann kommt ein Hinweise, dass es aktuell zu Kommunikationsproblemen kommt.

                                    Wenn man dies mit "nicht mehr anzeigen" quitiert, dann geht auch das Script wieder :-)

                                    Grüße,

                                    Martin

                                    1 Antwort Letzte Antwort
                                    1
                                    • R Offline
                                      R Offline
                                      radi71
                                      schrieb am zuletzt editiert von
                                      #101

                                      Also ich habe mal ein lauffähiges javascript für den iobroker erstellt.

                                      Was ich ausgeklammert habe ist die Temp, da ich keinen Sensor dran habe, aber PH + Redox wird zuverlässig ausgelesen.

                                      User + PW eintragen und die cid rausfinden (im Browser einmal anmelden dann F12 und dann steht da in der Konsole die cid

                                      d59be455-6a5e-4638-b2b4-5b118ddfbe45-image.jpeg

                                      ich lese nur zwischen 9 und 21 Uhr aus, alle 10 Min, da sonst meine Umwälzpumpe eh nicht läuft.
                                      Um keine falschen Werte anzuzeigen setze ich sie auf null wenn die Pumpe nicht läuft, aber das ist noch nicht 100%.

                                      Also hier das Script:

                                      const https = require('https');
                                      const { URL } = require('url');
                                      
                                      // ioBroker JavaScript-Adapter-Instanz
                                      const JS_INSTANCE = 'javascript.0';
                                      
                                      // Zugangsdaten
                                      const USER = 'xxx';
                                      const PASS = 'xxx';
                                      
                                      // Bayrol Controller-ID
                                      const CID = 'xxxxx';
                                      
                                      const BASE = 'https://www.bayrol-poolaccess.de/webview';
                                      
                                      const LOGIN_URL = `${BASE}/m/login.php`;
                                      const PLANTS_M_URL = `${BASE}/m/plants.php`;
                                      const DATA_URL = `${BASE}/getdata.php?cid=${CID}`;
                                      
                                      // ioBroker States
                                      const STATE_PH = `${JS_INSTANCE}.bayrol.ph`;
                                      const STATE_REDOX = `${JS_INSTANCE}.bayrol.redox`;
                                      const STATE_LAST_UPDATE = `${JS_INSTANCE}.bayrol.lastUpdate`;
                                      const STATE_CONNECTED = `${JS_INSTANCE}.bayrol.connected`;
                                      const STATE_PUMP_RUNNING = `${JS_INSTANCE}.bayrol.pumpRunning`;
                                      const STATE_VALUES_VALID = `${JS_INSTANCE}.bayrol.valuesValid`;
                                      
                                      let cookies = {};
                                      let loggedIn = false;
                                      let pollRunning = false;
                                      
                                      function ensureObjects() {
                                          setObject(STATE_PH, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol pH',
                                                  type: 'number',
                                                  role: 'value.ph',
                                                  unit: 'pH',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      
                                          setObject(STATE_REDOX, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol Redox',
                                                  type: 'number',
                                                  role: 'value',
                                                  unit: 'mV',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      
                                          setObject(STATE_LAST_UPDATE, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol letzte Aktualisierung',
                                                  type: 'string',
                                                  role: 'date',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      
                                          setObject(STATE_CONNECTED, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol verbunden',
                                                  type: 'boolean',
                                                  role: 'indicator.connected',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      
                                          setObject(STATE_PUMP_RUNNING, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol Umwälzpumpe läuft',
                                                  type: 'boolean',
                                                  role: 'indicator',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      
                                          setObject(STATE_VALUES_VALID, {
                                              type: 'state',
                                              common: {
                                                  name: 'Bayrol Messwerte gültig',
                                                  type: 'boolean',
                                                  role: 'indicator',
                                                  read: true,
                                                  write: false
                                              },
                                              native: {}
                                          });
                                      }
                                      
                                      function saveCookies(setCookieHeaders) {
                                          if (!setCookieHeaders) return;
                                      
                                          if (!Array.isArray(setCookieHeaders)) {
                                              setCookieHeaders = [setCookieHeaders];
                                          }
                                      
                                          setCookieHeaders.forEach(cookie => {
                                              const firstPart = cookie.split(';')[0];
                                              const eq = firstPart.indexOf('=');
                                      
                                              if (eq > 0) {
                                                  const name = firstPart.substring(0, eq).trim();
                                                  const value = firstPart.substring(eq + 1).trim();
                                                  cookies[name] = value;
                                              }
                                          });
                                      }
                                      
                                      function getCookieHeader() {
                                          return Object.entries(cookies)
                                              .map(([name, value]) => `${name}=${value}`)
                                              .join('; ');
                                      }
                                      
                                      function getAttr(tag, attrName) {
                                          const regex = new RegExp(attrName + '\\s*=\\s*["\\\']([^"\\\']*)["\\\']', 'i');
                                          const match = tag.match(regex);
                                          return match ? match[1] : '';
                                      }
                                      
                                      function request(method, url, body, extraHeaders = {}) {
                                          return new Promise((resolve, reject) => {
                                              const u = new URL(url);
                                      
                                              const headers = {
                                                  'User-Agent': 'Mozilla/5.0',
                                                  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                                                  'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8',
                                                  ...extraHeaders
                                              };
                                      
                                              const cookieHeader = getCookieHeader();
                                      
                                              if (cookieHeader) {
                                                  headers['Cookie'] = cookieHeader;
                                              }
                                      
                                              let payload = null;
                                      
                                              if (body !== undefined && body !== null) {
                                                  payload = String(body);
                                                  headers['Content-Length'] = Buffer.byteLength(payload);
                                              }
                                      
                                              const options = {
                                                  protocol: u.protocol,
                                                  hostname: u.hostname,
                                                  port: u.port || 443,
                                                  path: u.pathname + u.search,
                                                  method,
                                                  headers
                                              };
                                      
                                              const req = https.request(options, res => {
                                                  const chunks = [];
                                      
                                                  saveCookies(res.headers['set-cookie']);
                                      
                                                  res.on('data', chunk => chunks.push(chunk));
                                      
                                                  res.on('end', () => {
                                                      resolve({
                                                          statusCode: res.statusCode,
                                                          headers: res.headers,
                                                          body: Buffer.concat(chunks).toString('utf8')
                                                      });
                                                  });
                                              });
                                      
                                              req.on('error', reject);
                                      
                                              req.setTimeout(15000, () => {
                                                  req.destroy(new Error('Timeout'));
                                              });
                                      
                                              if (payload) {
                                                  req.write(payload);
                                              }
                                      
                                              req.end();
                                          });
                                      }
                                      
                                      async function requestFollow(method, url, body, headers = {}) {
                                          let currentMethod = method;
                                          let currentUrl = url;
                                          let currentBody = body;
                                          let currentHeaders = headers;
                                      
                                          for (let i = 0; i < 5; i++) {
                                              const res = await request(currentMethod, currentUrl, currentBody, currentHeaders);
                                      
                                              if (![301, 302, 303, 307, 308].includes(res.statusCode) || !res.headers.location) {
                                                  return res;
                                              }
                                      
                                              const oldUrl = currentUrl;
                                              const nextUrl = new URL(res.headers.location, currentUrl).toString();
                                      
                                              if (res.statusCode === 307 || res.statusCode === 308) {
                                                  currentUrl = nextUrl;
                                              } else {
                                                  currentMethod = 'GET';
                                                  currentUrl = nextUrl;
                                                  currentBody = null;
                                                  currentHeaders = {
                                                      'Referer': oldUrl
                                                  };
                                              }
                                          }
                                      
                                          throw new Error('Zu viele Redirects');
                                      }
                                      
                                      function parseLoginForm(html) {
                                          const form = {};
                                          const inputTags = html.match(/<input\b[^>]*>/gi) || [];
                                      
                                          let usernameSet = false;
                                          let passwordSet = false;
                                      
                                          inputTags.forEach(tag => {
                                              const name = getAttr(tag, 'name');
                                              const type = (getAttr(tag, 'type') || 'text').toLowerCase();
                                              const value = getAttr(tag, 'value');
                                      
                                              if (!name) return;
                                      
                                              form[name] = value || '';
                                      
                                              if (!usernameSet && (
                                                  type === 'email' ||
                                                  type === 'text' ||
                                                  /user|mail|email|login|benutzer/i.test(name)
                                              )) {
                                                  form[name] = USER;
                                                  usernameSet = true;
                                              }
                                      
                                              if (!passwordSet && (
                                                  type === 'password' ||
                                                  /pass|pwd|kennwort/i.test(name)
                                              )) {
                                                  form[name] = PASS;
                                                  passwordSet = true;
                                              }
                                          });
                                      
                                          if (!usernameSet) {
                                              form.username = USER;
                                          }
                                      
                                          if (!passwordSet) {
                                              form.password = PASS;
                                          }
                                      
                                          if (form.autologin !== undefined) {
                                              form.autologin = 'on';
                                          }
                                      
                                          const formMatch = html.match(/<form\b[^>]*action\s*=\s*["']([^"']+)["']/i);
                                      
                                          const action = formMatch
                                              ? new URL(formMatch[1], LOGIN_URL).toString()
                                              : `${BASE}/m/login.php?r=reg`;
                                      
                                          return {
                                              action,
                                              form
                                          };
                                      }
                                      
                                      function formEncode(obj) {
                                          return Object.entries(obj)
                                              .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
                                              .join('&');
                                      }
                                      
                                      function cleanHtmlText(value) {
                                          return String(value || '')
                                              .replace(/<script[\s\S]*?<\/script>/gi, '')
                                              .replace(/<style[\s\S]*?<\/style>/gi, '')
                                              .replace(/<[^>]*>/g, '')
                                              .replace(/&nbsp;/g, ' ')
                                              .replace(/&#160;/g, ' ')
                                              .replace(/&deg;/g, '°')
                                              .replace(/&auml;/g, 'ä')
                                              .replace(/&ouml;/g, 'ö')
                                              .replace(/&uuml;/g, 'ü')
                                              .replace(/&Auml;/g, 'Ä')
                                              .replace(/&Ouml;/g, 'Ö')
                                              .replace(/&Uuml;/g, 'Ü')
                                              .replace(/&szlig;/g, 'ß')
                                              .replace(/&amp;/g, '&')
                                              .replace(/\s+/g, ' ')
                                              .trim();
                                      }
                                      
                                      function parseNumber(value) {
                                          const text = cleanHtmlText(value)
                                              .replace(',', '.')
                                              .replace(/[^\d.+-]/g, '');
                                      
                                          const number = parseFloat(text);
                                      
                                          return Number.isFinite(number) ? number : null;
                                      }
                                      
                                      function labelToKey(label) {
                                          const l = cleanHtmlText(label)
                                              .replace(/\[[^\]]*\]/g, '')
                                              .replace(/\./g, '')
                                              .trim()
                                              .toLowerCase();
                                      
                                          if (l === 'ph' || l.includes('ph')) {
                                              return 'ph';
                                          }
                                      
                                          if (l.includes('redox') || l.includes('orp') || l.includes('mv')) {
                                              return 'redox';
                                          }
                                      
                                          return null;
                                      }
                                      
                                      function hasCssClass(html, className) {
                                          const regex = new RegExp('class\\s*=\\s*["\\\'][^"\\\']*\\b' + className + '\\b[^"\\\']*["\\\']', 'i');
                                          return regex.test(String(html || ''));
                                      }
                                      
                                      function parsePumpRunning(html) {
                                          const source = String(html || '');
                                      
                                          if (hasCssClass(source, 'gstat_ok')) {
                                              return true;
                                          }
                                      
                                          if (
                                              hasCssClass(source, 'gstat_nok') ||
                                              hasCssClass(source, 'gstat_error') ||
                                              hasCssClass(source, 'gstat_err') ||
                                              hasCssClass(source, 'gstat_alarm') ||
                                              hasCssClass(source, 'gstat_off')
                                          ) {
                                              return false;
                                          }
                                      
                                          const match = source.match(/class\s*=\s*["'][^"']*\bgstat_[^"']*["']/i);
                                      
                                          if (match) {
                                              log('Bayrol: Unbekannte Statusklasse gefunden: ' + match[0], 'warn');
                                          } else {
                                              log('Bayrol: Keine gstat-Statusklasse gefunden', 'warn');
                                          }
                                      
                                          return false;
                                      }
                                      
                                      function parseValues(html) {
                                          const source = String(html || '');
                                          const values = {};
                                      
                                          const boxRegex = /<div\b[^>]*class\s*=\s*["'][^"']*tab_box[^"']*["'][^>]*>([\s\S]*?)(?=<div\b[^>]*class\s*=\s*["'][^"']*tab_box|<div\b[^>]*class\s*=\s*["'][^"']*gapp_ase|<\/body>|$)/gi;
                                      
                                          let boxMatch;
                                      
                                          while ((boxMatch = boxRegex.exec(source)) !== null) {
                                              const boxHtml = boxMatch[1];
                                      
                                              const spanMatch = boxHtml.match(/<span\b[^>]*>([\s\S]*?)<\/span>/i);
                                              const h1Match = boxHtml.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i);
                                      
                                              if (!spanMatch || !h1Match) {
                                                  continue;
                                              }
                                      
                                              const label = cleanHtmlText(spanMatch[1]);
                                              const number = parseNumber(h1Match[1]);
                                              const key = labelToKey(label);
                                      
                                              if (key && number !== null) {
                                                  values[key] = Number(number);
                                              }
                                          }
                                      
                                          const spanH1Regex = /<span\b[^>]*>([\s\S]*?)<\/span>[\s\S]{0,400}?<h1\b[^>]*>([\s\S]*?)<\/h1>/gi;
                                      
                                          let spanH1Match;
                                      
                                          while ((spanH1Match = spanH1Regex.exec(source)) !== null) {
                                              const label = cleanHtmlText(spanH1Match[1]);
                                              const number = parseNumber(spanH1Match[2]);
                                              const key = labelToKey(label);
                                      
                                              if (key && number !== null) {
                                                  values[key] = Number(number);
                                              }
                                          }
                                      
                                          if (values.ph === undefined) {
                                              const phFallback = source.match(/pH\s*(?:\[[^\]]*\])?[\s\S]{0,500}?<h1[^>]*>\s*([0-9]+(?:[.,][0-9]+)?)\s*<\/h1>/i);
                                      
                                              if (phFallback) {
                                                  values.ph = Number(parseFloat(phFallback[1].replace(',', '.')));
                                              }
                                          }
                                      
                                          if (values.redox === undefined) {
                                              const redoxFallback = source.match(/Redox\s*(?:\[[^\]]*\])?[\s\S]{0,500}?<h1[^>]*>\s*([0-9]+(?:[.,][0-9]+)?)\s*<\/h1>/i);
                                      
                                              if (redoxFallback) {
                                                  values.redox = Number(parseFloat(redoxFallback[1].replace(',', '.')));
                                              }
                                          }
                                      
                                          if (values.redox !== undefined && values.redox < 100) {
                                              log('Bayrol: Redox-Wert unplausibel verworfen: ' + values.redox, 'warn');
                                              delete values.redox;
                                          }
                                      
                                          return values;
                                      }
                                      
                                      async function login() {
                                          cookies = {};
                                      
                                          log('Bayrol: Loginseite abrufen ...');
                                      
                                          const loginPage = await requestFollow('GET', LOGIN_URL, null);
                                          const parsed = parseLoginForm(loginPage.body);
                                      
                                          log(`Bayrol: Login-Action: ${parsed.action}`);
                                      
                                          const loginBody = formEncode(parsed.form);
                                      
                                          const loginRes = await requestFollow('POST', parsed.action, loginBody, {
                                              'Content-Type': 'application/x-www-form-urlencoded',
                                              'Referer': LOGIN_URL
                                          });
                                      
                                          const body = String(loginRes.body);
                                      
                                          if (
                                              body.includes('Fehler') ||
                                              body.includes('Zeit abgelaufen') ||
                                              body.includes('Captcha')
                                          ) {
                                              throw new Error('Bayrol Login fehlgeschlagen');
                                          }
                                      
                                          loggedIn = true;
                                          log('Bayrol: Login erfolgreich');
                                      }
                                      
                                      async function pollBayrol() {
                                          if (pollRunning) {
                                              log('Bayrol: Abruf läuft noch, überspringe diesen Durchlauf', 'warn');
                                              return;
                                          }
                                      
                                          pollRunning = true;
                                      
                                          try {
                                              if (!loggedIn) {
                                                  await login();
                                              }
                                      
                                              const res = await requestFollow('GET', DATA_URL, null, {
                                                  'Referer': PLANTS_M_URL
                                              });
                                      
                                              const html = String(res.body);
                                      
                                              if (html.includes('Anmeldung') && html.includes('Passwort')) {
                                                  loggedIn = false;
                                                  throw new Error('Session abgelaufen, Login wird beim nächsten Lauf erneuert');
                                              }
                                      
                                              const pumpRunning = parsePumpRunning(html);
                                              const values = parseValues(html);
                                      
                                              setState(STATE_CONNECTED, true, true);
                                              setState(STATE_PUMP_RUNNING, pumpRunning, true);
                                              setState(STATE_LAST_UPDATE, new Date().toISOString(), true);
                                      
                                              log(`Bayrol: Antwort Status ${res.statusCode}, Länge ${html.length}, Pumpe ${pumpRunning}, Werte ${JSON.stringify(values)}`);
                                      
                                              if (!pumpRunning) {
                                                  setState(STATE_PH, null, true);
                                                  setState(STATE_REDOX, null, true);
                                                  setState(STATE_VALUES_VALID, false, true);
                                      
                                                  log('Bayrol: Pumpe läuft nicht. pH und Redox wurden auf null gesetzt.', 'warn');
                                                  return;
                                              }
                                      
                                              if (values.ph === undefined && values.redox === undefined) {
                                                  loggedIn = false;
                                                  setState(STATE_CONNECTED, false, true);
                                                  setState(STATE_VALUES_VALID, false, true);
                                                  setState(STATE_PH, null, true);
                                                  setState(STATE_REDOX, null, true);
                                      
                                                  log('Bayrol: Keine pH-/Redox-Werte gefunden. Werte wurden auf null gesetzt. HTML-Auszug: ' + html.substring(0, 1500), 'warn');
                                                  return;
                                              }
                                      
                                              if (values.ph !== undefined) {
                                                  setState(STATE_PH, Number(values.ph), true);
                                              } else {
                                                  setState(STATE_PH, null, true);
                                              }
                                      
                                              if (values.redox !== undefined) {
                                                  setState(STATE_REDOX, Number(values.redox), true);
                                              } else {
                                                  setState(STATE_REDOX, null, true);
                                              }
                                      
                                              setState(STATE_VALUES_VALID, true, true);
                                      
                                              log('Bayrol: Werte aktualisiert: ' + JSON.stringify(values));
                                      
                                          } catch (err) {
                                              loggedIn = false;
                                              setState(STATE_CONNECTED, false, true);
                                              setState(STATE_VALUES_VALID, false, true);
                                              setState(STATE_PH, null, true);
                                              setState(STATE_REDOX, null, true);
                                      
                                              log('Bayrol Fehler: ' + err.message, 'warn');
                                          } finally {
                                              pollRunning = false;
                                          }
                                      }
                                      
                                      function isWithinPollWindow() {
                                          const now = new Date();
                                          const hour = now.getHours();
                                          const minute = now.getMinutes();
                                      
                                          // 09:00 bis 21:00 inklusive
                                          if (hour < 9) return false;
                                          if (hour > 21) return false;
                                          if (hour === 21 && minute > 0) return false;
                                      
                                          return true;
                                      }
                                      
                                      function pollBayrolIfInWindow() {
                                          if (!isWithinPollWindow()) {
                                              log('Bayrol: Außerhalb des Abfragezeitraums 09:00–21:00, kein Abruf.');
                                              return;
                                          }
                                      
                                          pollBayrol();
                                      }
                                      
                                      // Objekte sauber definieren
                                      ensureObjects();
                                      
                                      // Beim Skriptstart nur abrufen, wenn innerhalb des Zeitfensters
                                      setTimeout(pollBayrolIfInWindow, 3000);
                                      
                                      // alle 10 Minuten von 09:00 bis 20:50
                                      schedule('*/10 9-20 * * *', pollBayrol);
                                      
                                      // zusätzlich exakt um 21:00
                                      schedule('0 21 * * *', pollBayrol);
                                      
                                      OliverIOO 1 Antwort Letzte Antwort
                                      0
                                      • R radi71

                                        Also ich habe mal ein lauffähiges javascript für den iobroker erstellt.

                                        Was ich ausgeklammert habe ist die Temp, da ich keinen Sensor dran habe, aber PH + Redox wird zuverlässig ausgelesen.

                                        User + PW eintragen und die cid rausfinden (im Browser einmal anmelden dann F12 und dann steht da in der Konsole die cid

                                        d59be455-6a5e-4638-b2b4-5b118ddfbe45-image.jpeg

                                        ich lese nur zwischen 9 und 21 Uhr aus, alle 10 Min, da sonst meine Umwälzpumpe eh nicht läuft.
                                        Um keine falschen Werte anzuzeigen setze ich sie auf null wenn die Pumpe nicht läuft, aber das ist noch nicht 100%.

                                        Also hier das Script:

                                        const https = require('https');
                                        const { URL } = require('url');
                                        
                                        // ioBroker JavaScript-Adapter-Instanz
                                        const JS_INSTANCE = 'javascript.0';
                                        
                                        // Zugangsdaten
                                        const USER = 'xxx';
                                        const PASS = 'xxx';
                                        
                                        // Bayrol Controller-ID
                                        const CID = 'xxxxx';
                                        
                                        const BASE = 'https://www.bayrol-poolaccess.de/webview';
                                        
                                        const LOGIN_URL = `${BASE}/m/login.php`;
                                        const PLANTS_M_URL = `${BASE}/m/plants.php`;
                                        const DATA_URL = `${BASE}/getdata.php?cid=${CID}`;
                                        
                                        // ioBroker States
                                        const STATE_PH = `${JS_INSTANCE}.bayrol.ph`;
                                        const STATE_REDOX = `${JS_INSTANCE}.bayrol.redox`;
                                        const STATE_LAST_UPDATE = `${JS_INSTANCE}.bayrol.lastUpdate`;
                                        const STATE_CONNECTED = `${JS_INSTANCE}.bayrol.connected`;
                                        const STATE_PUMP_RUNNING = `${JS_INSTANCE}.bayrol.pumpRunning`;
                                        const STATE_VALUES_VALID = `${JS_INSTANCE}.bayrol.valuesValid`;
                                        
                                        let cookies = {};
                                        let loggedIn = false;
                                        let pollRunning = false;
                                        
                                        function ensureObjects() {
                                            setObject(STATE_PH, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol pH',
                                                    type: 'number',
                                                    role: 'value.ph',
                                                    unit: 'pH',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        
                                            setObject(STATE_REDOX, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol Redox',
                                                    type: 'number',
                                                    role: 'value',
                                                    unit: 'mV',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        
                                            setObject(STATE_LAST_UPDATE, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol letzte Aktualisierung',
                                                    type: 'string',
                                                    role: 'date',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        
                                            setObject(STATE_CONNECTED, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol verbunden',
                                                    type: 'boolean',
                                                    role: 'indicator.connected',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        
                                            setObject(STATE_PUMP_RUNNING, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol Umwälzpumpe läuft',
                                                    type: 'boolean',
                                                    role: 'indicator',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        
                                            setObject(STATE_VALUES_VALID, {
                                                type: 'state',
                                                common: {
                                                    name: 'Bayrol Messwerte gültig',
                                                    type: 'boolean',
                                                    role: 'indicator',
                                                    read: true,
                                                    write: false
                                                },
                                                native: {}
                                            });
                                        }
                                        
                                        function saveCookies(setCookieHeaders) {
                                            if (!setCookieHeaders) return;
                                        
                                            if (!Array.isArray(setCookieHeaders)) {
                                                setCookieHeaders = [setCookieHeaders];
                                            }
                                        
                                            setCookieHeaders.forEach(cookie => {
                                                const firstPart = cookie.split(';')[0];
                                                const eq = firstPart.indexOf('=');
                                        
                                                if (eq > 0) {
                                                    const name = firstPart.substring(0, eq).trim();
                                                    const value = firstPart.substring(eq + 1).trim();
                                                    cookies[name] = value;
                                                }
                                            });
                                        }
                                        
                                        function getCookieHeader() {
                                            return Object.entries(cookies)
                                                .map(([name, value]) => `${name}=${value}`)
                                                .join('; ');
                                        }
                                        
                                        function getAttr(tag, attrName) {
                                            const regex = new RegExp(attrName + '\\s*=\\s*["\\\']([^"\\\']*)["\\\']', 'i');
                                            const match = tag.match(regex);
                                            return match ? match[1] : '';
                                        }
                                        
                                        function request(method, url, body, extraHeaders = {}) {
                                            return new Promise((resolve, reject) => {
                                                const u = new URL(url);
                                        
                                                const headers = {
                                                    'User-Agent': 'Mozilla/5.0',
                                                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                                                    'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8',
                                                    ...extraHeaders
                                                };
                                        
                                                const cookieHeader = getCookieHeader();
                                        
                                                if (cookieHeader) {
                                                    headers['Cookie'] = cookieHeader;
                                                }
                                        
                                                let payload = null;
                                        
                                                if (body !== undefined && body !== null) {
                                                    payload = String(body);
                                                    headers['Content-Length'] = Buffer.byteLength(payload);
                                                }
                                        
                                                const options = {
                                                    protocol: u.protocol,
                                                    hostname: u.hostname,
                                                    port: u.port || 443,
                                                    path: u.pathname + u.search,
                                                    method,
                                                    headers
                                                };
                                        
                                                const req = https.request(options, res => {
                                                    const chunks = [];
                                        
                                                    saveCookies(res.headers['set-cookie']);
                                        
                                                    res.on('data', chunk => chunks.push(chunk));
                                        
                                                    res.on('end', () => {
                                                        resolve({
                                                            statusCode: res.statusCode,
                                                            headers: res.headers,
                                                            body: Buffer.concat(chunks).toString('utf8')
                                                        });
                                                    });
                                                });
                                        
                                                req.on('error', reject);
                                        
                                                req.setTimeout(15000, () => {
                                                    req.destroy(new Error('Timeout'));
                                                });
                                        
                                                if (payload) {
                                                    req.write(payload);
                                                }
                                        
                                                req.end();
                                            });
                                        }
                                        
                                        async function requestFollow(method, url, body, headers = {}) {
                                            let currentMethod = method;
                                            let currentUrl = url;
                                            let currentBody = body;
                                            let currentHeaders = headers;
                                        
                                            for (let i = 0; i < 5; i++) {
                                                const res = await request(currentMethod, currentUrl, currentBody, currentHeaders);
                                        
                                                if (![301, 302, 303, 307, 308].includes(res.statusCode) || !res.headers.location) {
                                                    return res;
                                                }
                                        
                                                const oldUrl = currentUrl;
                                                const nextUrl = new URL(res.headers.location, currentUrl).toString();
                                        
                                                if (res.statusCode === 307 || res.statusCode === 308) {
                                                    currentUrl = nextUrl;
                                                } else {
                                                    currentMethod = 'GET';
                                                    currentUrl = nextUrl;
                                                    currentBody = null;
                                                    currentHeaders = {
                                                        'Referer': oldUrl
                                                    };
                                                }
                                            }
                                        
                                            throw new Error('Zu viele Redirects');
                                        }
                                        
                                        function parseLoginForm(html) {
                                            const form = {};
                                            const inputTags = html.match(/<input\b[^>]*>/gi) || [];
                                        
                                            let usernameSet = false;
                                            let passwordSet = false;
                                        
                                            inputTags.forEach(tag => {
                                                const name = getAttr(tag, 'name');
                                                const type = (getAttr(tag, 'type') || 'text').toLowerCase();
                                                const value = getAttr(tag, 'value');
                                        
                                                if (!name) return;
                                        
                                                form[name] = value || '';
                                        
                                                if (!usernameSet && (
                                                    type === 'email' ||
                                                    type === 'text' ||
                                                    /user|mail|email|login|benutzer/i.test(name)
                                                )) {
                                                    form[name] = USER;
                                                    usernameSet = true;
                                                }
                                        
                                                if (!passwordSet && (
                                                    type === 'password' ||
                                                    /pass|pwd|kennwort/i.test(name)
                                                )) {
                                                    form[name] = PASS;
                                                    passwordSet = true;
                                                }
                                            });
                                        
                                            if (!usernameSet) {
                                                form.username = USER;
                                            }
                                        
                                            if (!passwordSet) {
                                                form.password = PASS;
                                            }
                                        
                                            if (form.autologin !== undefined) {
                                                form.autologin = 'on';
                                            }
                                        
                                            const formMatch = html.match(/<form\b[^>]*action\s*=\s*["']([^"']+)["']/i);
                                        
                                            const action = formMatch
                                                ? new URL(formMatch[1], LOGIN_URL).toString()
                                                : `${BASE}/m/login.php?r=reg`;
                                        
                                            return {
                                                action,
                                                form
                                            };
                                        }
                                        
                                        function formEncode(obj) {
                                            return Object.entries(obj)
                                                .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
                                                .join('&');
                                        }
                                        
                                        function cleanHtmlText(value) {
                                            return String(value || '')
                                                .replace(/<script[\s\S]*?<\/script>/gi, '')
                                                .replace(/<style[\s\S]*?<\/style>/gi, '')
                                                .replace(/<[^>]*>/g, '')
                                                .replace(/&nbsp;/g, ' ')
                                                .replace(/&#160;/g, ' ')
                                                .replace(/&deg;/g, '°')
                                                .replace(/&auml;/g, 'ä')
                                                .replace(/&ouml;/g, 'ö')
                                                .replace(/&uuml;/g, 'ü')
                                                .replace(/&Auml;/g, 'Ä')
                                                .replace(/&Ouml;/g, 'Ö')
                                                .replace(/&Uuml;/g, 'Ü')
                                                .replace(/&szlig;/g, 'ß')
                                                .replace(/&amp;/g, '&')
                                                .replace(/\s+/g, ' ')
                                                .trim();
                                        }
                                        
                                        function parseNumber(value) {
                                            const text = cleanHtmlText(value)
                                                .replace(',', '.')
                                                .replace(/[^\d.+-]/g, '');
                                        
                                            const number = parseFloat(text);
                                        
                                            return Number.isFinite(number) ? number : null;
                                        }
                                        
                                        function labelToKey(label) {
                                            const l = cleanHtmlText(label)
                                                .replace(/\[[^\]]*\]/g, '')
                                                .replace(/\./g, '')
                                                .trim()
                                                .toLowerCase();
                                        
                                            if (l === 'ph' || l.includes('ph')) {
                                                return 'ph';
                                            }
                                        
                                            if (l.includes('redox') || l.includes('orp') || l.includes('mv')) {
                                                return 'redox';
                                            }
                                        
                                            return null;
                                        }
                                        
                                        function hasCssClass(html, className) {
                                            const regex = new RegExp('class\\s*=\\s*["\\\'][^"\\\']*\\b' + className + '\\b[^"\\\']*["\\\']', 'i');
                                            return regex.test(String(html || ''));
                                        }
                                        
                                        function parsePumpRunning(html) {
                                            const source = String(html || '');
                                        
                                            if (hasCssClass(source, 'gstat_ok')) {
                                                return true;
                                            }
                                        
                                            if (
                                                hasCssClass(source, 'gstat_nok') ||
                                                hasCssClass(source, 'gstat_error') ||
                                                hasCssClass(source, 'gstat_err') ||
                                                hasCssClass(source, 'gstat_alarm') ||
                                                hasCssClass(source, 'gstat_off')
                                            ) {
                                                return false;
                                            }
                                        
                                            const match = source.match(/class\s*=\s*["'][^"']*\bgstat_[^"']*["']/i);
                                        
                                            if (match) {
                                                log('Bayrol: Unbekannte Statusklasse gefunden: ' + match[0], 'warn');
                                            } else {
                                                log('Bayrol: Keine gstat-Statusklasse gefunden', 'warn');
                                            }
                                        
                                            return false;
                                        }
                                        
                                        function parseValues(html) {
                                            const source = String(html || '');
                                            const values = {};
                                        
                                            const boxRegex = /<div\b[^>]*class\s*=\s*["'][^"']*tab_box[^"']*["'][^>]*>([\s\S]*?)(?=<div\b[^>]*class\s*=\s*["'][^"']*tab_box|<div\b[^>]*class\s*=\s*["'][^"']*gapp_ase|<\/body>|$)/gi;
                                        
                                            let boxMatch;
                                        
                                            while ((boxMatch = boxRegex.exec(source)) !== null) {
                                                const boxHtml = boxMatch[1];
                                        
                                                const spanMatch = boxHtml.match(/<span\b[^>]*>([\s\S]*?)<\/span>/i);
                                                const h1Match = boxHtml.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i);
                                        
                                                if (!spanMatch || !h1Match) {
                                                    continue;
                                                }
                                        
                                                const label = cleanHtmlText(spanMatch[1]);
                                                const number = parseNumber(h1Match[1]);
                                                const key = labelToKey(label);
                                        
                                                if (key && number !== null) {
                                                    values[key] = Number(number);
                                                }
                                            }
                                        
                                            const spanH1Regex = /<span\b[^>]*>([\s\S]*?)<\/span>[\s\S]{0,400}?<h1\b[^>]*>([\s\S]*?)<\/h1>/gi;
                                        
                                            let spanH1Match;
                                        
                                            while ((spanH1Match = spanH1Regex.exec(source)) !== null) {
                                                const label = cleanHtmlText(spanH1Match[1]);
                                                const number = parseNumber(spanH1Match[2]);
                                                const key = labelToKey(label);
                                        
                                                if (key && number !== null) {
                                                    values[key] = Number(number);
                                                }
                                            }
                                        
                                            if (values.ph === undefined) {
                                                const phFallback = source.match(/pH\s*(?:\[[^\]]*\])?[\s\S]{0,500}?<h1[^>]*>\s*([0-9]+(?:[.,][0-9]+)?)\s*<\/h1>/i);
                                        
                                                if (phFallback) {
                                                    values.ph = Number(parseFloat(phFallback[1].replace(',', '.')));
                                                }
                                            }
                                        
                                            if (values.redox === undefined) {
                                                const redoxFallback = source.match(/Redox\s*(?:\[[^\]]*\])?[\s\S]{0,500}?<h1[^>]*>\s*([0-9]+(?:[.,][0-9]+)?)\s*<\/h1>/i);
                                        
                                                if (redoxFallback) {
                                                    values.redox = Number(parseFloat(redoxFallback[1].replace(',', '.')));
                                                }
                                            }
                                        
                                            if (values.redox !== undefined && values.redox < 100) {
                                                log('Bayrol: Redox-Wert unplausibel verworfen: ' + values.redox, 'warn');
                                                delete values.redox;
                                            }
                                        
                                            return values;
                                        }
                                        
                                        async function login() {
                                            cookies = {};
                                        
                                            log('Bayrol: Loginseite abrufen ...');
                                        
                                            const loginPage = await requestFollow('GET', LOGIN_URL, null);
                                            const parsed = parseLoginForm(loginPage.body);
                                        
                                            log(`Bayrol: Login-Action: ${parsed.action}`);
                                        
                                            const loginBody = formEncode(parsed.form);
                                        
                                            const loginRes = await requestFollow('POST', parsed.action, loginBody, {
                                                'Content-Type': 'application/x-www-form-urlencoded',
                                                'Referer': LOGIN_URL
                                            });
                                        
                                            const body = String(loginRes.body);
                                        
                                            if (
                                                body.includes('Fehler') ||
                                                body.includes('Zeit abgelaufen') ||
                                                body.includes('Captcha')
                                            ) {
                                                throw new Error('Bayrol Login fehlgeschlagen');
                                            }
                                        
                                            loggedIn = true;
                                            log('Bayrol: Login erfolgreich');
                                        }
                                        
                                        async function pollBayrol() {
                                            if (pollRunning) {
                                                log('Bayrol: Abruf läuft noch, überspringe diesen Durchlauf', 'warn');
                                                return;
                                            }
                                        
                                            pollRunning = true;
                                        
                                            try {
                                                if (!loggedIn) {
                                                    await login();
                                                }
                                        
                                                const res = await requestFollow('GET', DATA_URL, null, {
                                                    'Referer': PLANTS_M_URL
                                                });
                                        
                                                const html = String(res.body);
                                        
                                                if (html.includes('Anmeldung') && html.includes('Passwort')) {
                                                    loggedIn = false;
                                                    throw new Error('Session abgelaufen, Login wird beim nächsten Lauf erneuert');
                                                }
                                        
                                                const pumpRunning = parsePumpRunning(html);
                                                const values = parseValues(html);
                                        
                                                setState(STATE_CONNECTED, true, true);
                                                setState(STATE_PUMP_RUNNING, pumpRunning, true);
                                                setState(STATE_LAST_UPDATE, new Date().toISOString(), true);
                                        
                                                log(`Bayrol: Antwort Status ${res.statusCode}, Länge ${html.length}, Pumpe ${pumpRunning}, Werte ${JSON.stringify(values)}`);
                                        
                                                if (!pumpRunning) {
                                                    setState(STATE_PH, null, true);
                                                    setState(STATE_REDOX, null, true);
                                                    setState(STATE_VALUES_VALID, false, true);
                                        
                                                    log('Bayrol: Pumpe läuft nicht. pH und Redox wurden auf null gesetzt.', 'warn');
                                                    return;
                                                }
                                        
                                                if (values.ph === undefined && values.redox === undefined) {
                                                    loggedIn = false;
                                                    setState(STATE_CONNECTED, false, true);
                                                    setState(STATE_VALUES_VALID, false, true);
                                                    setState(STATE_PH, null, true);
                                                    setState(STATE_REDOX, null, true);
                                        
                                                    log('Bayrol: Keine pH-/Redox-Werte gefunden. Werte wurden auf null gesetzt. HTML-Auszug: ' + html.substring(0, 1500), 'warn');
                                                    return;
                                                }
                                        
                                                if (values.ph !== undefined) {
                                                    setState(STATE_PH, Number(values.ph), true);
                                                } else {
                                                    setState(STATE_PH, null, true);
                                                }
                                        
                                                if (values.redox !== undefined) {
                                                    setState(STATE_REDOX, Number(values.redox), true);
                                                } else {
                                                    setState(STATE_REDOX, null, true);
                                                }
                                        
                                                setState(STATE_VALUES_VALID, true, true);
                                        
                                                log('Bayrol: Werte aktualisiert: ' + JSON.stringify(values));
                                        
                                            } catch (err) {
                                                loggedIn = false;
                                                setState(STATE_CONNECTED, false, true);
                                                setState(STATE_VALUES_VALID, false, true);
                                                setState(STATE_PH, null, true);
                                                setState(STATE_REDOX, null, true);
                                        
                                                log('Bayrol Fehler: ' + err.message, 'warn');
                                            } finally {
                                                pollRunning = false;
                                            }
                                        }
                                        
                                        function isWithinPollWindow() {
                                            const now = new Date();
                                            const hour = now.getHours();
                                            const minute = now.getMinutes();
                                        
                                            // 09:00 bis 21:00 inklusive
                                            if (hour < 9) return false;
                                            if (hour > 21) return false;
                                            if (hour === 21 && minute > 0) return false;
                                        
                                            return true;
                                        }
                                        
                                        function pollBayrolIfInWindow() {
                                            if (!isWithinPollWindow()) {
                                                log('Bayrol: Außerhalb des Abfragezeitraums 09:00–21:00, kein Abruf.');
                                                return;
                                            }
                                        
                                            pollBayrol();
                                        }
                                        
                                        // Objekte sauber definieren
                                        ensureObjects();
                                        
                                        // Beim Skriptstart nur abrufen, wenn innerhalb des Zeitfensters
                                        setTimeout(pollBayrolIfInWindow, 3000);
                                        
                                        // alle 10 Minuten von 09:00 bis 20:50
                                        schedule('*/10 9-20 * * *', pollBayrol);
                                        
                                        // zusätzlich exakt um 21:00
                                        schedule('0 21 * * *', pollBayrol);
                                        
                                        OliverIOO Offline
                                        OliverIOO Offline
                                        OliverIO
                                        schrieb am zuletzt editiert von OliverIO
                                        #102

                                        @radi71

                                        nochmal eines?
                                        was war das problem am letzen?
                                        bzw was ist der vorteil von diesem?

                                        Meine Adapter und Widgets
                                        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                        Links im Profil

                                        R 1 Antwort Letzte Antwort
                                        0
                                        • OliverIOO OliverIO

                                          @radi71

                                          nochmal eines?
                                          was war das problem am letzen?
                                          bzw was ist der vorteil von diesem?

                                          R Offline
                                          R Offline
                                          radi71
                                          schrieb am zuletzt editiert von radi71
                                          #103

                                          @OliverIO das andere hat bei mir nicht funktioniert, bzw. vielleicht hatte ich auch nicht den letzten Stand gefunden

                                          OliverIOO 1 Antwort Letzte Antwort
                                          0

                                          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
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          559

                                          Online

                                          33.0k

                                          Benutzer

                                          83.3k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2026
                                          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