NEWS
NodeRed XML-Daten zerlegen
-
Evtl. fällt jemandem von euch ein, wie das ganze relativ simpel gelöst werden kann `
Ist aber nicht wirklich schwer.Auch wenn rewenode von dieser Lösung nicht begeistert sein wird, aber in Javascript ist es für mich im Moment noch einfacher so etwas zu lösen. Mit einem change-Node und JSONata sollte man es aber genauso hinbekommen können. Ich lasse zum besseren Verständnis mal die Schritt für Schritt Vorgehensweise.
! ````
[{"id":"64fd1aec.c1f11c","type":"comment","z":"3f55344e.eced9c","name":"xml zerlegen","info":"","x":170,"y":520,"wires":[]},{"id":"d6618056.7e59d","type":"inject","z":"3f55344e.eced9c","name":"Teststring","topic":"","payload":" <eta version=""1.0"" xmlns=""http://www.eta.co.at/rest/v1""><value uri=""//user/var/120/10601/0/0/13434"" strvalue=""68"" unit=""°C"" decplaces=""0"" scalefactor=""10"" advtextoffset=""0"">680</value></eta>","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":580,"wires":[["2920c29d.7d53be"]]},{"id":"2920c29d.7d53be","type":"function","z":"3f55344e.eced9c","name":"","func":"var str = msg.payload;\nvar n = str.search("strValue=")+10;//Stelle an dem strValue steht ermitteln\nvar n1 = str.search("unit=")-2;//Stelle an dem unit steht ermitteln\nvar n2 = str.substring(n,n1);//Wert aus String herausschneiden\nvar n3 = parseFloat(n2);//Stringwert in Floatwert umwandeln\nnode.send({payload: {"strValue": n}});//Debug Ausschnittwert 1\nnode.send({payload: {"unit": n1}});// Debug Ausschnitwert2\nnode.send({payload: {"strValue_Float": n3}});//Debug Floatwert\nmsg.payload=n2;// Ausgabe als Strinwert, wenn Floatwert gewuenscht dann n2 durch n3 ersetzen\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":580,"wires":[["fbda119f.d1467"]]},{"id":"fbda119f.d1467","type":"debug","z":"3f55344e.eced9c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":590,"y":580,"wires":[]}]![3639_sc21.jpg](/assets/uploads/files/3639_sc21.jpg) ![3639_sc22.jpg](/assets/uploads/files/3639_sc22.jpg)
-
Und hier noch die Lösung mit einem change-Node. Damit tue ich mich noch etwas schwerer. Aber ich lerne täglich dazu.
! ````
[{"id":"1233a82b.0f69f8","type":"change","z":"3f55344e.eced9c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t$n := $substringAfter(payload, "strValue=");\t$n2 := $substringBefore($n, " unit");\t$n3 := $substring($n2, 1);\t$l := $length($n3)-1;\t$n4 := $substring($n3, -0, $l);\t$nf := $number($n4);\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":676,"wires":[["ec0f7be6.0f69b"]]},{"id":"3f388d3c.679f92","type":"inject","z":"3f55344e.eced9c","name":"Teststring","topic":"","payload":" <eta version=""1.0"" xmlns=""http://www.eta.co.at/rest/v1""><value uri=""//user/var/120/10601/0/0/13434"" strvalue=""68"" unit=""°C"" decplaces=""0"" scalefactor=""10"" advtextoffset=""0"">680</value></eta>","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":676,"wires":[["1233a82b.0f69f8"]]},{"id":"ec0f7be6.0f69b","type":"debug","z":"3f55344e.eced9c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":590,"y":676,"wires":[]},{"id":"b424926b.04b468","type":"comment","z":"3f55344e.eced9c","name":"Wert als Float","info":"","x":130,"y":636,"wires":[]},{"id":"2f5177.8ac9f68a","type":"change","z":"3f55344e.eced9c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"(\t$n := $substringAfter(payload, "strValue=");\t$n2 := $substringBefore($n, " unit");\t$n3 := $substring($n2, 1);\t$l := $length($n3)-1;\t$n4 := $substring($n3, -0, $l);\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":760,"wires":[["46bccbb1.e5a214"]]},{"id":"2448112.7f9af6e","type":"inject","z":"3f55344e.eced9c","name":"Teststring","topic":"","payload":" <eta version=""1.0"" xmlns=""http://www.eta.co.at/rest/v1""><value uri=""//user/var/120/10601/0/0/13434"" strvalue=""68"" unit=""°C"" decplaces=""0"" scalefactor=""10"" advtextoffset=""0"">680</value></eta>","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":760,"wires":[["2f5177.8ac9f68a"]]},{"id":"46bccbb1.e5a214","type":"debug","z":"3f55344e.eced9c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":590,"y":760,"wires":[]},{"id":"2f50c72e.a10b8","type":"comment","z":"3f55344e.eced9c","name":"Wert als String","info":"","x":140,"y":720,"wires":[]}]![3639_sc23.jpg](/assets/uploads/files/3639_sc23.jpg) ![3639_sc24.jpg](/assets/uploads/files/3639_sc24.jpg)
-
Hallo Garf,
danke für deine Hilfe, ich habe den Function Node gewählt und an sich funktioniert es soweit schon was jedoch noch nicht passt und ich selbst auch nicht hinbekomme ist die folgende Fehlermeldung. Aus meiner Sicht liegt es daran, dass es ein JSON Ausdruck und keine Number ist - die Änderung hat bei mir aber leider nicht geklappt.
Invalid JSONata expression: Unable to cast value to a number: "?xml version=\"1.0\" encoding=\"utf-8\"?>\n<eta version="\"1.0\"" xmlns="\"http://www.eta.co.at/rest/v1\"">\n <error>Invalid permission</error>\n</eta>"
-
Sorry deine Ausführungen sind schon ein wenig im Widerspruch.
Hier schreibst Du:
> Ich frage zyklisch, alle 10s, eine http-Adresse ab und bekomme von dort den nachfolgenden ****<size size="150">String</size>**** zurück.
Und jetzt diese Aussage
> dass es ein JSON Ausdruck und keine Number ist
Der angezeigte Fehler würde mich dann noch eher in Richtung change-Node lenken, denn dort habe ich ein Script in JSONata geschrieben. Jedoch steht es im Widerspruch zu dieser Aussage:
> ich habe den Function Node gewählt und an sich funktioniert es soweit schon
Für mich wird es so fast unmöglich hier noch weiter zu helfen. Wie Du den Flows entnehmen kannst, wird über das inject-Node die von dir gepostetet Stringwert-Abfragerückmeldung an die change-Nodes und an das function-Node übergeben. Und heraus kommt dann das gewünschte Ergebnis. Sollte die Rückmeldung in einem anderen Format vorliegen, dann müsstest Du dies mal hier posten und ich schaue es mir noch einmal an. Vielleicht hängst Du mal direkt ein debug-Node an den Ausgang deiner Abfrage. Ein paar Screenshots von deinem flow und den vom debug-Node angezeigten Rückmeldung könnten evtl. auch noch weiter helfen.
Das Christkind hat leider auch in diesem Jahr die berühmte Glaskugel nicht unter den Weihnachtsbaum gelegt. :x
<u>Edit:</u>
Ich habe mir noch einmal Gedanken gemacht. Wahrscheinlich frägst Du über das http-Node Daten ab. Die Rückmeldewerte werden dir im Json-Format zur Verfügung gestellt. Um daraus jetzt ein String zu machen gibt es ein fertiges Node.
Nur den ganzen Budenzauber braucht man nicht, da man die JSON-Werte direkt als Variable verarbeiten kann.
Ich habe es mal an einem einfachen Beispiel versucht nachzustellen:
Abfrage des Rheinpegels
Die JSON-Daten kann man direkt als Wert übernehmen.
Der Wert steht in meinem Beispiel für den Rheinpegelstand (value:) in der Variablen: msg.payload.gaugeZero.valueAber alles nur Spekulation.
-
Hi,
anbei meine hoffentlich konkreteren Punkte:
Ich frage zyklisch über einen http request node meine Heizungssteuerung ab. Der http request Node liefert mir einen XML-String zurück aus welchem ich einen Wert (strValue) als Number benötige. Dieser Wert soll dann in influxDB geschrieben werden
XML in Heizungssteuerung
<eta xmlns="http://www.eta.co.at/rest/v1" version="1.0"><value uri="//user/var/120/10601/0/0/13434" strvalue="71" unit="°C" decplaces="0" scalefactor="10" advtextoffset="0">708</value></eta>
String aus http request node
<eta version="1.0" xmlns="http://www.eta.co.at/rest/v1"><value uri="//user/var/120/10601/0/0/13434" strvalue="71" unit="°C" decplaces="0" scalefactor="10" advtextoffset="0">707</value></eta>
Meine Problemstellung, welche ich nicht gelöst bekomme ist dass ich aus diesem String den Wert von strValue als Number zur Übergabe in influxDB benötige und keinen Plan habe wie ich da hinkommen soll. Eventuell ist mein Ansatz mit dem http request node auch schon nicht der richtige?!?
9006_flow.txt
9006_flow_mit_debug_output.png -
Wie du die Daten aus dem Request bekommst, hat Dir ja Graf schon gezeigt.
Was die Influxdb betrifft, kannst du die Daten zwar direkt per Node-red schreiben (hab ich auch lange so gemacht) aber wenn du nicht so fit mit NR bist, würde ich die Daten jeweils in States schreiben und den iobroker-Influxdb verwenden. Da gehts dann ganz easy.
Bin grad für ein paar Tage im „Leben neben ioBroker“ deshalb kann ich nicht detaillierter helfen.
Gesendet von iPhone mit Tapatalk
-
O.K. versuchen wir es weiter.
Halten wir fest: wir haben als Rückmeldung mit einem Stringwert zu tun.
Bitte hänge an das http-Node entweder das function-Node, oder eins von den change-Nodes und dann ein debug-Node, damit wir uns die Ausgabe ansehen können. Das Node für die influx-DB kenne ich nicht, da müssen wir mal schauen wie und in welchem Format die Daten übergeben werden müssen. Ich benutze als DB phpMyAdmin und aus Erfahrung kann ich dir sagen, dass die Werteübergabe absolut fehlerfrei erfolgen muss.
Daher bitte erst einmal ohne die Anbindung an die Datenbank testen. Da müssen wir sicher im function-Node noch etwas an der Ausgabe arbeiten.
Ich sehe gerade rewenode hat sich gemeldet und kennt sich mit dieser DB offensichtlich aus. Dass ist schon einmal eine gute Sache.
-
Hallo ihr beiden,
lustigerweise funktioniert nun der angehängte Flow. D.h. es werden Werte (strValue) als Number in influxDB geschrieben, trotzdem bekomme ich immer noch einen Fehler im Debug. Den Change Node habe ich von dir übernommen und nicht geändert.
Aber warum bekomme ich da jetzt einen Fehler aber in der Datenbank kommt der Wert richtig als Number an?!?
Edit:
- Ist das Performancemäßig nun die richtige Methode oder gäbs zusätzlich zum Fehler noch Optimierungsbedarf?
- Um auf den Beitrag von rewenode noch zu Antworten: Ich schreibe aktuell lieber direkt in die Datenbank um unnötige Schritte wenn möglich auszulassen - lasse mich aber gerne vom gegenteil überzeugen
9006_flow_-_working.png
-
Du müsstest mal nachsehen von welchem Node die Fehlermeldung kommt.
Die zweite Meldung kommt mit Sicherheit aus dem debug-Node.
Dafür mal auf die Nummer hinter Node: in der Message klicken, dann erhält das fehlermeldende Node einen gestrichelten Rahmen.
-
Ich schreibe aktuell lieber direkt in die Datenbank um unnötige Schritte wenn möglich auszulassen - lasse mich aber gerne vom gegenteil überzeugen `
So habe ich auch ca. 1 Jahr zu meiner vollsten Zufriedenheit gearbeitet;-) Und wenn das bei dir ok ist brauchst du dich von nichts Anderem überzeugen lassen.Bei mir sind halt irgendwann Aktoren (zigbee/wlan(power) ) dazu gekommen, die ihre States ja direkt in ioBroker abbilden. Da ist es dann viel einfacher, die mit einem Klick direkt per influxdb-Adapter zu loggen, ohne note-red bemühen zu müssen.
Und um die Aufbewahrungsfristen und Measurement-typen kümmert sich der Adapter auch selbstständig.
Ich hab da lieber eine einheitliche Art, wie Daten in meine db kommen, als dass ich mehrere Wege bedenken und pflegen muss.
Was bei mir ungünstig war, meine db-Struktur war anders, als ioBroker das tut. Deswegen hab ich der Einfachheit halber die db platt gemacht und mit ioBroker neu aufgebaut.
Allerdings erst nachdem ich erkannt habe, dass die ioBroker-db-Struktur besser als meine Eigenkreation ist;-) Und so wichtig waren mir meine Altdaten nicht, als dass sich eine Konvertierung gelohnt hätte.
Ich visualisiere meine Daten mit Grafana und das geht super einfach bei Aktor=Measurement.
Und generell hat es auch noch Vorteile, zu loggende Daten über einen eigenen State zu loggen.
Die lassen sich dann sehr einfach für eigene Trigger verwenden bzw. in andere Funktionalitäten einbinden.
Und noch einen Vorteil möchte ich nicht mehr missen. Man kann mal eben temporär mit einem Mausklick einen State in der db loggen um die unkompliziert zu untersuchen.
Nach dem die Batterie-Anzeige diverser zigbee Autoren mehrfach geändert wurden, logge ich die jetzt einfach mit und mach meine Auswertung direkt aus der db. Das ist für den Ladezustand viel genauer und man weis, das man von der Absolutwertanzeige zu halten hat, wenn man sieht, wie die Schwankungen sind.
-
Auch wenn wir ein wenig vom Thema abscheifen. Ich logge Daten direkt auf meine NAS in eine sql Datenbank. Gelesen von dort habe ich noch keine Daten. Die Pflege und auch die einmalige Einrichtung sollte man bei seiner Entscheidung mit berücksichtigen. Die von mir benutzte sql-Datenbank ist echt nicht ohne, die hat mich schon etliche Stunden an Zeit gekostet.
-
Hi, nur zur Info. Ich bin gerade dabei einen Adapter für ETA (ETA Touch mit aktivierter XML REST API) zu schreiben. Sobald eine erste funktionsfähige Version verfügbar ist werde ich den Link im Forum für Adapter posten…
-
Auch wenn das ganze Thema schon länger her ist - ich muss es noch einmal aufgreifen da ich zwar mittlerweile die Basics verstanden habe aber die Details noch nicht so gut klappen.
- Ich rufe in Node-Red über die Funktion http request als msg.payload einen String ab
<?xml version="1.0" encoding="utf-8"?> <eta version="1.0" xmlns="http://www.eta.co.at/rest/v1"> <value uri="//user/var/120/10601/0/0/13434" strValue="72" unit="°C" decPlaces="0" scaleFactor="10" advTextOffset="0">724</value> </eta>
- Diesen lasse ich durch den XML-Node laufen und konnte dadurch in der Debug-Ausgabe den Pfad evaluieren in welchem der Wert steht
payload.eta.value[0].$.strValue
- In der Debug Ausgabe erhalte ich dann mit dieser Payload den richtigen Wert für die Datenbank.
Leider bekomme ich es nicht hin diesen dann anstatt im Debug in iobroker zu schieben da ich ich im xml Node nicht msg.payload.eta.value[0].$.strValue nutzen kann.
Stehe ich hier irgendwo komplett auf dem Schlauch?
-
@catnipper Hi, das war mir bewusst - ich tracke aber heute schon seit gut 1 1/2 Jahrendie Daten per Parser und würde das aber gerne ändern da ich das Modul nicht mehr nutzen möchte.
Sobald das von dir fertig ist werde ich mir es gerne anschauen.
-
@andreasploetz Ich nehme dafür eine functions node und übergebe das an eine ioBroker out node als JSON:
msg = msg.payload.eta.value[0].$ var payload = "["+JSON.stringify(msg)+"]"; node.send({payload});
oder "normal" (ungetestet):
var payload = msg.payload.eta.value[0].$.strValue node.send(payload);