Der Zugang zur Viessmann API ist nicht ganz trivial. Die Beschreibung auf den Viessmann Seiten lässt auch zu wünschen übrig. Trotzdem schadet es nicht, sich das alles dort einmal durchzulesen. Ich beschreibe hier den Ablauf analog dazu aber eben auf Node-Red angepasst. Ist der Flow erst einmal fertiggestellt, ist alles Weitere ein Klacks.
Mit jeder Erkenntnis wird dieser Beitrag aktualisiert und dadurch leider auch länger und etwas unübersichtlich. Wichtige Änderungen in meiner Anleitung sind entsprechend hervorgehoben und zusätzlich haben meine Beiträge jetzt auch ein Inhaltsverzeichnis.
Inhalt
Schritt für Schritt
Vorbemerkung: diese Anleitung geht davon aus, dass Node-Red native auf einem Linux Rechner, das heißt einem Raspberry Pi installiert wird also ohne ein Hausautomatisierungsframework darum herum. Für Spezialrechner auf Linux Basis (z.B. CCU3) oder Windows PCs, Synology Disk Stations etc. gelten unter Umständen andere Voraussetzungen – zum Beispiel spezielle Client Firewall Regeln und Port-Einstellungen, die hier nicht behandelt werden. Dasselbe gilt für ein embedded Node-Red im Homeassistant oder IO Broker. Auch Docker macht immer wieder Probleme. Ich kann hier auch nur eingeschränkten Support leisten. Schaut euch auch bitte die untenstehenden "Hinweise zur Fehlersuche" an, wo ich Lösungsmöglichkeiten dank der Hinweise von einigen Lesern zusammengetragen habe.
A propos Firewall: Der Router braucht keine Portfreischaltung im Firewall. Hütet euch ferner davor, den Node-Red Port 1880 im Router freizuschalten. Damit hättet ihr ein riesiges Sicherheitsproblem.
Voraussetzungen – Vorarbeiten
Grundvoraussetzung ist, die ViCare App zum Laufen zu bringen. Mit der App wird ein Viessmann Account angelegt und die Anlage registriert. Damit kennen die Viessmann-Server deine Installation. Es ist dann auch sichergestellt, dass die internetseitige Verbindung funktioniert. Darauf achten, dass das Vitoconnect Kästchen – sofern verwendet – eine ausreichende Empfangsstärke hat. 1 Balken ist definitiv zu wenig. Siehe hier (Abschnitt Anleitung).
Anschließend, bzw. nach Erhalt und Quittierung des Bestätigungsmails solltest du dich bei developer.viessmann.com einloggen. Dabei sind dieselben Zugangsdaten zu verwenden, die bei der Registrierung der ViCare App verwendet wurden. Das Ganze ist weitestgehend selbsterklärend.
Nach dem Login hat man Zugriff auf die Dokumentation und das Viessmann Developer Dahboard. Dort muss zuerst einmal die
Client ID
angelegt werden. Mit Klick auf My Dashboard wird dieses angezeigt. Auf der Kachel "Your Clients" klicken wir das Stiftsymbol an. Es kann nur ein Client angelegt werden. Normalerweise braucht du nur eine URI. Zwei URIs sind ggf. vonnöten, wenn Node-Red zusammen mit dem Viessmann API Adapter auf einem IO Broker laufen soll.
Bei Name trägst du denselben Namen ein, den du deiner Anlage in der App verpasst hast – ich bin mir aber nicht sicher, ob das wirklich so sein muss. Die Client ID wird automatisch erzeugt, wenn du am Ende "Save Client" anklickst.
Zuvor muss aber noch das Google reCAPTCHA ausgeschaltet und eine Redirect URI eingegeben werden.
Die Redirect URI ist die Aufrufadresse (Callback Adresse) deiner Applikation, an die bei Aufruf ein AuthCode übermittelt wird. In der generischen Viessmann Anleitung steht http://localhost:4200 . Wir hingegen verwenden http://localhost:1880/authcode – das ist die Adresse bzw. der Port, auf dem Node-Red auf Input lauscht. Das /authcode ist ein beliebiger Pfad, der unbedingt erforderlich ist, sonst ruft Viessmann den Node-Red Editor anstatt des Flows auf. Merke dir diesen Pfad, du brauchst ihn in den nächsten Schritten.
Die Client ID ist statisch und bleibt so lange gültig, bis du sie im Dashboard löschst.
Merke: Die ClientID wird im Folgenden insgesamt dreimal in einen http Request Node eingetragen. Das wird gerne übersehen, wenn man die ClientID später einmal geändert hat.
Authcode abrufen
Das Erzeugen der Client ID war der letzte manuelle Schritt und muss auch nur einmalig durchgeführt werden. Der Rest ist künftig automatisiert:
Wir ziehen uns nun in Node-Red drei Nodes auf das Editiertableau und "verkabeln" diese.
Timestamp zum Triggern, http request zum Abfragen und Debug für das Ergebnis.
ACHTUNG: Der Debug Node (hier debug 5) wird erst dann ein sinnvolles Ergebnis liefern, wenn ihr auch den weiter unten stehenden Schritt mit dem http in Node gegangen seid. Erst der http in Node erzeugt das virtuelle Verzeichnis, in das der Viessmann Server hineinschreibt.
In die URL Zeile des http request kommt folgender Inhalt:
1 |
https://iam.viessmann.com/idp/v3/authorize?client_id=DeineClientIDkommtHierhin&redirect_uri=http://localhost:1880/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access |
Bisherige Nutzer der API aufgepasst: seit Februar 2023 gibt es eine neue Version des API Authentifizierungsprozesses: Anstatt https://iam.viessmann.com/idp/v2/authorize… heißt es jetzt https://iam.viessmann.com/idp/v3/authorize… sonst ändert sich nichts. Der Vorteil liegt in konkreteren Fehlermeldungen beim Login. Siehe Viessmanm API Changelog Abschnitt Februar 2023. Übernimmt man die Änderung, sollte weiter unten d.h. bei https://iam.viessmann.com/idp/v3/token… ebenfalls v3 anstatt v2 verwendet werden.
Deine Client ID an der entsprechenden Stelle eintragen, den gesamten anderen Kram könnt ihr so stehen lassen. In der Viessmann Anleitung ist etwas von Oauth die Rede für Code Challenge und -Response. Ich habe nie verstanden, wie das funktioniert. Es reicht, hier dieselbe Challenge/Response wie in der Viessmann Dokumentation zu nehmen.
Die Redirect URI 1:1 aus dem ClientID Prozess auf den Viessmann Seiten übernehmen.
scope= IoT User (bzw. scope=IoT%20User ) ist vorgegeben, offline_access veranlasst die API noch ein Refresh Token mitzugeben, was die spätere Nutzung deutlich vereinfacht.
Den Rest des http requests wie folgt ausfüllen:
Methode ist GET, Nutzdaten ignorieren, Basis Authentifizierung verwenden – hier die Viessmann Account Daten (Username/eMail und Passwort aus der App – nicht den Namen aus dem Viessmann „Edit Client“ Fenster) eintragen – und schließlich bei Rückgabe eine UTF-8 Zeichenfolge auswählen.
So lange du die Client ID nicht änderst, brauchst du diese Blöcke nicht mehr anfassen.
Mit dem http Request Node haben wir die Anfrage losgeschickt, mit einem http In Node empfangen wir die Antwort. Im Prinzip bauen wir hier einen winzigen Webserver auf.
Der http In Node wird wie folgt konfiguriert:
Das URL Feld muss dem Pfad entsprechen, der beim Anlegen der Client ID verwendet wurde. Allerdings ohne Localhost und Portnummer.
Der Response Node wird lediglich auf Status 200 gesetzt. Der Response Node ist wichtig, um die Anfrage des Viessmann Servers korrekt abzuschließen!
Bitte beachte ferner, dass der Sende- und der Empfangsteil sind nicht miteinander verdrahtet sind. Hier zaubert das Internet.
Jetzt – erst jetzt – könnt ihr testen: Wenn alles funktioniert, sollte der Debug Node am Empfangsende den Authorization Code anzeigen wenn der Trigger auf der Sendeseite ausgelöst wurde. Der Code steckt jetzt in msg.payload.code .
Den kompletten JSON Flow findest du am Ende des Artikels.
Hinweise zur Fehlersuche
Cannot get /authcode
Wie man manchen Kommentaren entnehmen kann, kommt es gelegentlich zu Fehlern der Art "Cannot GET /authcode".
Der Fehler tritt immer dann auf, wenn der Viessmann Server unter der angegebenen Adresse nichts findet. Das kann an einer falsch konfigurierten URL liegen, einer falschen Portnummer oder daran, dass der in NR eingebaute Webserver nicht angesprochen werden kann. Hauptursache ist aber wahrscheinlich, dass der zum ersten http Request passende http in Node noch nicht eingebaut wurde. Siehe mit Achtung markierten Absatz weiter oben. Erst der http in Node, oben mit
[get] /authcode bezeichnet, erzeugt das vom Viessmann Server benötigte virtuelle Verzeichnis.
connect ECONNREFUSED
Unter bestimmten Umständen, z.B. wegen einer nicht ganz standardmäßgen Konfiguration auf eurer Seite, durchläuft Node Red eine Identitätskrise und weiß auf einmal nicht mehr, dass es selbst durch localhost aufgerufen wird. Demzufolge wird der Viessmann-Callback abgelehnt und es gibt eine Fehlermeldung der Art:
RequestError: connect ECONNREFUSED ::1:1880
Test: probiert mal Folgendes:
1 |
[{"id":"e008437fd10a7172","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"19375c41d180b1f7","type":"http in","z":"e008437fd10a7172","name":"\"http in\" Node","url":"test","method":"get","upload":false,"swaggerDoc":"","x":990,"y":160,"wires":[["62d56fd0194be715"]]},{"id":"cb7ae7e2d1498dd5","type":"http response","z":"e008437fd10a7172","name":"","statusCode":"200","headers":{"content-type":"text/plain"},"x":1460,"y":160,"wires":[]},{"id":"62d56fd0194be715","type":"template","z":"e008437fd10a7172","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"This is the payload!","output":"str","x":1240,"y":160,"wires":[["cb7ae7e2d1498dd5"]]},{"id":"59871b13fa1668f2","type":"http request","z":"e008437fd10a7172","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"localhost:1880/test/?helloword","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1190,"y":80,"wires":[["e961ab6d8dca2a1f"]]},{"id":"53be7c837e4a97d8","type":"inject","z":"e008437fd10a7172","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"trigger","payloadType":"str","x":1010,"y":80,"wires":[["59871b13fa1668f2"]]},{"id":"e961ab6d8dca2a1f","type":"debug","z":"e008437fd10a7172","name":"debug 145","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1410,"y":80,"wires":[]}] |
Mit dem Trigger wird ein http request angestupst, der an die Adresse localhost:1880/test eine belanglose Nachricht schickt. Der http in Node empfängt diese – vorausgesetzt localhost ist nicht blockiert – und gibt an den http request eine Nachricht zurück, die ihr im Debugfenster lesen könnt. Funktioniert das nicht, erscheint eine Fehlermeldung "Cannot GET /test".
Um zu sehen, ob Node-Red überhaupt antwortet, könnt ihr den gerade erzeugten Microwebserver über einen Browser auf einem anderen Gerät im lokalen Netz aufrufen: http://IPdesNodeRedServers:1880/test . Wenn das nicht funktioniert, hat NR ein generelles Problem oder ihr habt euch irgendwo verschrieben.
Dem ECONNREFUSED Problem kann man oft abhelfen, indem man durchgehend 127.0.0.1 anstatt localhost verwendet. Logisch betrachtet ist beides dasselbe aber manchmal hilft es, anstatt des lokalen Namens, die IP Adresse zu verwenden .
Dafür die Viessmann Client ID löschen und dort die redirect URI neu mit
http://127.0.0.1:1880/authcode
anlegen. Dann noch die neu generierte Client ID und die neue URI in den obersten Request Node übertragen.
Dank an Günter fürs geduldige Ausprobieren und die Rückmeldung!
Home Assistant:
Bei einem "embedded Node Red" ist die Adressierung des NR internen Servers anders.
Als virtuelles NR Verzeichnis für den Autorisierungsvorgang haben wir weiter oben /authcode verwendet. Der Verzeichname ist beim native NR wahlfrei. Bei HA allerdings nicht! Das Verzeichnis muss /endpoint/... lauten. Also z.B. /endpoint/authcode . Und zwar überall:
-
- Auf der Viessmann Seite beim Anlegen der Redirect Client URI,
- beim ersten http Request – Generieren des Authorization Codes
- beim http in "[get]/authcode/
- und bei den beiden "set payload & headers" Nodes zu erstmaligen Erzeugen des Access tokens und zum Refresh desselben.
Herzlichen Dank an Alex P. fürs Aufzeigen der Lösung!
IO Broker:
Ich habe mir mal die Mühe gemacht, und den IO Broker nebst integriertem Node-Red Adapter auf einem Raspi installiert. Abgesehen davon, dass ich den IO Broker für ein hoffnungslos überladenes Klickibunti halte, hat alles astrein 1:1 funktioniert. Bei der Instanziierung darauf achen, dass die NR Portnummer 1880 gesetzt wird. Läuft auch noch der Viessmann Adapter auf dem Broker, müssen (wahrscheinlich) zwei URIs bei der Edit Client Seite bei Viessmann eingetragen werden. Ist also der Viessmann Adapter und der Node-Red Adapter gleichzeitig installiert, muss dann noch gemäß Vorschrift im Broker eine 2. URI (http://localhost:4200) angelegt werden (Angabe ohne Gewähr).
Docker:
Habt ihr NR in einem Docker Container laufen, dann wird das so ohne weiteres nicht funktionieren. Docker sperrt – so habe ich es verstanden – den Zugriff auf localhost. Das müsste erst einmal freigeschaltet werden. Wie? Keine Ahnung! Ich habe für mich keinen Vorteil von Docker erkannt und nutze es deshalb nicht. Zum Basteln habe ich einen isolierten Raspberry Pi und laufe so wenig Gefahr, etwas zu zuerstören.
Noch eine Möglichkeit (mangels Docker Installation blind geraten): Wenn Docker localhost sperrt, dann klappt es vielleicht mit 127.0.0.1 anstatt localhost. Siehe connect ECONNREFUSED weiter oben. Mir bitte unbedingt Bescheid geben, was daraus geworden ist.
Oder dieses Link hier: Docker Container unter Hostname nicht erreichbar
Zitat:
"Haben Docker Container nicht eine eigene "virtuelle" Netzwerkinfrastruktur, die man erst nach außen routen muss?
Also sprich sowas wie (Beispiel nginx Server):
docker run --name mynginx -d -p 8080:80 nginx Das macht nginx nach außen (localhost) auf Port 8080 erreichbar."
Zitat Ende.
Aktuelle Node Red Version
Noch was: seht zu, dass ihr die aktuellste Version von Node Red auf eurer Kiste laufen habt. Stand November 2023 ist das Version 3.1.0
Feedback, bitte:
Ich gebe mir alle Mühe, meinen Lesern bei der Fehlersuche weiterzuhelfen.
Daher eine Bitte: gebt genau an, welcher Node den Fehler ausgibt, ferner die komplett ausgeklappte Fehlermeldung im Debugfenster rechts. Idealerweise auch euren – anonymisierten – Flow per Mail schicken. (Adresse steht im Impressum). Gut zu wissen wäre ebenfalls, ob ihr Node-Red direkt auf eurem Rechner betreibt oder gekapselt in Docker, IO Broker, Home Assistant etc.
Und noch eine Bitte: Immer wieder zermartere ich mein Hirn und gebe ich Hinweise, wie ein Problem zu lösen sein könnte. Vom Adressaten bekomme ich meist… nichts! Kein Feedback, Funkstille. Damit stochere ich mit 'ner Stange im Nebel, da ich nicht weiß, ob mein Tipp geholfen hat. Also, bitte gebt mir Feedback und ich gebe mein Bestes, euch weiterzuhelfen. Auch wenn ihr eine Lösung für ein Problem gefunden habt, wäre ich für eine Mitteilung dankbar.
Access Token initial erzeugen
Wenn ihr jetzt den Authcode erzeugen konntet, geht's weiter:
Die drei Nodes oben links kennen bzw. haben wir schon.
Kommen wir zum Funktionsnode set payload & headers, der den darauf folgenden http Request Node mit Daten auflädt. Der im vorherigen Schritt gewonnene Code wird per Stringvariable hinten angehängt.
Auch hier kommt wieder die Client ID an die entsprechende Stelle des Aufrufstrings – wird gerne vergessen, wenn man mal die ClientID neu erzeugt hat.
1 2 3 4 5 |
msg.payload = 'grant_type=authorization_code&client_id=DeineclientIDKommtHierhin&redirect_uri=http://localhost:1880/authcode&code_verifier=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&code=' + msg.payload.code; msg.headers = {}; msg.headers['Content-Type'] = 'application/x-www-form-urlencoded'; return msg; |
Anders als der oben verwendete http Request ist der hier verwendete http Request Node ein POST Request, d.h. es werden Daten im http header anstatt in der URL transportiert. Er wird wie folgt konfiguriert. Darauf achten, dass die Rückgabe als "Ein parsed JSON Objekt" erfolgen soll.
Auch hier sollte wieder v3 anstatt v2 verwendet werden.
Wenn alles funktioniert, dann enthält das zurück geschickte JSON Objekt sowohl das Access Token als auch das Refresh Token. Die Token stecken in msg.payload.access_token bzw. msg.payload.refresh_token.
Mit dem Access Token könnten wir nun 3600 Sekunden oder eine Stunde lang arbeiten bevor es verfällt.
Sinnvollerweise packen wir die beiden Token in Flow Variable um sie weiter zu verwenden. Hast du die Viessmann Logik auf mehreren Node-Red Blätter verteilt, sollten sie in Global anstatt in Flow Variablen untergebracht werden.
Das geschieht am einfachsten mit einem Change Node:
Variable können auch innerhalb eines Function Nodes mit
flow.set("FlowVariablenname", meineVariable) gesetzt werden. Das macht vor allem innnerhalb komplexerer Funktionsblöcke Sinn.
Abgerufen werden die Flow Variablen mit einem Kommando der Art:
var meineVariable = flow.get("FlowVariablenname");
Sind wir wie oben beschrieben vorgegangen, können wir jetzt überall innerhalb des Flows (Tabellenblatt) auf die Tokens zugreifen.
Statische Parameter
Um mit der API zu arbeiten, benötigen wir noch drei statische Werte, welche am Gerät hängen und sich normalerweise nie ändern.
Wie man sie bekommt, ist in der Viessmann Doku beschrieben oder man nutzt diesen JSON Flow für Node Red:
1 |
[{"id":"8ebef3e8da13cc88","type":"http request","z":"640d4a161fb8fa28","name":"DeviceID","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/equipment/installations/{{iid}}/gateways/{{gws}}/devices/ ","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":660,"y":560,"wires":[["46022befd51c1c67"]]},{"id":"798ae186e9020315","type":"change","z":"640d4a161fb8fa28","name":"","rules":[{"t":"set","p":"deviceID","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":560,"wires":[[]]},{"id":"dc35dc89a8567d81","type":"function","z":"640d4a161fb8fa28","name":"extended auth header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.iid = flow.get('installationID');\nmsg.gws = flow.get('gatewaySerial');\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":560,"wires":[["8ebef3e8da13cc88"]]},{"id":"46022befd51c1c67","type":"function","z":"640d4a161fb8fa28","name":"locate deviceID","func":"const deviceArray=msg.payload.data;\nvar idx = deviceArray.findIndex( (element) => element.deviceType === 'heating');\nmsg.payload=msg.payload.data[idx].id;\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":560,"wires":[["6e1ddceae4be021a","798ae186e9020315"]]}] |
Es bleibt dir überlassen, wo du diesen Teil einbaust. Im Prinzip kann man die drei Parameter Installation ID, Gateway Serial und Device ID ein einziges Mal abfragen und dann als fixe Werte, also "hard coded" weiterverarbeiten. Oder – so habe ich es gemacht – jedes Mal neu abfragen, wenn die Logik nach einem Neustart des Servers bzw. alle 180 Tage (siehe unten) initialisiert und die Token wieder neu generiert werden.
Erläuterung der drei statischen Parameter:
InstallationID identifiziert eure gesamte Anlage mit allen Komponenten, Therme, Wärmepumpe, Photovoltaik etc. Normalerweise gibt es pro Haus/Wohnung nur eine InstallationID.
GatewaySerial: Hat man nur einen Viessmann Wärme-/Energieerzeuger, dann gibt es in der Regel auch nur eine einzige GatewaySerial. Hat man deren mehrere, dann hat jeder modernere Wärmeerzeuger eine eigene WiFi Komponente (oder bei Legacy Geräten ein VitoConnect Kästchen).
Sind z.B. sowohl WP als auch PV installiert, musst du, um die gesamte Anlage über die API anzusprechen, beide GatewaySerials heranziehen und die Abfragen bzw. Befehle für die Geräte dem jeweiligen Gateway zuordnen. Auch bei einer späteren Nachrüstung (z.B. mit PV) muss die Programmierung entsprechend angepasst werden.
Jedes Gateway hat wiederum mehrere Device IDs. Relevant bzw. nutzbar für unsere Anwendungsfälle ist das Device Nummer "0" – der Wärme- oder Energieerzeuger.
Nr "1" ist das Gateway selbst, hier gibt es keine Features, die abgerufen werden können.
Nr. "2" ist virtuell und bei meiner Therme etwas, das sich "HeatDemandControl" nennt und wohl die Sensorik (?) darstellt. Ebenfalls keine Features.
Device ID "3" ist auch virtuell und die Einzelraumsteuerung welche in der Vitotronic wohl auch dann angelegt ist, wenn physisch es gar keine Einzelraumsteuerung gibt.
Update Anfang 2024: Leider stimmt diese Reihenfolge nicht mehr generell. Siehe untenstehendes Kapitel.
ACHTUNG NEU 2024
Nur relevant für bereits bestehende Nutzer dieser Anleitung: Warum auch immer hat Viessmann etwas an der Position der DeviceID geändert. Die Abfrage nach der Device ID in obigem Flow bzw. die Abfrage
https://api.viessmann.com/iot/v1/equipment/installations/{{iid}}/gateways/{{gws}}/devices/ generiert eine Payload bestehend aus einem Array mit vier Elementen — msg.payload.data[0] bis data[3]. Bisher stand die Device ID in msg.payload.data[0].id, seit ca. Anfang 2024 steckt die DeviceID bei mir in msg.payload.data[1].id
Leider ist das aber nicht bei jedem so. Bei Wärmepumpen kann es zum Beispiel sein, dass die deviceID im dritten Element .data[2] steckt. Auch wenn es etwas nassforsch ist, empfehle ich, generell einfach "0" als DeviceID in euren Flows zu verwenden anstatt das regelmäßig bei Viessmann abzufragen.
Für alle Puristen, die die Device ID trotzdem gerne bei der API abfragen, hier noch der Flow, der eine hoffentlich betriebssichere Abfrage ermöglicht. Gesucht wird nach dem Element in der Payload, das bei deviceType den Wert "heating" drinstehen hat. Einfach die hier abgebildeten Nodes ersetzen. Diese Methode ist auch in obigem Flow realisiert.
Bei Fotovoltaik, Lüftung oder Kühlung müsst ihr nachsehen, welcher deviceType verwendet wird und den "locate deviceID" Node entsprechend anpassen.
1 |
[{"id":"8ebef3e8da13cc88","type":"http request","z":"640d4a161fb8fa28","name":"DeviceID","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/equipment/installations/{{iid}}/gateways/{{gws}}/devices/ ","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":660,"y":560,"wires":[["46022befd51c1c67"]]},{"id":"798ae186e9020315","type":"change","z":"640d4a161fb8fa28","name":"","rules":[{"t":"set","p":"deviceID","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":560,"wires":[[]]},{"id":"dc35dc89a8567d81","type":"function","z":"640d4a161fb8fa28","name":"extended auth header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.iid = flow.get('installationID');\nmsg.gws = flow.get('gatewaySerial');\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":560,"wires":[["8ebef3e8da13cc88"]]},{"id":"46022befd51c1c67","type":"function","z":"640d4a161fb8fa28","name":"locate deviceID","func":"const deviceArray=msg.payload.data;\nvar idx = deviceArray.findIndex( (element) => element.deviceType === 'heating');\nmsg.payload=msg.payload.data[idx].id;\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":560,"wires":[["6e1ddceae4be021a","798ae186e9020315"]]}] |
Refresh alle 3600 Sekunden
Jetzt endlich können wir mit der API arbeiten. Aber nach einer Stunde ist der Spaß vorbei, das Access Token ist abgelaufen. Um nun nicht wieder die gesamte obige Routine durchlaufen zu müssen, gibt es eine Abkürzung mit dem Refresh Token.
Hier wird der Trigger – auf "wiederhole automatisch alle 59 Minuten" eingestellt,
Der Funktionsnode hat folgenden Inhalt:
1 2 3 4 5 |
let refreshToken=flow.get('refreshToken'); msg.payload = 'grant_type=refresh_token&client_id=HierKommtDeine ClientIDHin&refresh_token=' + refreshToken; msg.headers = {}; msg.headers['Content-Type'] = 'application/x-www-form-urlencoded'; return msg; |
Wie du siehst, wird hier die Flow Variable "refreshToken" im Javascript ausgelesen. Deine Client ID muss ebenfalls wieder eingetragen werden und das Refresh Token wird als String hinten agehängt.
Es folgt ein http Request Node mit folgender Konfiguration:
Ferner noch ein Change Node, welcher die zurückgegebene Payload in die Access_Token Variable schreibt.
Und hier der zugehörige JSON Flow zum importieren:
1 |
[{"id":"794bf2047ed74376","type":"function","z":"8da86d39b73b390b","name":"set payload and headers","func":"let refreshToken=flow.get('refreshToken');\nmsg.payload = 'grant_type=refresh_token&client_id=DeineClientIDkommtHierhin&refresh_token=' + refreshToken;\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":160,"wires":[["ed038a951c955501"]]},{"id":"38dd6ecae9f953db","type":"inject","z":"8da86d39b73b390b","name":"Refresh Access Token","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3540","crontab":"","once":true,"onceDelay":"2","topic":"","payload":"","payloadType":"date","x":230,"y":160,"wires":[["794bf2047ed74376"]]},{"id":"ed038a951c955501","type":"http request","z":"8da86d39b73b390b","name":"refreshtoken","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://iam.viessmann.com/idp/v3/token","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"credentials":{"user":"","password":""},"x":710,"y":160,"wires":[["e33267b623c5f5d6"]]},{"id":"c2d4d5a3cc1023ad","type":"debug","z":"8da86d39b73b390b","name":"Tokens","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1140,"y":160,"wires":[]},{"id":"e33267b623c5f5d6","type":"change","z":"8da86d39b73b390b","name":"","rules":[{"t":"set","p":"accessToken","pt":"flow","to":"payload.access_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":930,"y":160,"wires":[["c2d4d5a3cc1023ad"]]}] |
Bisherige Nutzer achten wieder auf "v3" in der URL des Request Nodes.
Wird der Flow regelmäßig ausgeführt, hat man immer ein gültiges Access Token.
Refresh nach 180 Tagen erneuern
…zumindest für 180 Tage. Dann verfällt auch das Refresh Token und wir müssen tatsächlich wieder beim Kapitel Authcode abrufen einsteigen. Die Client ID muss dafür nicht neu erzeugt werden. Das Triggern der Schritte kann natürlich auch automatisch erfolgen, sodaß es keinerlei menschlichen Eingriffs mehr bedarf. Das ist z.B. möglich, indem man in der "Access Token Refresh" Routine eine Abfrage nach dem Wert des erneuerten Access Tokens einbaut. Hat das Access Token den Wert "null" (das ist etwas anderes als der Wert 0), wird auf die Initialroutine verzweigt. Die Abfrage mittels Switch-Node sieht so aus:
Siehe auch unten abgebildeten Flow mit Kommentar.
Was auch möglich wäre, aber nicht so betriebssicher, ist den Initialflow einfach alle 4319 Stunden (= 180 Tage minus 1 Stunde) per Trigger aufzurufen. Das wird aber nur funktionieren, wenn die ganze Viessmann Logik wirklich ununterbrochen durchläuft, damit der Trigger komplett abläuft. In 180 Tagen kann eine Menge passieren…
Im Prinzip spricht auch wenig dagegen, den "Refresh Token aktualisieren" Zyklus alle 24 Stunden oder so aufzurufen.
Gesamter Flow
JSON für dieses Kapitel
1 |
[{"id":"41f5e66ea1123715","type":"function","z":"edb7360203dfca8a","name":"set payload and headers","func":"let refreshToken=flow.get('refreshToken');\nmsg.payload = 'grant_type=refresh_token&client_id=deineClientID&refresh_token=' + refreshToken;\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded';\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":860,"wires":[["202623e583f50b9d"]]},{"id":"ccc0fba0ce9645c1","type":"inject","z":"edb7360203dfca8a","name":"Refresh Access Token","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3540","crontab":"","once":false,"onceDelay":"2","topic":"","payload":"","payloadType":"date","x":430,"y":860,"wires":[["41f5e66ea1123715"]]},{"id":"202623e583f50b9d","type":"http request","z":"edb7360203dfca8a","name":"refreshtoken","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://iam.viessmann.com/idp/v3/token","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":true,"headers":[],"x":910,"y":860,"wires":[["e89fe2cc1c73775b","9ed4f0d7bf8b5660"]]},{"id":"706b68f457ed12c3","type":"debug","z":"edb7360203dfca8a","name":"complete msg object","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1240,"y":280,"wires":[]},{"id":"a7188662ba731da7","type":"http request","z":"edb7360203dfca8a","name":"1st time Token Request","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://iam.viessmann.com/idp/v3/token","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":true,"headers":[],"x":970,"y":400,"wires":[["706b68f457ed12c3","af369dbbde2acfbc","77feb868a756cde1","32a92f39827be27e"]]},{"id":"82ff5c6c7dda8279","type":"function","z":"edb7360203dfca8a","name":"set payload & headers","func":"msg.payload = 'grant_type=authorization_code&client_id=deineClientID&redirect_uri=http://localhost:1880/authcode&code_verifier=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&code=' + msg.payload.code;\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded';\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":400,"wires":[["a7188662ba731da7"]]},{"id":"acbf0c1a6db3e9cb","type":"comment","z":"edb7360203dfca8a","name":"Refresh Access Token in normal operation - expires after 3600 seconds","info":"","x":570,"y":800,"wires":[]},{"id":"e92010ef0dfe54cf","type":"inject","z":"edb7360203dfca8a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":520,"y":180,"wires":[["f941ac264dad0dfd"]]},{"id":"134c745731091253","type":"debug","z":"edb7360203dfca8a","name":"Request Result","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":900,"y":180,"wires":[]},{"id":"10ac545d4a7179d1","type":"http in","z":"edb7360203dfca8a","name":"","url":"/authcode/","method":"get","upload":false,"swaggerDoc":"","x":400,"y":300,"wires":[["cd0e4c633d826bf5"]]},{"id":"ec7dd7cefa63b846","type":"debug","z":"edb7360203dfca8a","name":"msg.payload.code","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.code","targetType":"msg","statusVal":"","statusType":"auto","x":710,"y":260,"wires":[]},{"id":"9e8956bf53f56c41","type":"comment","z":"edb7360203dfca8a","name":"Generate authorization code","info":"","x":560,"y":140,"wires":[]},{"id":"cc2bd5d85345dbb3","type":"comment","z":"edb7360203dfca8a","name":"Click here -->","info":"","x":350,"y":180,"wires":[]},{"id":"771e439c68b4bc4d","type":"comment","z":"edb7360203dfca8a","name":"after expiry","info":"","x":340,"y":140,"wires":[]},{"id":"af369dbbde2acfbc","type":"debug","z":"edb7360203dfca8a","name":"access_token","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1220,"y":360,"wires":[]},{"id":"32a92f39827be27e","type":"debug","z":"edb7360203dfca8a","name":"refresh_token","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1220,"y":320,"wires":[]},{"id":"77feb868a756cde1","type":"change","z":"edb7360203dfca8a","name":"set token flow variables","rules":[{"t":"set","p":"accessToken","pt":"flow","to":"payload.access_token","tot":"msg"},{"t":"set","p":"refreshToken","pt":"flow","to":"payload.refresh_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1250,"y":400,"wires":[["7177030fe9bd815a"]]},{"id":"221dabf581eb4756","type":"http request","z":"edb7360203dfca8a","name":"Installation ID","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/equipment/installations","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":920,"y":540,"wires":[["29991e8f79994b07"]]},{"id":"7177030fe9bd815a","type":"function","z":"edb7360203dfca8a","name":"Auth Header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":540,"wires":[["221dabf581eb4756"]]},{"id":"989ceef32cf23cdc","type":"http request","z":"edb7360203dfca8a","name":"Gateway Serial","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/equipment/gateways","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":920,"y":580,"wires":[["4266736c7fd3130a"]]},{"id":"29991e8f79994b07","type":"change","z":"edb7360203dfca8a","name":"set flow.installationID","rules":[{"t":"set","p":"installationID","pt":"flow","to":"payload.data[0].id","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1120,"y":540,"wires":[["91e135ba6d79060e"]]},{"id":"4266736c7fd3130a","type":"change","z":"edb7360203dfca8a","name":"set flow.gatewaySerial","rules":[{"t":"set","p":"gatewaySerial","pt":"flow","to":"payload.data[0].serial","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1120,"y":580,"wires":[["74f4935316632db8"]]},{"id":"91e135ba6d79060e","type":"function","z":"edb7360203dfca8a","name":"Auth Header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":580,"wires":[["989ceef32cf23cdc"]]},{"id":"dcbd89935b7dfcfb","type":"http request","z":"edb7360203dfca8a","name":"DeviceID","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.viessmann.com/iot/v1/equipment/installations/{{iid}}/gateways/{{gws}}/devices/ ","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":900,"y":620,"wires":[["e5d6363248f0ff0b"]]},{"id":"b6a236b47b09e0bf","type":"change","z":"edb7360203dfca8a","name":"","rules":[{"t":"set","p":"deviceID","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1250,"y":620,"wires":[[]]},{"id":"74f4935316632db8","type":"function","z":"edb7360203dfca8a","name":"extended auth header","func":"var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.iid = flow.get('installationID');\nmsg.gws = flow.get('gatewaySerial');\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":620,"wires":[["dcbd89935b7dfcfb"]]},{"id":"25a0350eb2855d86","type":"comment","z":"edb7360203dfca8a","name":"get tokens 1st time","info":"","x":530,"y":360,"wires":[]},{"id":"1c83d789d12a8d81","type":"comment","z":"edb7360203dfca8a","name":"get/set invariable parameters","info":"","x":720,"y":480,"wires":[]},{"id":"e89fe2cc1c73775b","type":"switch","z":"edb7360203dfca8a","name":"","property":"payload.access_token","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1070,"y":860,"wires":[["f941ac264dad0dfd"],["188685a4b5de73a8"]]},{"id":"9ed4f0d7bf8b5660","type":"debug","z":"edb7360203dfca8a","name":"RefreshToken","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1060,"y":780,"wires":[]},{"id":"f941ac264dad0dfd","type":"http request","z":"edb7360203dfca8a","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://iam.viessmann.com/idp/v3/authorize?client_id=deineClientID&redirect_uri=http://localhost:1880/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"basic","senderr":true,"headers":[],"x":690,"y":180,"wires":[["134c745731091253"]]},{"id":"b02cd61bbe1d4d9f","type":"http response","z":"edb7360203dfca8a","name":"Reponse","statusCode":"200","headers":{},"x":760,"y":300,"wires":[]},{"id":"9f9bc4ad9aa94822","type":"debug","z":"edb7360203dfca8a","name":"debug 155","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":720,"wires":[]},{"id":"e5d6363248f0ff0b","type":"function","z":"edb7360203dfca8a","name":"locate deviceID","func":"const deviceArray=msg.payload.data;\nvar idx = deviceArray.findIndex( (element) => element.deviceType === 'heating');\nmsg.payload=msg.payload.data[idx].id;\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":620,"wires":[["9f9bc4ad9aa94822","b6a236b47b09e0bf"]]},{"id":"188685a4b5de73a8","type":"change","z":"edb7360203dfca8a","name":"","rules":[{"t":"set","p":"accessToken","pt":"flow","to":"payload.access_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1270,"y":900,"wires":[[]]},{"id":"cd0e4c633d826bf5","type":"junction","z":"edb7360203dfca8a","x":540,"y":300,"wires":[["ec7dd7cefa63b846","82ff5c6c7dda8279","b02cd61bbe1d4d9f"]]}] |
Weiter gehts mit dem nächsten Kapitel Daten abfragen und visualisieren.
Also falls jemand über das gleiche Problem stolpert. Bei mir hat es mit obiger Anleitung nicht funktioniert. Habe aber auch Node RED in HA integriert. Folgendes hat dann funktioniert:
Sowohl im Viessmann Developer Portal als auch in der URL in Node RED musste ich "endpoint" hinzufügen. Also:
http://localhost:1880/endpoint/authcode
Aha! Danke für den Hinweis.
Bei in Homeassistant integriertem NR kommt es tatsächlich zu Problemen. Wenn das die Lösung für das Problem ist, würde ich das gerne dokumentieren. Wo genau – bei welcher Abfrage – musst du den endpoint hinzufügen? Ist es der Node, der mit [get]/authcode/ beschriftet ist? Muss man das dann nicht auch beim allerersten http Request so machen?
https://iam.viessmann.com/idp/v3/authorize?client_id=DeineClientIDkommtHierhin&redirect_uri=http://localhost:1880/endpoint/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access
Würde mir helfen, meine Anleitung besser zu machen. Ich selbst nutze HA nicht und tue mich dementsprechend schwer, spezifische HA Besonderheiten herauszufinden. Danke nochmal für diesen guten Tipp!
VG
Chris
Anleitung habe ich entsprechend ergänzt. Vielen Dank Alex!
Moin,
ich habe die "Refresh" Routine weggelassen und führe stattdessen die "Initialroutine" alle 59 Minuten aus. Funktioniert seit 3 Wochen ohne Probleme.
Spricht was dagegen das weiter so zu tun oder wäre es tatsächlich besser mit der "Refresh" Routine zu arbeiten?
Super Anleitung übrigens…. war gar kein Problem das so nachzubauen!! Danke 😉
Totti
Freut mich, dass meine Tutorials dir gefallen. Bzgl. der dauernden Verwendung der Initialroutine anstatt des Refreshs bin ich überfragt.
Du kannst dich ja mal im Viessmann Forum schlau machen. Viessmann-Community.com
Viel Spaß
Chris
P.S. Das Einzige was mir als Grund für die Verwendung des Refresh Tokens einfällt, könnten Lastgründe sein. d.h. die Initialroutine braucht auf der Viessmann Seite mehr Systemressourcen, weshalb man den Weg über den Refresh vorzieht.
Hallo, bitte um Hilfe.
Ich versuche deinen Flow seit Stunden zum Laufen zu bringen.
ich bekomme immer folgenden Request:
Error
Hab auch nochmals einen Raps neu aufgesetzt mit nur NodeRed, immer das gleiche Ergebnis.
Hallo,
tut mir leid, dass das bei dir nicht klappt. Deine Informationen sind leider ein bisschen knapp. Bekommst du im obersten Flow (Timestamp-httpRequest-Debug) ein sinnvolles Ergebnis angezeigt?
Das sieht im 'Debug Node etwa so aus: {"code":"BXpX1B73QsqxyzaJZDt9EndUXJsQ0WMfs6SIH0-pNmM"}
Wenn nein, hast du bei der Client ID bzw. beim http Request etwas falsch gamcht.Es würde mir helfen, dir zu helfen, wenn du mir den Flow als JSON exportiert schicken könntest. Die privaten Daten kannst du gerne mit Text überschreiben.
VG Chris
ANMERKUNG: Im obersten/ersten Debug Node steht nur dann etwas Sinnvolles, wenn im weiteren Verlauf der zuerst eingebaute http in Node das vom Viessmann Server angesprochene virtuelle Verzeichnis
/authcode
aktiviert hat.Noch ein Tipp: Probiere doch mal, die URL Zeile aus dem allerersten http Request in den Browser einzugeben.
z.B.
https://iam.viessmann.com/idp/v3/authorize?client_id=deineClientIDkommtHierhin&redirect_uri=http://localhost:1880/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access
Deine generierte ClientID musst du natürlich an der entsprechenden Zeile eintragen.
Dann kommt das Viessmann Login Fenster, du loggst dich ein. Es kommt eine Fehlermeldung aber in der URL Zeile vom Brwoser steht der Authcode. http://localhost:1880/authcode?code=2TsyNSphQ98hUHP6oMaoamhl4NSG1L1olDOetcpp
Wenn das funktioniert, dann kannst du weitermachen.
VG
Chris
Hallo, bei mir kommt auch der Fehler
Error
Aber die Abfrage im Browser funktioniert und der Code wir dort angezeigt.
Klingt jetzt blöd, aber bei mir funktioniert es problemlos.
Schicke mir doch bitte deinen Flow (eigene Codes etc. Mit xxx oder so überschreiben). Dann kann ich schauen, was evtl. nicht stimmt.
Adresse steht im Impressum.
Viele Grüße
Chris
Bitte sage mit, an welcher Stelle die Fehlermeldung kommt. Welcher Node/Debug Node gibt die aus? Was steht im Debug Balken aufder rechten Seite (Screenshot per Mail)? Ich kann den Fehler nicht reproduzieren, egal, wie sehr ich die ClientID Funktion bei Viessmann absichtlich verkehrt befülle. Steh am Schlauch….
Chris
Hi,
Ich hab auch diesen Fehler, konnte ihn aber etwas eingrenzen.
Da die URL den Code enthält (und die API andere Fehler auswirft falls nicht) sollte der Teil stimmen. Ich glaube eher das der Loopback das Problem ist.
Dem Nodered (und damit dem Webserver unten drunter) wird eine Anfrage auf ein Verzeichnis gestellt das er nicht kennt. Damit antwortet er mit der entsprechenden Meldung. Nehme ich das originale Nodered Verzeichnis bekomme ich eine andere Antwort – nämlich Standard Apache Index.html – Genauso falsch und kein Code, aber das GET wird akzeptiert.
Die Frage lautet also wie den Pi einstellen damit er das Verzeichnis akzeptiert… Dafür reicht mein Wissen aber nicht ;(
Danke für deine Mühe, aber: Der Webserver bzw. das Verzeichnis von NR muss nicht "eingestellt" werden. Das erledigt der "http in" Node. Probiere mal folgendes:
[{"id":"e51bfe99a850ee6c","type":"http in","z":"640d4a161fb8fa28","name":"\"http in\" Node","url":"test","method":"get","upload":false,"swaggerDoc":"","x":910,"y":100,"wires":[["8c6a6d49941230e9"]]},{"id":"7a56abfc800f82aa","type":"http response","z":"640d4a161fb8fa28","name":"","statusCode":"200","headers":{"content-type":"text/plain"},"x":1380,"y":100,"wires":[]},{"id":"8c6a6d49941230e9","type":"template","z":"640d4a161fb8fa28","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"This is the payload: test !","output":"str","x":1160,"y":100,"wires":[["7a56abfc800f82aa"]]}]
Das ist ein Mini Webserver, der nur eine simple Nachricht zurückschickt, wenn er aufgerufen wird: http://IPdesNodeRedServers:1880/test also z.B. http://192.168.178.42:1880/test
Da muss also nichts eingestellt oder konfiguriert werden, sofern der "http in" Node das Zielverzeichnis aufführt.
Schicke mir bitte mal deinen Flow, zumindest die ersten 6 oder so Nodes bis inkl. dem http in Node und dem Response Node. Dann kann ich mir das ansehen. Ich versteh' echt nicht, warum das bei manchen von euch nicht funktioniert.
Welche Version von Node-Red nehmt ihr her? 3.1.0 ist die aktuellste. Die im Raspberry Pi mitgelieferte Version ist eher veraltet.
Noch eine Möglichkeit für den Fall, dass du mit Docker arbeitest: Wenn Docker localhost sperrt, dann klappte es vielleicht mit
127.0.0.1
anstatt localhost. Ist im Grunde dasselbe aber vielleicht nützt es ja was… Dafür aber auch bei der Anlage der ClientID anstatt localhost die IP Adresse127.0.0.1
eintragen und ebenso beim ersten http request node. Mir bitte unbedingt Bescheid geben, was daraus geworden ist.VG
Chris
Ich habs gefunden… Dein Webserver-Hinweis hat mich auf die Lösung gebracht weil der genau das tut was ich vermisst habe: Das Verzeichnis aufrufbar machen.
Für dich ists wahrscheinlich selbstverständlich, aber ich habe das Tutorial Step-by-Step gelesen und umgesetzt und entsprechend schon den ersten einfachen Flow mit Timestamp->Request->Debug getestet was die Fehlermeldung verursacht hat. Im Abschnitt darunter wird dann das HHTP Objekt eingefügt.
Nachdem das drin war (Und der Request Ausgang mit dem Ergebnis verknüpft) klappt es jetzt und ich kriege den Code…
DANKE DIR!
Ich überarbeite dann meine Anleitung noch etwas. Natürlich funktioniiert der allererste Debug nur dann, wenn schon das Verzeichnis (durch den "http in" Node) bereitgestellt wurde. Freut mich, dass wir das endlich geschafft haben!
VG
Chris
Hatte ich auch, auch unter HA.
Mein Problem war, dass überall "/endpoint" ergänzt werden musste, außer in der "set payload & headers".
Da stand schon von vornherein, dass alles relativ zu "/endloint" ist.
Prima. Danke für die Bestätigung.
VG
Chris
Hallo, ich bekomme es leider nicht zum Laufen.
Hab alles so eingestellt wie beschrieben, auf einem Raps mit Nodered bekomme folgenden String zurück:
Viessmann Login
<link href="/idp/sso/v1/nevislogrend/applications/IDP_SSO_V1/webdata/css/icon.css" rel="s…
Auf einem Raspi mit Nodered in Docker, folgende Meldung:
Error
Bitte um Hilfe, danke.
Gruß Matthias
Sorry,
dein Post hing in meinem Spamfilter, wahrscheinlich wg. der komischen href Zeile von der ich keine Ahnung habe was die bedeuten soll. Kommt das von Viessmann oder ist das ein Copy&Paste Fehler?
Chris
Hi, ich benutze HomeAssistant mit NodeRed. Versuche dein Skript zum laufen zu bekommen aber es scheitert schon beim ersten Flow. Da kommt folgende Fehlermeldung im Node "Request Result":
"RequestError: connect ECONNREFUSED ::1:1880 : https://iam.viessmann.com/idp/v3/authorize?client_id=MEINEIID&redirect_uri=http://localhost:1880/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access"
Hast du da irgendeine Idee?
Hallo Daniel,
Tut mir leid, ich habe von Homeassistant keine Ahnung. Bei mir läuft das alles „native” auf Node-Red ohne irgendwelche Smart Home Frameworks.
Wenn du einen Linux (evtl. Geht auch Windows) Rechner hast, probier es doch mal ohne Homeassistant.
Ansonsten mal Tante Google fragen.
Jetzt im Sommer werde jetzt h wohl nicht dazu kommen, das Problem mal selbst nachzustellen.
Viel Glück noch
Chris
Hallo Daniel,
ich habe gerade noch etwas gegrübelt… Die Response vom Viessmann Server "RequestError: connect ECONNREFUSED ::1:1880" besagt, dass dein NR Server bzw. die HA Shell darum herum den Request abgelehnt hat. ::1:1880 ist dasselbe wie localhost:1880
Ich vermute, dass HA die Anfrage nicht durchlässt. Eventuell wird der Port 1880 geblockt oder umgeleitet. Probiere mal mit einem http-in Node einen Versuchsaufbau zu erstellen. Der Node sollte auf die GET Methode eingestellt werden, als URL trägst du test ein. Der Vollständigkeit halber noch einen http-Response Node, der den Statuscode 200 zurückschickt.
Hier der Setup als JSON:
[{"id":"d51ef4933a634ccc","type":"http in","z":"090ac94c9cd39a60","name":"","url":"/test","method":"get","upload":false,"swaggerDoc":"","x":300,"y":820,"wires":[["747daccfb6ae69f1","ec68e3b00f09949e"]]},{"id":"747daccfb6ae69f1","type":"debug","z":"090ac94c9cd39a60","name":"debug 59","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":500,"y":820,"wires":[]},{"id":"ec68e3b00f09949e","type":"http response","z":"090ac94c9cd39a60","name":"","statusCode":"200","headers":{},"x":500,"y":760,"wires":[]}]
Kannst du diesen Node über einen Browser aus deinem Heimnetz "anfunken"? http://IPdeinesNRServers:1880/test/?message=deineTestMessage. Im Debug Node sollte message=deineTestMessage erscheinen
Wenn das nicht funktioniert, dann ist die Ursache wie oben beschrieben, und du musst schauen, wie du den HA Server bzw. NR darin freischaltest.
Keinesfalls den Port 1880 im Router freischalten sonst kann jeder auf deine Installation zugreifen!!
Wenn doch, dann musst du leider weiter forschen. Ich kann das leider nur sehr bedingt, da ich keine dieser Klickibunti Hausautomatisierungsgeschichten bei mir habe. HA oder IObroker sind mir für meine bescheidenen Anforderungen zu mächtig, zu kompliziert und zu intransparent.
Viele Grüße aus München
Chris
Hallo, bei mir läuft Node Red direkt auf der CCU3. Bedienung über Win 10 PC.
Bekomme auch immer die Fehlermeldung „ ErrorCannot GET /authcode“.
Habe zur Probe meine Firewall abgeschaltet—> gleicher Fehler
Den/die o. a. Code/Programmierung habe ich so übertragen.
Port 1880 ist in der CCU freigegeben.
Abfrage des Codes über Browser funktioniert.
Im Dev Portal von Viessmann stimmen die Einstellungen auch.
Was muss ich einstellen, damit ich den Authcode via Node Red abrufen kann?
Hallo,
Bin grad unterwegs. Mit CCU3/Homematic kenne ich mich überhaupt nicht aus. Wenn das Teil auf Linux läuft, dann probiere mal diese Hilfestellung:
Checke nochmal die ClientID Geschichte beim Developer.viessmann.com Dashboard:
Google Captcha muss ausgeschaltet sein
Redirect URI muss http://localhost:1880/authcode lauten. Keine IP Adresse verwenden.
im Node Red http request folgende URL eintragen (nur mit deiner Client ID anpassen, den Rest genau so lassen.)
https://iam.viessmann.com/idp/v3/authorize?client_id=deineClientIDKommtHierHin&redirect_uri=http://localhost:1880/authcode&response_type=code&code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&scope=IoT%20User%20offline_access
Nicht vergessen, die Daten für das Basic Authentifizierungs Login einzutragen. Das ist dasselbe Login, dass du auch für deinen Viessmann Account oder die ViCare App verwendest.
Das MUSS funktionieren, d.h. im Debug Node (Request Result) steht dann der Auth Code. Wenn nicht, dann mal die URL Zeile in den Browser eingeben, dich mit deinem Viessmann Login einloggen. Es erscheint eine Verbindung Fehlgeschlagen Seite aber in der URL Zeile vom Browser steht jetzt etwas der Art: http://localhost:1880/authcode?code=1ewaadBgBpQchLjJN4hh-z4RMVR8FJ5dvG5heuZp23k
Wenn das geht, dann hast du etwas bei Node Red oder deinem Hardware Setup verkehrt. Wenn nein, würde ich vorschlagen, mit Michael Hanna von Viessmann Kontakt aufzunehmen.
Hi!
Danke für die schnelle Antwort.
Wie beschrieben passt die Config von Viessmann etc. . Wenn ich den Request im Browser ausführe, bekomme ich den Code.
Bzgl. der Einstellungen im Node Red bin ich absoluter Rookie.
Evtl. benötigt man in diesem Setup hier einen anderen Port, den man (zusätzlich) freigeben muss.
Werde mal den Kollegen von Viessmann kontaktieren. Danke für den Hinweis 🙂
Hi,
Probiere mal die ersten drei Nodes aus dem Kapitel „Authcode abrufen“. Im Debug Node steht das Resultat. Wie du den http Request Node konfigurierst steht im Text.
Normalerweise läuft Node-Red auf Port 1880. Evtl mal in der Konfigurationsdatei nachsehen, ob da ein anderer Port eingestellt ist.
Viele Ostermontags-Grüße
Chris
ANMERKUNG/Nachtrag: Im obersten/ersten Debug Node steht nur dann etwas Sinnvolles, wenn im weiteren Verlauf der zuerst eingebaute http in Node das vom Viessmann Server angesprochene virtuelle Verzeichnis /authcode aktiviert hat.
Hi!
Welche Konfigurationsdatei meinst Du genau?
Hallo,
Bei Linux steht die Datei settings.js im versteckten Node-Red Verzeichnis unterhalb deines Home Directories. Also z.B. /home/philipp/.node-red/settings.js
Aber wenn du Node-Red über die url http://deinServerName:1880 aufrufen kannst, dann ist das auch die Portnuummer für das Viessmann Gedöns.
VG
Chris
******Dieser Post ist fälschlicherweise vom Spamfilter aussortiert worden – sorry! *******
Hallo,
eine Abfrage mit GET (wie im Text beschrieben) im ersten http-Request liefert kein Ergebnis.
Grundsätzlich funktioniert diese URL für eine Abfrage via Browser bei Viessmann.
Bei einer Abfrage mit POST via Node Red mit gleicher URL kommt folgendes Ergebnis heraus:
302 FoundFoundThe document has moved here.
Zumindest wird da der Authcode angezeigt.
Ist es möglich dieses Ergebnis im Node Red so aufzubereiten, dass nur der Code-Teil im msg.payload abgespeichert wird?
Hallo,
ich muss da leider passen. Die Abfrage sollte mit einem GET Request funktionieren. Da ich das ganze für einen Raspberry Pi entwickelt habe, kann es durchaus sein, dass ein anderes Gerät mit Linux Kern nicht ganz so funktioniert wie gewünscht, da dort irgendwelche Standardkomponenten fehlen, deaktiviert oder anders konfiguriert sind. Im Prinzip ist eine z.B. Fritz!Box auch bloß ein Linux Rechner, aber die Viessmann API wirst du damit nur mit erheblichem Aufwand zum Laufen bringen. Bei der CCU3 ist das vielleicht auch so.
Notbehelf: Access und Refresh Token auf anderem Weg erzeugen (Postman, Funktion bei developer.viessmann.com) in Node-Red einbauen und laufen lassen. Nach 180 Tagen widerholen.
Viel Erfolg noch
Chris
ANMERKUNG: Im obersten/ersten Debug Node steht nur dann etwas Sinnvolles, wenn der weiter unten stehende http in Node existiert und das vom Viessmann Server angesprochene virtuelle Verzeichnis
/authcode
generiert hat.Moin, bin etwas am verzweifeln. Ich erhalte folgende Fehlermeldung "ErrorCannot GET /authcode". Client-ID habe ich mehrfach neu angelegt.
Ich habe NodeRed auf einer Diskstation laufen. Hast Du irgendwelche Ideen?
Danke!
Thilo
Hi,
Es könnte sich um ein Firewall Problem der Diskstation handeln. Port 1880 muss in der Diskstation explizit freigegeben werden. Im Router hingegen NICHT sonst bekommst du ein massives Sicherheisproblem.
Gruß
Chris
Probier das mal
ist mittlerweile erledigt … die Diskstation hatte eine Macke … Neustart hat es gebracht … bitte den Eintrag löschen … und sorry!
Hallo Chris,
vielen Dank für die super Anleitung und das gesamte Tutorial!
Sogar ich als blutiger Anfänger auf dem Pi und mit Nodered finde mich gut zurecht.
Ich habe jetzt den Flow soweit implementiert (mit der Schleife für den refresh Token) und mir ein Dashboard gebastelt. Das funktioniert auch soweit so gut.
Leider kommt nach ca 1,5 Stunden ein Fehler und die function nodes für das Auslesen der Werte aus den Features laufen alle in die selbe Meldung: "TypeError: Cannot read properties of undefined (reading 'findIndex')"
Also irgendetwas kann mit dem Index ausgelesen werden.
Hast du eine Idee woran das liegen kann?
Vielen Dank und Grüße
Moritz
Hi,
Freut mich, wenn es dir hilft und gefallen hat. Das von dir beschriebene Problem tritt immer dann auf, wenn die Viessmann Server gerade nicht antworten.
Nach ein paar Minuten oder auch vielen paar Minuten funktioniert es dann wieder.
Viel Spaß noch
Chris
Hallo,
erstmal vielen Dank für das super Tutorial.
Kann mir bitte jemand die Integration für den 180 Tage refresh erklären.
Leider bin ich in NoteRed noch purer Anfänger. Danke.
Hallo Matthias,
aler Anfang ist schwer…
Danke für deine Frage, das hilft mir, Verständnisprobleme bei meinem Text zu erkennen. Ich passe mein Tutorial entsprechend an.
Im Prinzip musst du beim "Refresh Access Token" Teil, der spätestens alle 3600 Sekunden aufgerufen werden muss, mit einem Switch Node abfragen, ob der Refresh geklappt hat. Falls nicht (d.h. msg.payload.access_token = null), wird ganz nach oben zur Initialroutine verzweigt.
Alternativ kannst du den Trigger ganz am Anfang so einstellen, dass er vor dem Verfall des Refresh Tokens anspringt – z.B. alle 179 Tage.
Viele Grüße und viel Spaß
Chris
Danke! habs mit minimalen Anpassungen integriert – klasse! Schon lustig, entweder ich habs in der viessmann-doku überlesen, oder es wird nicht wirklich präsent erwähnt, dass auch dieser token nach 180t abläuft .. naja, macht ja sinn trotzdem. VG
Hi,
freut mich, wenn ich dir damit helfen konnte. Du schreibst "minimale Anpassungen"… hast du einen Fehler entdeckt oder was konkret hast du abgeändert. Vielleicht macht das ja mehr Sinn.
Danke Chris
Ja, es war bei den Debug-Steinen "access_token" und "refresh_token" ein Fehler. Sie haben beide beides angezeigt. Hier musste der Payload gefiltert werden.
Danke für den Hinweis, ich hab's korrigiert.
VG
Chris