Dies ist das dritte Kapitel meiner Reihe über die Nutzung der Viessmann API mit Node-Red. Einen Einstieg bekommst du am ehesten, indem du mit dem Kapitel 1 – Die Viessmann API und Node-Red Überblick anfängst.
Inhalt
Autorisierung des Requests
Alle für die Autorisierung eines beliebigen Requests nötigen Informationen befinden sich in meinem "Universal Header Node", einem Funktionsnode, der den http Request Node entsprechend für die Abfrage der API bestückt. Der Funktionsnode sieht wie folgt aus und muss nicht individuell angepasst werden.
1 2 3 4 5 6 7 8 |
var atoken = flow.get('accessToken') msg.headers = { Authorization: "Bearer "+ atoken } msg.installationID = flow.get('installationID'); msg.gatewaySerial = flow.get('gatewaySerial'); msg.deviceId = flow.get('deviceID'); return msg; |
Das alles setzt voraus, dass die entsprechenden Flow Variablen wie im vorigen Kapitel gesetzt wurden.
In diesem Beispiel sind alle Viessmann Komponenten auf einem Node-Red Tab versammelt; daher werden weitgehend Flow Variable verwendet. Für den Fall, dass die Logik auf mehrere Flows verteilt ist, sind ensprechend Global Variablen zu verwenden.
Feature Überblick
Die Feature Abfrage liefert dir auf einen Schlag alle Parameter, welche deine Anlage bei dem von dir gebuchten Paket zur Verfügung stellt. Die übermittelte Liste (ein großes JSON Objekt) ist für jede Installation unterschiedlich. Sie ist hilfreich, um sich die Parameter herauszusuchen, die einen interessieren. Die Datenpunkte sind im Developer Bereich von Viessmann erklärt.
Die Abfrage erfolgt wie folgt:
Der http Request sieht so aus:
Zur besseren Lesbarkeit noch die URL Zeile als JS Code:
1 |
https://api.viessmann.com/iot/v1/features/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices/{{deviceId}}/features/ |
Auch diese Zeile muss nicht angepasst werden. Die im Universal Heade Node davor gesetzten Werte stecken in den doppelten geschweiften Klammern (double moustaches).
Seit Februar 2023 gibt es eine etwas andere API Syntax bei der Feature Abfrage, bzw. einen neuen Endpunkt "features", der den bisherigen Endunkt "equipment" ersetzt.
https://api.viessmann.com/iot/v1/features/installations... Die Anleitung hier ist auf die neuen Verhältnisse angepasst.
Nach dem Triggern erscheint – wenn alles funktioniert wie gewünscht – im Debug Node ein Objekt, das wir durch Anklicken der kleinen Dreiecke analysieren können. Unsere Features stecken in der Payload, bei mir sind das immerhin 110 verschiedene Parameter.
Das Debug Fenster erreicht man über das Anklicken des Käfersymbols oben rechts.
Zum Ansehen eines JSON Objekts gibt es mehrere Möglichkeiten. Entweder einen Online JSON Viewer, oder mit Firefox indem man das abgespeicherte JSON File lädt oder mit Notepad++ und einem JSON Viewer Plugin und sicher noch eine Menge anderer Möglichkeiten. Einfach den "Werte kopieren" Button oben rechts im Debugfenster anklicken und dann in das gewünschte Dokument pasten.
Der Vollständigkeit halber noch der JSON Flow:
1 |
[{"id":"c7bf0b120ed79afe","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"52cc82fc16871334","type":"inject","z":"c7bf0b120ed79afe","name":"Trigger","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"2","topic":"","payload":"","payloadType":"date","x":210,"y":80,"wires":[["67486be1a7671f13"]]},{"id":"57b1621ab4d7d311","type":"http request","z":"c7bf0b120ed79afe","name":"Read Events","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v2/events-history/installations/{{installationID}}/events?gatewaySerial={{gatewaySerial}}","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":570,"y":80,"wires":[["cd6d356cea0a5307"]]},{"id":"cd6d356cea0a5307","type":"debug","z":"c7bf0b120ed79afe","name":"Feature Array","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":780,"y":80,"wires":[]},{"id":"67486be1a7671f13","type":"function","z":"c7bf0b120ed79afe","name":"Header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {}\nmsg.headers = {\n Authorization: \"Bearer \" + atoken\n}\nmsg.installationID = flow.get('installationID');\nmsg.gatewaySerial = flow.get('gatewaySerial');\n//msg.deviceId = flow.get('deviceID');\n//msg.headers['Content-Type'] = 'application/json';\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":80,"wires":[["57b1621ab4d7d311"]]}] |
Nur wenige Datenpunkte auslesen
Wie du wahrscheinlich weißt, gibt es eine Begrenzung von 1440 Zugriffen innerhalb 24 Stunden. Wenn dich nur wenige Datenpunkte interessieren und diese auch nicht all zu oft abfragen willst, dann ist der direkte Featurezugriff über die URL am einfachsten.
Probieren wir das einfach mit dem Wert "gemeinsame Vorlauftemperatur" – im JSON steht das unter heating.boiler.sensors.temperature.commonSupply.
Die URL Zeile im Read Feature http Request Node sieht wie folgt aus:
1 |
https://api.viessmann-platform.io/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices/{{deviceId}}/features/heating.boiler.sensors.temperature.commonSupply |
Die API liefert uns ein kleines JSON Objekt, aus dem wir den Datenpunkt ganz leicht extrahieren können. Der Extract Value Node sieht so aus:
1 2 3 |
msg.payload=msg.payload.data.properties.value.value; msg.topic="Common Supply"; return msg; |
msg.topic ist nicht unbedingt erforderlich, hilft aber, wenn man ein Chart mit mehreren Kurven baut.
Hier der JSON Flow dazu:
1 |
[{"id":"170a509bdabfdf1e","type":"function","z":"31c57f8640528976","name":"Gem. Vorlauftemperatur","func":"featureArray=msg.payload.data;\nidx = featureArray.findIndex( (element) => element.feature === 'heating.boiler.sensors.temperature.commonSupply');\nmsg.payload=msg.payload.data[idx].properties.value.value;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1290,"y":1400,"wires":[["bafae4f6f43e5a4b"]]},{"id":"8a8b8fda0e742c53","type":"inject","z":"31c57f8640528976","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"90","crontab":"","once":true,"onceDelay":"5","topic":"","payload":"true","payloadType":"bool","x":130,"y":1840,"wires":[["8e3997f78f283787"]]},{"id":"8e3997f78f283787","type":"function","z":"31c57f8640528976","name":"Universal Header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.installationID = flow.get('installationID');\nmsg.gatewaySerial = flow.get('gatewaySerial');\nmsg.deviceId = flow.get('deviceID');\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":1840,"wires":[["70ab63bf7d6ee874"]]},{"id":"70ab63bf7d6ee874","type":"http request","z":"31c57f8640528976","name":"Features auslesen","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/features/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices/{{deviceId}}/features/","tls":"","persist":false,"proxy":"","authType":"","x":530,"y":1840,"wires":[["156b84e328c10f60","03d135c35ea4a3d9","354cb6e083ea9537","2fd1dc003983448d","8fc25e53f7393458","868b098e8326c769","d4cab413a741b33d","184ccbdfa9647990","f17524410cd1d0fc","aa2b6db4c5916710","261b31a892603efb","04a27b99c129548f"]]},{"id":"156b84e328c10f60","type":"debug","z":"31c57f8640528976","name":"Features","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":680,"y":1320,"wires":[]}] |
Würdest du diesen Flow jede Minute aufrufen, wären alle 1440 Zugriffe/Tag verbraucht. In so fern ist das Abfragen weniger einzelner Datenpunkte nur bei geringer Abfragefrequenz sinnvoll.
Übrigens: Auch wenn alle Zugriffe verbraucht sind, kannst du immer noch mit der App auf deine Heizung zugreifen.
Mehr Datenpunkte öfter auslesen
Da der große "Feature Request" von weiter oben ja alle Datenpunkte inklusive deren Werte auf einmal ausliest, können wir das Ergebnis dieses Requests relativ leicht in einzelne Werte aufdröseln.
Man könnte sich hier einfach an der Position des gesuchten Datenpunkts im Array orientieren. Nehmen wir an, die Außentemperatur ist der 65. Wert in der Feature Overview Tabelle, dann können wir diesen Wert per Javacript ganz einfach extrahieren:
1 |
msg.payload=msg.payload.data[65].properties.value.value; |
Das klingt zwar ganz einfach, hat aber Nachteile: Viessmann wird die Reihenfolge beliebig ändern, wenn neue Features hinzukommen oder wegfallen. Der Datenpunkt ist also nicht immer an 65. Stelle. Auch wird sich die Position des Datenpunkts von Installation zu Installation unterscheiden.
Um die uns interessierenden Datenpunkte zu extrahieren, müssen wir das JSON Feature Objekt nach dem richtigen Namen durchforsten d.h. parsen.
Das geschieht über die Javascript findindex Methode:
1 2 3 4 |
var featureArray=msg.payload.data; var idx = featureArray.findIndex( (element) => element.feature === 'heating.sensors.temperature.outside'); msg.payload=msg.payload.data[idx].properties.value.value; return msg; |
Auf diese Weise lassen sich quasi beliebig viele Datenpunkte auswerten, ohne das Abrufkontingent zu überlasten. Bei meiner Implementation frage ich alle 90 Sekunden nach den Werten. So habe ich immer noch genug Reserve für andere Abfragen oder Einstellungen.
Visualisieren
Will man sich lediglich den aktuellen Wert in Textform anzeigen lassen, dann reicht der Dashboard Text Node aus.
Eine hübschere Darstellung bekommen wir, wenn wir den Dashboard Gauge Node. verwenden. Für die Darstellung von Prozentwerten ist das Donut Gauge sehr nett anzusehen. Füllstände mit dem Level Gauge.
Schaltzustände z.B. Brenner an/aus lassen sich ganz einfach durch umfunktionierte Dashboard Switch Nodes darstellen.Hier lässt sich auch das Standard Icon gegen eine Reihe anderer, auch animierter Symbole austauschen. Obiges Flammensymbol lässt sich einstellen, indem der Switch Mode wie folgt konfiguriert wird:
Mehr über die Verwendung von Font Awesome und Material Design Icons im Kapitel "Node-Red Dashboard Tips & Tricks".
Liniendiagramme
Werte im Zeitverlauf kann man sehr schön mit mit dem Dashboard Chart Node darstellen.
Hierzu einfach den Output Node mit dem Chart Node verbinden. Bei Gruppe einen entsprechenden Überbegriff eintragen, ggf. dahinter (Bleistiftsymbol) noch das passende Tab auswählen. Hier einfach mal ein bisschen spielen…
Wenn man bei Y-Achse nichts einträgt, passt Node-Red die Achse automatisch an.
Will man mehrere Linien in einem Diagram darstellen, dann sollte jeder Output unbedingt sein eigenes Topic haben. Dieses Topic stellt dann auch die Legende im Chart dar.
Die Farben kann man im Chart Node auswählen, wobei der zuerst ankommende Wert immer die Farbe oben links bekommt, der zweite die rechts daneben, der vierte den linken Farbwert der zweiten Zeile und so fort. Ich habe bislang keine Möglichkeit gefunden, die Farbe direkt festzulegen.
Ich behelfe mir hierbei mit dem Delay Node, der sicherstellt, dass bei nahezu gleichzeitig eintreffenden Werten, der erste direkt durchgelassen, der zweite etwas, der dritte mehr und der vierte Wert lange verzögert wird.
Die Dauer der Aufzeichnung kann ebenfalls im Charte Node Eigenschaftsfenster unter X-Achse festgelegt werden. Ältere Werte fallen dann hinten runter und werden nicht gespeichert. Ebenso vergisst Node-Red alle Werte, wenn es neu gestartet wird.
Will man das verhindern, müssen die Werte phyikalisch weggeschrieben werden. Am besten in eine Datenbank, wobei sich hier die InfluxDB anbietet, welche für genau diesen Zweck geschaffen wurde. Hierfür gibt es bei Node-Red bereits entsprechende Schreibe- und Lesenodes. Leider ist das Auslesen und Darstellen in Node-Red etwas kompiziert, aber das erkläre ich in im Kapitel über die Influx DB
Ich war heute mal nach etwas längerer Zeit auf dieser Website und musste erfreut feststellen dass es einige interessante neue Themen gibt. Gerade diese Solarprojekte sind immer sehr spannend. Immer sehr geil- weiter so!
Aber was mich eigentlich hergetrieben hat: Seit gestern scheint dieses Auslesen von Viessmann "Nur wenige Datenpunkte auslesen" nicht mehr zu funktionieren.
Ich bekomme da immer ein Fehler unter dem Read Feature Node : ERR_TLS_CERT_ALTNAME_INVALID
Das sagt mir nichts. Was läuft da falsch?
Hallo,
tut mir leid, dass ich erst jetzt antworte. Mein Spamfilter hat deinen Kommentar als Spam ausgesondert – wundert mich angesichts des ersten Satzes auch nicht. So in der Art fangen viele Spam Kommentare an…
Zu deinem Problem. Googeln hilft, bzw. Duckduckgo. Das Problem liegt wohl eher auf der Viessmann Seite. Eine gute Erklärung (in englisch) habe ich hier gefunden.
Notfalls an Michael Hanna von Viessmann wenden: developer@viessmann.de
Viel Spaß noch
Chris
Guten Tag Chris,
ich habe einen Teil deiner nodes einmal in mein node red eingebaut. Das Lesen des Data-Arrays und extrahieren von gewünschten Features funktioniert bis auf das auslesen der Außentemperatur. Adressiere ich das Array im function node direkt ist alles fein. Adressiere ich es über die function node Definition:
var featureArray=msg.payload.data;
var idx = featureArray.findIndex( (element) => element.feature === 'heating.sensors.temperature.outside');
msg.payload=msg.payload.data[idx].properties.value.value;
return msg;
bekomme ich nicht den Wert über paylod zurück, sondern das gesamte array. Ich denke, dass er es nicht gefunden hat. Die Data Definitionen um die es geht lauten:
{
"feature": "heating.sensors.temperature.outside",
"gatewayId": "7637415054512237",
"deviceId": "0",
"timestamp": "2024-04-08T09:23:41.460Z",
"isEnabled": true,
"isReady": true,
"apiVersion": 1,
"uri": "https://api.viessmann.com/iot/v1/features/installations/2367104/gateways/7637415054512237/devices/0/features/heating.sensors.temperature.outside",
"properties": {
"value": {
"type": "number",
"value": 17.6,
"unit": "celsius"
},
"status": {
"type": "string",
"value": "connected"
}
},
"commands": {
}
},
Ich würde mich auf ein feedback von dir freuen.
Grüße
Joachim
Hallo,
ich habe auch erst gestutzt, da ich keinen Unterschied feststellen konnte. Erst als ich deinen "findindex" Code verwendet habe bin ich drauf gekommen, was es sein könnte. Kann es sein, dass dein Editor oder WordPress die Single Quotes in smarte Anführungszeichen umwandelt? Leider macht WordPress, auf dem mein Blog basiert das auch.
Inzwischen habe ich mein WordPress so angepasst, so dass es keine smart Quotes mehr einbaut. Dadurch sehe ich auch, dass du wahrscheinlich alles richtig gemacht hast, d.h. dein einkopierter Code bzw. das Viessmann Feature JSON sind jetzt korrekt dargestellt. Ich muss noch ein bisschen hirnen, um herauszufinden, warum genau dieser eine Featureeintrag sich nicht über die findIndex Methode entschlüsseln lässt.
Schicke mir bitte mal das ganze (falsche) Antwortarray. Kann es evtl. sein, dass du den Debug Node nicht auf msg.payload als Antwort sondern auf das gesamte message Objekt eingestellt hast? –>>Ausgabe: kompletten Nachrichten Objekt <-- Der Gramatikfehler ist nicht von mir 🙂 Bzgl. Editor: Ich verwende Notepad++, das kostet nichts und ist ausgesprochen leistungsfähig. VG Chris
Hallo Chris,
habe das Problem gefunden. Irgend etwas war in dem function node nicht korrekt. Änderungen, die ich in dem function node gemacht hatte wurden ebenfalls nicht honoriert. Habe es gelöscht und neu angelegt. Danach war alles ok.
Gruß
Joachim
Sehr gut! Manchmal scheint es so, als ob Node-Red einen Schluckauf hätte. Dann die merkwürdig funktionierenden Teile löschen und neu aufzusetzen hilft. Beim Entwickeln immer wieder speichern, dann muss man nicht ganz bei 0 anfangen.
Viel Spaß noch
Chris
hallo,
vielleicht bin ich hier falsch. Ich betreibe seit wenigen Monaten eine Hybridheizung von Viessmann mit WP u Gastherme und bin es einfach leid, dass ich die massenhaft aus der Anlage vorliegenden Daten (auf Viessmann-Servern) nicht als CSV laden und in Excel weiter verarbeiten kann.
Gibt es eine Lösung auch für Programier-Laien?
Gruß
Gerd
Hallo,
Bis Sie erst einmal auf die Daten zugreifen können, braucht es schon einiges an Progammier- oder Konfigurationsaufwand.
Mit Node-Red ist das zwar „relativ“ einfach, erfordert aber den Willen, sich mit der Materie auseinander zu setzen.
Vielleicht finden Sie ja jemanden, der Ihnen das einrichtet.
Ggf. Gibt es auch plug&play Lösungen auf Basis Home Assistant o.ä.
Hier in meinem Blog wende ich mich an wohlmeinende Amateure mit etwas Basiswissen und liefere eher „Hilfe zur Selbsthilfe“.
Eine gute Zeit noch wünsche ich Ihnen.
Chris
Hallo Chris
Funktioniert soweit alles perfekt. Danke für deine ausführliche Anleitung und deine Arbeit 🙂
Bei mir gibt es Features, die zwar vorhanden sind, aber von findIndex nicht gefunden werden. Und zwar alle, die eine Nummer im Feature haben (z.B. heating.circuits.0.circulation.pump).
Muss ich hier etwas besonders beachten?
Da ist eigentlich nichts Besonderes zu beachten. FindIndex funktioniert auch mit Zahlen.
Hier ein Beispiel
var featureArray = msg.payload.data;
var idx = featureArray.findIndex((element) => element.feature === 'heating.circuits.2.operating.programs.active');
msg.payload = msg.payload.data[idx].properties.value.value;
return msg;
Im Beispiel wird der Status vom 2. Heizkreis abgefragt.
VG
Chris
Hallo,
gibt es eine Möglichkeit boolean Werte umzuwandeln und im Diagramm darstellen zu können. So würde mich interessieren, wenn zB die Warmwasseranforderung vorliegt. Das hätte ich dann gerne in dem Diagramm mit den Warmwasserspeicher Temperaturen dargestellt.
Danke
Moritz
Klar geht das. Mit einem Change Node den True/false Wert in 0/1 umwandeln und dann mit einem Chart Node (Line Chart) verbinden.
Hi Christoph,
ich weiß ehrlich gesagt nicht, was der Fehler war. Ich habe den Function Node gelöscht und einfach noch mal neu angelegt und dann ging es. Vielleicht war ein Punkt oder eine Klammer zu viel oder zu wenig rein-kopiert.
Allerbesten Danken für deine Gute Beschreibung, auch deine Kommentare in der Viessmann-Community. Ich habe damit sehr viel gute Lösungen für meine Vitodens200 umsetzen können.
Besten Gruß
Christoph
Prima! Freut mich außerordentlich. Falls du andere Fehler feststellen solltest, freue ich mich über jeden Hinweis.
Chris
Leider funktioniert das extrahieren der Datenpunkte nicht.
Woran kann das wohl liegen?
"TypeError: featureArray.findIndex is not a function"
Die Features werden korrekt angeziegt und sind auslesbar.
Hallo,
verstehe ich nicht, warum das einen Fehler wirft.
Wie sieht der gesamte Function Node bei dir aus?
Die kritische Zeile ist diese hier (für Außentemperatur). Alle Klammern geschlossen?
var idx = featureArray.findIndex( (element) => element.feature === 'heating.sensors.temperature.outside');
Viele Grüße von Christoph zu Christoph