Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen

    NEWS

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen

    This topic has been deleted. Only users with topic management privileges can see it.
    • OliverIO
      OliverIO @steinche last edited by OliverIO

      @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

      Error','stack':'Error: Parse Error: Invalid header value char\n at Function.AxiosError.from

      Ich bin etwas verwirrt.
      Im obigen Codebeispiel wird request genutzt. Die Fehlermeldung ist jetzt aber von Axios.
      Kannst du bitte mal deinen kompletten Code posten

      Du kannst mal hier schauen
      https://www.codewithyou.com/blog/axioserror-parse-error-invalid-header-value-char

      Mit der oben besagten Version 12.15 wurde eingeführt, das der response header einer http anfrage strikter geprüft wird. wenn nun der server ein nicht erlaubtes zeichen sendet, dann wird dieser fehler geworfen.
      mit der Option im Link, kann man das unterdrücken.
      Allerdings sollte man sich Fragen, warum meteohub so ein zeichen sendet.

      evtl hat dein curl auch eine entsprechende warnung angezeigt?

      S 1 Reply Last reply Reply Quote 0
      • S
        steinche @OliverIO last edited by

        @oliverio

        Bei mir läuft die node Version 18.17.0

        Der aktuelle Code sieht so aus:

        /* Meteohub
        Skript holt Daten aus Meteohub XML Datei, bereitet sie auf und stellt einige Datenpunkte zur Verfügung
        erstellt: 2020 Wolfgang Berger
        {1}
        V 0.1 Initiale Version. Hartcodierte Zuordnung. Wird nicht funktionieren sobald der Windmesser online ist.
        V 0.2 jetzt Sensoren in Liste
        V 0.3 kosmetische Aufbereitung. Altlasten entfernt.
        */
         
        // Settings   ################################################################
        const mh_URL = 'http://192.168.75.9/meteograph.cgi?text=allxml';
        const axios = require('axios') // das an den Anfang des Skripts
        
        // End of settings ###########################################################
         
         
        // Includes    ################################################################
        const request = require('request');    
        var parser = require('xml2json');
        const util = require('util');      // for debugging. Use log(util.inspect(obj));
         
        // Type definitions  ################################################################
        var state_temp = {      type: 'number',  unit: '°C',   read: true,  write: false,role: 'value.temperature' };
        var state_json = {                                     read: true,  write: false,role: 'mh.json' };    
        var state_humidity = {  type: 'number',  unit: '%rH',  read: true,  write: false,role: 'value.humidity' };                                  
        var state_speed = {     type: 'number',  unit: 'km/h', read: true,  write: false,role: 'value.speed' };                                  
        var state_direction = { type: 'number',  unit: '°',    read: true,  write: false,role: 'value.direction' };                                  
        var state_pressure  = { type: 'number',  unit: 'mbar', read: true,  write: false,role: 'value.pressure' };     
        var state_rainrate  = { type: 'number',  unit: 'mm/h', read: true,  write: false,role: 'value.precipitation.hour' };         
        var state_rain  = {     type: 'number',  unit: 'mm',   read: true,  write: false,role: 'value.precipitation.today' };             
         
        // Now build State Tree ################################################################
        function parseXML(xmldata,do_init) {
           log(xmldata)
           var mh_json = parser.toJson(xmldata);    // convert XML to JSON
           var mh_data = JSON.parse(mh_json);       // parse JSON into JS object
           let data = mh_data.meteohub.data;        // only use the data section of the object. We ignore the config section for now.
         
           // Loop through data sections. each data[i] contains data for a given timeframe like actual, like 1h, 1day, etc.
           for(let i = 0; i < data.length; i++) {
             let folder = 'meteohub.' + data[i].timeframe + '.';       // timeframe is can be "actual", "alltime" and much more. Each datasection only contains one timeframe value
             let item = data[i].item;
             //   log(util.inspect(data[i]));
         
             // Now we have selected one timeframe and loop through all items
             // instead of building a state tree with hundreds of values, we pick only the ones that are interesting.
             for(let j = 0; j < item.length; j++) {
                let id = folder + item[j].sensor + '.' + item[j].cat;
         
                // Temperature Value in degrees Celsius
                if( (item[j].cat == 'temp') && (item[j].unit == 'c')) {
                    if (do_init==true) {    createState(id,parseFloat(item[j].$t),state_temp); }
                      else {    setState(id,parseFloat(item[j].$t)); }
                }
         
                // Humidity as relative humidity
                if( (item[j].cat == 'hum') && (item[j].unit == 'rel')) {
                    if (do_init==true) {   createState(id,parseFloat(item[j].$t),state_humidity); }
                      else  {   setState(id,parseFloat(item[j].$t)); }          
                }
         
                // Air pressure refered to sealevel
                if( (item[j].cat == 'sealevel') && (item[j].unit == 'hpa')) {   
                    if (do_init==true) {   createState(id,parseFloat(item[j].$t),state_pressure); }
                      else  {   setState(id,parseFloat(item[j].$t)); }          
                }        
         
                // rain values in mm
                if( (item[j].sensor == 'rain0') && (item[j].unit == 'mm')) {
                    if (do_init==true) { createState(id,parseFloat(item[j].$t),state_rain);  }
                      else { setState(id,parseFloat(item[j].$t));  }
                }
         
                // for windsensor currently we tend to catch nearly all, because the whitelist could be long. For example windspeed is interesting in different units.
                // Therefore instead of whitelisting the values we do the oposit and use a blacklist for the ones we don't like.
                if( (item[j].sensor == 'wind0') ) {
                    if ((item[j].unit == 'time')) {
                        let dat = item[j].$t;
                        let d = new Date(dat.substring(0,4) + '-' + dat.substring(4,6) + '-' + dat.substring(6,8) + 'T' + dat.substring(8,10) +':' + dat.substring(10,12) + ':'+ dat.substring(12,14) );
                        if (do_init==true) {    createState(id+'.'+item[j].unit,  d);    }
                          else {    setState(id+'.'+item[j].unit,  d);    }
                    }
                    else {
                        // first catch values in degrees celsius. Because there we can set the unit. Leave the others without unit.
                        if (item[j].unit == 'c') {
                          if (do_init==true) { createState(id+'.'+item[j].unit,  parseFloat(item[j].$t),state_temp); }                           
                            else  { setState(id+'.'+item[j].unit,  parseFloat(item[j].$t)); }               
                        }
                        else {
                            // Blacklisting for values we don't like
                            if (!(item[j].unit == 'f' || item[j].unit == 'en' || item[j].unit == 'nl' || item[j].unit == 'mph')) {
                            if (do_init==true) { createState(id+'.'+item[j].unit,  parseFloat(item[j].$t)); }                           
                                else  { setState(id+'.'+item[j].unit,  parseFloat(item[j].$t)); }               
                            }
                        }
                    }
                }
         
             }
            }
         
        }  // end parseXML()
         
        async function getXML(do_init) {
            // loads full meteohub xml file from the mh_URL and calls the parse function.
            // on very first execution do_init is true and all states are created. Each successive call only sets the state values.
            
            log('meteohub query data from '+mh_URL); // Debug output
            let result = null
            try {
                result = await execAsync('curl '+mh_URL) 
                log(result) // kann weg wenns geht, ansonsten das hier posten
            } catch(e) {log(e)}
            if (result) {
                var start = new Date();            
                parseXML(result, do_init);
                var time = new Date() - start;            
                log('Meteohub XML2JSON Durchlaufzeit: '+time);             
            } else {
                log('Keine Daten','warn')
            };  
        }
        
        
        // On first script execution, create the states
         let do_init=true;
         getXML(do_init);
        
        function execAsync(f) {
            return new Promise((resolve, reject) => {
                exec(f, function (error, stdout, stderr) {
                    resolve();
                });
            })
        }
        
        // Regular Update
        schedule('*/1 * * * *', function () {
            let do_init=false;
            getXML(do_init);  // regelmäßiger Update
        });
        

        Ursprünglich war es der Code aus dem Post und die Zeile für den Datenabruf:

        const mh_URL = 'http://192.168.75.9/meteograph.cgi?text=allxml';
        

        musste angepasst werden. Danach hatte ich das Problem, dass er wegen folgenden Fehler hatte:

        20.7.2023, 21:05:08.838	[error]: javascript.0 (2129892) script.js.common.WetterdatenEinlesen: Fehler beim Herunterladen Meteohub XML: Error: Parse Error: Invalid header value char
        

        @Homoran , @paul53 und @ticaki haben sich dann an vielen Dingen versucht, aber bisher ohne Erfolg 😢

        OliverIO 1 Reply Last reply Reply Quote 0
        • OliverIO
          OliverIO @steinche last edited by

          @steinche

          da ist der code mit axios abruf nicht mehr drin.
          lese den link oben durch, dann kennst du den grund, warum der fehler geworfen wurde.
          funktioniert den der curl aufruf aus dem skript heraus?
          da könnten evtl noch berechtigungsprobleme anstehen.
          der nutzer iobroker muss curl benutzen dürfen
          skripte werden immer als benutzer iobroker auf dem system durchgeführt

          T S 2 Replies Last reply Reply Quote 0
          • T
            ticaki Developer @OliverIO last edited by ticaki

            @oliverio
            Hallo Oliver,

            das ursprüngliche Skript verwendete Request und warf diesen Fehler:

            3.8.2023, 12:31:23.341	[error]: javascript.0 (1584787) script.js.common.WetterdatenEinlesen: Fehler beim Herunterladen Meteohub XML: Error: Parse Error: Invalid header value char
            

            Da ich request nie wirklich genutzt habe habe ich das auf axios geändert das diesen Fehler produzierte

            3.8.2023, 22:45:34.282	[error]: javascript.0 (830120) script.js.common.WetterdatenEinlesen: Fehler beim Herunterladen Meteohub XML: Error: Parse Error: Invalid header value char
            

            Ist http sollte also nicht mit der axios option zu beheben sein oder?
            Das ist die Abrufadresse:

            http://192.168.75.9/meteograph.cgi?text=allxml
            

            Ein curl auf der Console hat dieses Ergebnis gebracht:

            root@ioBroker-Master-51:~# curl http://192.168.75.9/meteograph.cgi?text=allxml
            <?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
            <meteohub>
              <config>
                <language>de</language>
                <temp_sensor unit="c" print="°C">th0</temp_sensor>
                <hum_sensor unit="rel" print="%">th0</hum_sensor>
                <dew_sensor unit="c" print="°C">th0</dew_sensor>
            snip
            

            Daher meine Vorschlag das mit curl zu lösen.

            Vielleicht kanns du ihm ja helfen 🙂

            OliverIO 1 Reply Last reply Reply Quote 0
            • S
              steinche @OliverIO last edited by

              @oliverio said in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

              @steinche

              da ist der code mit axios abruf nicht mehr drin.

              @ticaki hat ziemlich viel versucht.

              lese den link oben durch, dann kennst du den grund, warum der fehler geworfen wurde.
              Habe es auf axios umgebaut und um ', { insecureHTTPParser: true }' ergänzt -> ERFOLGREICH!!

              funktioniert den der curl aufruf aus dem skript heraus?
              da könnten evtl noch berechtigungsprobleme anstehen.
              der nutzer iobroker muss curl benutzen dürfen
              skripte werden immer als benutzer iobroker auf dem system durchgeführt

              Berechtigungen für alle auf ausführen gesetzt, ohne Erfolg.

              OliverIO 1 Reply Last reply Reply Quote 0
              • OliverIO
                OliverIO @steinche last edited by

                @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                Habe es auf axios umgebaut und um ', { insecureHTTPParser: true }' ergänzt -> ERFOLGREICH!!

                Na dann kann es ja weitergehen.
                Dann braucht man den curl-Aufruf nicht mehr.

                Wenn du schreibst das etwas nicht tut, dann musst du auch irgenwie mal noch das ergebnis/fehlermeldung liefern.
                ferndiagnose ist an sich schon nicht so einfach. aber mit glaskugel unmöglich
                auch den curl-aufruf hätten wir noch zum laufen bekommen.
                aber der abruf aus dem skript direkt heraus ist besser

                T 1 Reply Last reply Reply Quote 0
                • OliverIO
                  OliverIO @ticaki last edited by

                  @ticaki sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                  Daher meine Vorschlag das mit curl zu lösen

                  das ist schon klar.
                  nur hat niemand mal nach dem Grund für die fehlermeldung gesucht.
                  und er hat seinen code versteckt. so geht man von falschen voraussetzungen aus und verschendet ungern zeit. das ist bspw bei mir so ein lust-killer

                  S 1 Reply Last reply Reply Quote 0
                  • T
                    ticaki Developer @OliverIO last edited by ticaki

                    @oliverio sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                    @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                    Habe es auf axios umgebaut und um ', { insecureHTTPParser: true }' ergänzt -> ERFOLGREICH!!

                    Na dann kann es ja weitergehen.

                    und wieder was gelernt, hatte das mit dem insecure zwar auch mal gelesen auf auf https bezogen. 🙂

                    1 Reply Last reply Reply Quote 0
                    • S
                      steinche @OliverIO last edited by steinche

                      @oliverio said in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                      und er hat seinen code versteckt. so geht man von falschen voraussetzungen aus und verschendet ungern zeit. das ist bspw bei mir so ein lust-killer

                      Ich hatte die Teile "eingebaut", die @ticaki so versucht hat, daher hatte ich nicht jedes mal den komplette Code gepostet.

                      Die original Funktion:

                      function getXML(do_init) {
                          // loads full meteohub xml file from the mh_URL and calls the parse function.
                          // on very first execution do_init is true and all states are created. Each successive call only sets the state values.
                          log('meteohub query data from '+mh_URL); // Debug output
                          request(mh_URL, function (error, response, body) {
                              if (error) log("Fehler beim Herunterladen Meteohub XML: " + error, 'error');
                              else {
                                  //var start = new Date();
                                  parseXML(body,do_init);
                                  //var time = new Date() - start;            
                                  //log('Meteohub XML2JS Durchlaufzeit: '+time); 
                              };
                          });
                      }
                      

                      bringt den Fehler:

                      23:47:04.347	error	javascript.0 (77182) script.js.common.WetterdatenEinlesen: Fehler beim Herunterladen Meteohub XML: Error: Parse Error: Invalid header value char
                      

                      Das muss doch daran liegen, dass dem request etwas nicht passt?

                      Abschließend noch mal vielen Dank an alle für die Unterstützung, dass die Daten jetzt abgerufen werden!

                      Die Verarbeitung der Daten muss ich noch anpassen, aber das bekomme ich hoffentlich alleine hin. Inzwischen weiß ich etwas mehr zu JavaScript als nur, wie man es schreibt 😊

                      OliverIO 1 Reply Last reply Reply Quote 0
                      • OliverIO
                        OliverIO @steinche last edited by OliverIO

                        @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                        Das muss doch daran liegen, dass dem request etwas nicht passt?

                        @oliverio sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                        Mit der oben besagten Version 12.15 wurde eingeführt, das der response header einer http anfrage strikter geprüft wird. wenn nun der server ein nicht erlaubtes zeichen sendet, dann wird dieser fehler geworfen.

                        Hast du den Artikel gelesen, den ich oben verlinkt habe?
                        Das setzen der Option unterdrückt diese strikte Prüfung.
                        Das Beispiel ist halt nur für axios.
                        wenn man unbedingt das auch für request lösen will muss man im Internet suchen.
                        allerdings ist axios neuer und request ist deprecated. also reicht die eine funktionierende Lösung ja aus.

                        dein aktueller code:
                        jetzt hast du axios wieder zu request zurückgebaut?
                        verstehst du den unterschied zwischen request und axios überhaupt?

                        wer hat den jetzt das folgende geschrieben? Ich blick da nicht mehr durch

                        @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                        Habe es auf axios umgebaut und um ', { insecureHTTPParser: true }' ergänzt -> ERFOLGREICH!!

                        S 1 Reply Last reply Reply Quote 0
                        • S
                          steinche @OliverIO last edited by

                          @oliverio said in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                          @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                          Das muss doch daran liegen, dass dem request etwas nicht passt?

                          @oliverio sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                          Mit der oben besagten Version 12.15 wurde eingeführt, das der response header einer http anfrage strikter geprüft wird. wenn nun der server ein nicht erlaubtes zeichen sendet, dann wird dieser fehler geworfen.

                          Sorry, ich bin von Hause aus SPS Programmierer und dementsprechend eher in anderen Sprachen unterwegs.

                          Hast du den Artikel gelesen, den ich oben verlinkt habe?

                          Den Artikel habe ich gelesen, bin aber davon ausgegangen, dass es sich auf axios bezieht.

                          Das setzen der Option unterdrückt diese strikte Prüfung.

                          Das habe ich festgestellt 😉

                          wenn man unbedingt das auch für request lösen will muss man im Internet suchen.
                          allerdings ist axios neuer und request ist deprecated. also reicht die eine funktionierende Lösung ja aus.

                          dein aktueller code:
                          jetzt hast du axios wieder zu request zurückgebaut?

                          Nein, das war nur eine Frage, weil im ursprünglichen Code von @wberger mit request gearbeitet wurde.

                          verstehst du den unterschied zwischen request und axios überhaupt?

                          Nein, ich kann erkennen, dass die beiden Funktionen(?) Daten holen sollen, damit hört es bei mir schon auf.

                          wer hat den jetzt das folgende geschrieben? Ich blick da nicht mehr durch

                          @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                          Habe es auf axios umgebaut und um ', { insecureHTTPParser: true }' ergänzt -> ERFOLGREICH!!

                          Den Abruf mittels axios hat @ticaki hier geschrieben und ich habe bei mir eingesetzt. Danach haben wir viel hin und her probiert, auch mit curl und mein obiger Kommentar bezog sich auf den Code von @ticaki , den ich um den Parameter aus Deinem Link ergänzt habe. Da habe ich dann selbst hinbekommen. Aber das ist so das Level, auf dem ich mich bewege - also Grundschule addieren im Zahlenbereich 1-10 😉

                          Den Bereich, der die Daten parst konnte ich auch entsprechend der noch für mich wichtigen Daten erweitern. Allerdings ging es bei mir dann über den Zahlenbereich von 10 hinaus, da im Log von ioBroker beim schreiben der Werte bei jedem Wert eine Warnung kommt.

                          2023-08-05 07:38:02.034	warn	Read-only state "javascript.0.meteohub.alltime.sol0.radiation" has been written without ack-flag with value "153.9"
                          

                          Ich versuche immer erst mal selbst zu schauen und nicht, dass man mir den Arm bei jeder Kleinigkeit aus der Sonne legen muss. Die Suche hat folgendes gefunden Klick
                          Daraufhin die Eingträge

                          else { setState(id,parseFloat(item[j].$t)) }
                          

                          gegen:

                          else { setState(id,parseFloat(item[j].$t), true) }
                          

                          ersetzt. "Problem" selbst gelöst und autodidaktisch den Zahlenbereich bis 20 erschlossen 🙂
                          Ich werde den aktuellen Code noch etwas um Kommentare ergänzen, auch den Teil, der die Daten parst um ein paar Standardwerte und in dann hier rein stellen, falls noch jemand Meteohub verwendet direkt, ohne Umweg über Wetterdiente, auch seine Daten zugreifen möchte.

                          Und man kann es nicht oft genug sagen DANKE !!!

                          1 Reply Last reply Reply Quote 0
                          • T
                            ticaki Developer last edited by

                            @steinche sagte in [gelöst] Meteohub Daten, XML parsen, JSON durchsuchen:

                            ersetzt. "Problem" selbst gelöst und autodidaktisch den Zahlenbereich bis 20 erschlossen 🙂

                            https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#best-practice

                            als referenze

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            828
                            Online

                            31.7k
                            Users

                            79.8k
                            Topics

                            1.3m
                            Posts

                            javascript
                            6
                            43
                            2663
                            Loading More Posts
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes
                            Reply
                            • Reply as topic
                            Log in to reply
                            Community
                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                            The ioBroker Community 2014-2023
                            logo