{"id":1855,"date":"2023-01-16T15:02:15","date_gmt":"2023-01-16T14:02:15","guid":{"rendered":"https:\/\/www.rustimation.eu\/?p=1855"},"modified":"2025-11-26T11:43:48","modified_gmt":"2025-11-26T10:43:48","slug":"1_zugang_api","status":"publish","type":"post","link":"https:\/\/www.rustimation.eu\/index.php\/1_zugang_api\/","title":{"rendered":"Viessmann API und Node-Red &#8211; Teil 2 &#8211; API Zugriff"},"content":{"rendered":"<p>Der Zugang zur Viessmann API ist nicht ganz trivial. Die Beschreibung auf den <a href=\"https:\/\/documentation.viessmann.com\/static\/getting-started\" target=\"_blank\" rel=\"noopener\">Viessmann Seiten<\/a> l\u00e4sst auch zu w\u00fcnschen \u00fcbrig. 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 API Zugriff erst einmal funktionsf\u00e4hig, ist alles Weitere ein Klacks.<\/p>\n<p><!--more--><\/p>\n<p>Mit jeder Erkenntnis wird dieser Beitrag aktualisiert und dadurch leider auch l\u00e4nger und etwas un\u00fcbersichtlich. Wichtige \u00c4nderungen in meiner Anleitung sind entsprechend hervorgehoben und zus\u00e4tzlich haben meine Beitr\u00e4ge jetzt auch ein Inhaltsverzeichnis.<\/p>\n<h2>Schritt f\u00fcr Schritt<\/h2>\n<p><strong>Vorbemerkung:<\/strong> diese Anleitung geht davon aus, dass <strong>Node-Red native<\/strong> auf einem Linux Rechner, das hei\u00dft einem <strong>Raspberry Pi<\/strong> installiert wird also ohne ein Hausautomatisierungsframework darum herum. F\u00fcr Spezialrechner auf Linux Basis (z.B. CCU3) oder Windows PCs, Synology Disk Stations etc. gelten unter Umst\u00e4nden andere Voraussetzungen &#8211; zum Beispiel spezielle Client Firewall Regeln und Port-Einstellungen, die hier nicht behandelt werden. Dasselbe gilt f\u00fcr ein embedded Node-Red im <strong>Homeassistant<\/strong> oder <strong>IO Broker<\/strong>. Auch <strong>Docker<\/strong> macht immer wieder Probleme. Ich kann hier auch nur eingeschr\u00e4nkten Support leisten. Schaut euch auch bitte die untenstehenden \"Hinweise zur Fehlersuche\" an, wo ich L\u00f6sungsm\u00f6glichkeiten dank der Hinweise von einigen Lesern zusammengetragen habe.<\/p>\n<p>A propos Firewall: Der Router braucht <strong>keine<\/strong> Portfreischaltung im Firewall. H\u00fctet euch <strong>unbedingt<\/strong> davor, den Node-Red Port 1880 im Router freizuschalten. Damit h\u00e4ttet ihr ein riesiges Sicherheitsproblem.<\/p>\n<h4><span style=\"color: #ff0000;\">Achtung: Neu ab Sommer 2025<\/span><\/h4>\n<p>Im Zuge der \"Eingemeindung\" von Viessmann in die US-amerikanische Firma Carrier \u00e4ndern sich leider die aufzurufenden URLs. Aus <strong>viessmann.com<\/strong> wird durchg\u00e4ngig <strong>viessmann-climatesolutions.com. <\/strong>Ab Jahresende 2025 gilt dann nur noch die neue URL. Bis dahin sind beide URLs zul\u00e4ssig.<\/p>\n<p>Ich habe meine Beitr\u00e4ge zum Thema Viessmann API entsprechend angepasst. Screenshots werde ich sukzessive auch migrieren, was allerdings sehr aufwendig ist. Sollte jemand noch eine alte URL in den Node-Red JSON Snippets finden, bitte ich um eine kurze Mitteilung \u00fcber die Kommentarfunktion.<\/p>\n<p>Ansonsten: Wem das Gewese um die Viessmann API zu bl\u00f6d geworden ist, dem empfehle ich den <a href=\"https:\/\/www.rustimation.eu\/index.php\/viessmann-ohne-api-optolink-splitter-1\/\" target=\"_blank\" rel=\"noopener\">alternativen Zugriff auf die Heizanlage \u00fcber den Optolink-Splitter<\/a> oder <a href=\"https:\/\/www.rustimation.eu\/index.php\/a-viessmann-api-und-node-red\/#open3e\" target=\"_blank\" rel=\"noopener\">open3e<\/a> f\u00fcr neuere Ger\u00e4te ohne Vitoconnect K\u00e4stchen. Ich selbst arbeite nur noch damit und nicht mehr \u00fcber die API.<\/p>\n<h3>Voraussetzungen &#8211; Vorarbeiten<\/h3>\n<p>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\u00e4stchen &#8211; sofern verwendet &#8211; eine ausreichende Empfangsst\u00e4rke hat. 1 Balken ist definitiv zu wenig. Siehe <a href=\"https:\/\/www.viessmann.de\/de\/produkte\/steuerung-und-konnektivitaet\/vitoconnect.html\" target=\"_blank\" rel=\"noopener\">hier<\/a> (Abschnitt <em>Anleitung<\/em>).<\/p>\n<p>Anschlie\u00dfend, bzw. nach Erhalt und Quittierung des Best\u00e4tigungsmails solltest du dich bei <a href=\"http:\/\/developer.viessmann-climatesolutions.com\" target=\"_blank\" rel=\"noopener\">developer.viessmann-climatesolutions.com<\/a> einloggen. Dabei sind dieselben Zugangsdaten zu verwenden,\u00a0 die bei der Registrierung der ViCare App verwendet wurden. Das Ganze ist weitestgehend selbsterkl\u00e4rend.<\/p>\n<p>Nach dem Login hat man Zugriff auf die Dokumentation und das Viessmann Developer Dahboard. Dort muss zuerst einmal die<\/p>\n<h3>Client ID<\/h3>\n<p>angelegt werden. Mit Klick auf <em>My Dashboard<\/em> 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\u00f6ten, wenn Node-Red zusammen mit dem Viessmann API Adapter auf einem IO Broker laufen soll.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1877\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-15-14_29_58-Developer-Portal-\u2013-Mozilla-Firefox-e1673791203987.png\" alt=\"\" width=\"400\" height=\"365\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-15-14_29_58-Developer-Portal-\u2013-Mozilla-Firefox-e1673791203987.png 400w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-15-14_29_58-Developer-Portal-\u2013-Mozilla-Firefox-e1673791203987-300x274.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>Bei <em>Name<\/em> tr\u00e4gst du denselben Namen ein, den du deiner\u00a0 Anlage in der App verpasst hast &#8211; 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.<\/p>\n<p>Zuvor muss aber noch das <em>Google reCAPTCHA<\/em> ausgeschaltet und eine <em>Redirect URI<\/em> eingegeben werden.<\/p>\n<p>Die Redirect URI ist die Aufrufadresse (Callback Adresse) deiner Applikation, an die bei Aufruf ein AuthCode \u00fcbermittelt wird. In der generischen <a href=\"https:\/\/documentation.viessmann-climatesolutions.com\/static\/authentication\" target=\"_blank\" rel=\"noopener\">Viessmann Anleitung<\/a> steht\u00a0 <span class=\"lang:js decode:true crayon-inline\">http:\/\/localhost:4200<\/span> . Wir hingegen verwenden <span class=\"lang:js decode:true crayon-inline\">http:\/\/localhost:1880\/authcode<\/span>\u00a0 &#8211; das ist die Adresse bzw. der Port, auf dem Node-Red auf Input lauscht. Das <span class=\"lang:default decode:true crayon-inline \">\/authcode<\/span> ist ein beliebiger <strong>Pfad<\/strong>, <strong>der unbedingt erforderlich ist<\/strong>, sonst ruft Viessmann den Node-Red Editor anstatt des Flows auf. Merke dir diesen Pfad, du brauchst ihn in den n\u00e4chsten Schritten.<\/p>\n<p>Die Client ID ist statisch und bleibt so lange g\u00fcltig, bis du sie im Dashboard l\u00f6schst.<br \/>\n<strong>Merke<\/strong>: Die ClientID wird im Folgenden insgesamt dreimal in einen http Request Node eingetragen. Das wird gerne \u00fcbersehen, wenn man die ClientID sp\u00e4ter einmal ge\u00e4ndert hat.<\/p>\n<h3>Authcode abrufen<\/h3>\n<p>Das Erzeugen der Client ID war der letzte manuelle Schritt und muss auch nur einmalig durchgef\u00fchrt werden. Der Rest ist k\u00fcnftig automatisiert:<\/p>\n<p>Wir ziehen uns nun in Node-Red drei Nodes auf das Editiertableau und \"verkabeln\" diese.<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/cacicala_1-1664025783018\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1886\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_1-1664025783018.png\" alt=\"\" width=\"696\" height=\"65\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_1-1664025783018.png 696w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_1-1664025783018-300x28.png 300w\" sizes=\"auto, (max-width: 696px) 100vw, 696px\" \/><\/a><\/p>\n<p><em>Timestamp <\/em>zum Triggern, <em>http request<\/em> zum Abfragen und <em>Debug<\/em> f\u00fcr das Ergebnis.<\/p>\n<p style=\"padding-left: 40px;\"><span style=\"color: #ff0000;\"><strong>ACHTUNG<\/strong><\/span>: Der Debug Node (hier debug 5) wird erst dann ein sinnvolles Ergebnis liefern, wenn ihr auch den weiter unten stehenden Schritt mit dem <em>http in<\/em> Node gegangen seid. Erst der <em>http in<\/em> Node erzeugt das virtuelle Verzeichnis, in das der Viessmann Server hineinschreibt.<\/p>\n<p>In die URL Zeile des\u00a0 <em>http request <\/em>kommt folgender Inhalt:<\/p>\n<pre class=\"height-set:true height-mode:1 height:25 top-set:false bottom-set:false lang:js decode:true\">https:\/\/iam.viessmann-climatesolutions.com\/idp\/v3\/authorize?client_id=DeineclientID&amp;redirect_uri=http:\/\/localhost:1880\/authcode&amp;response_type=code&amp;code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&amp;scope=IoT%20User%20offline_access<\/pre>\n<p style=\"padding-left: 40px;\"><span style=\"color: #808080;\"><strong>Bisherige Nutzer der API aufgepasst<\/strong>: seit Februar 2023 gibt es eine neue Version des API Authentifizierungsprozesses: Anstatt<em> https:\/\/iam.viessmann.com\/idp\/v2\/authorize&#8230;<\/em> hei\u00dft es jetzt <em>https:\/\/iam.viessmann.com\/idp\/<\/em><strong><span style=\"color: #ff0000;\"><em>v3<\/em><\/span><\/strong><em>\/authorize<\/em>&#8230; <\/span><span style=\"color: #ff0000;\"><span style=\"color: #000000;\"><span style=\"color: #808080;\">sonst \u00e4ndert sich nichts. Der Vorteil liegt in konkreteren Fehlermeldungen beim Login. Siehe <a style=\"color: #808080;\" href=\"https:\/\/documentation.viessmann.com\/static\/changelog\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #993300;\">Viessmanm API Changelog<\/span><\/a> Abschnitt Februar 2023. \u00dcbernimmt man die \u00c4nderung, sollte weiter unten d.h. bei <em>https:\/\/iam.viessmann.com\/idp\/<span style=\"color: #ff0000;\"><strong>v3<\/strong><\/span>\/token&#8230; ebenfalls <\/em>v3 anstatt v2 verwendet werden.<\/span><br \/>\n<\/span><\/span><\/p>\n<p>Deine <strong>Client ID<\/strong> an der entsprechenden Stelle eintragen, den gesamten anderen Kram k\u00f6nnt ihr so stehen lassen. In der Viessmann Anleitung ist etwas von <em>Oauth\u00a0<\/em> die Rede f\u00fcr Code Challenge und -Response. Ich habe nie verstanden, wie das funktioniert. Es reicht, hier dieselbe Challenge\/Response wie in der Viessmann Dokumentation zu nehmen.<\/p>\n<p>Die Redirect URI 1:1 aus dem ClientID Prozess auf den Viessmann Seiten \u00fcbernehmen.<\/p>\n<p><em>scope= IoT User<\/em> (bzw. <span class=\"lang:js decode:true crayon-inline\">scope=IoT%20User<\/span> ) ist vorgegeben, <em>offline_access<\/em> veranlasst die API noch ein Refresh Token mitzugeben, was die sp\u00e4tere Nutzung deutlich vereinfacht.<\/p>\n<p>Den Rest des http requests wie folgt ausf\u00fcllen:<\/p>\n<figure id=\"attachment_2319\" aria-describedby=\"caption-attachment-2319\" style=\"width: 1536px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2319 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/03\/A98136AE-10FA-4E04-8972-4545C6A3E246-e1677951622901.jpeg\" alt=\"\" width=\"1536\" height=\"1506\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/03\/A98136AE-10FA-4E04-8972-4545C6A3E246-e1677951622901.jpeg 1536w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/03\/A98136AE-10FA-4E04-8972-4545C6A3E246-e1677951622901-300x294.jpeg 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/03\/A98136AE-10FA-4E04-8972-4545C6A3E246-e1677951622901-1024x1004.jpeg 1024w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/03\/A98136AE-10FA-4E04-8972-4545C6A3E246-e1677951622901-768x753.jpeg 768w\" sizes=\"auto, (max-width: 1536px) 100vw, 1536px\" \/><figcaption id=\"caption-attachment-2319\" class=\"wp-caption-text\">Achtung: neue URL viessmann-climatesolutions.com<\/figcaption><\/figure>\n<p>Methode ist GET, Nutzdaten ignorieren, Basis Authentifizierung verwenden &#8211; hier die <strong>Viessmann Account Daten<\/strong> (Username\/eMail und Passwort aus der App &#8211; nicht den Namen aus dem Viessmann \u201eEdit Client\u201c Fenster) eintragen &#8211; und schlie\u00dflich bei R\u00fcckgabe eine UTF-8 Zeichenfolge ausw\u00e4hlen.<\/p>\n<p>So lange du die Client ID nicht \u00e4nderst, brauchst du diese Bl\u00f6cke nicht mehr anfassen.<\/p>\n<p>Mit dem <em>http Request Node<\/em> haben wir die Anfrage losgeschickt, mit einem <em>http In Node<\/em> empfangen wir die Antwort. Im Prinzip bauen wir hier einen winzigen Webserver auf.<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/index.php\/1_zugang_api\/2023-01-16-12_04_57-node-red-_-192-168-178-24-mozilla-firefox\/\" rel=\"attachment wp-att-1894\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1894\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-12_04_57-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"595\" height=\"121\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-12_04_57-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 595w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-12_04_57-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x61.png 300w\" sizes=\"auto, (max-width: 595px) 100vw, 595px\" \/><\/a><\/p>\n<p>Der <em>http In Node<\/em> wird wie folgt konfiguriert:<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/2023-01-16-11_59_09-node-red-_-192-168-178-24-mozilla-firefox\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1893\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-11_59_09-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"562\" height=\"327\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-11_59_09-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 562w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-11_59_09-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x175.png 300w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><\/a><\/p>\n<p>Das URL Feld muss dem Pfad entsprechen, der beim Anlegen der Client ID verwendet wurde. Allerdings ohne Localhost und Portnummer.<\/p>\n<p>Der Response Node wird lediglich auf Status 200 gesetzt. Der Response Node ist wichtig, um die Anfrage des Viessmann Servers korrekt abzuschlie\u00dfen!<\/p>\n<p>Bitte beachte ferner, dass der Sende- und der Empfangsteil sind <strong>nicht<\/strong> miteinander verdrahtet sind. Hier zaubert das Internet.<\/p>\n<p>Jetzt &#8211; erst jetzt &#8211; k\u00f6nnt ihr testen: Wenn alles funktioniert, sollte der <em>Debug Node<\/em> am Empfangsende den Authorization Code anzeigen wenn der Trigger auf der Sendeseite ausgel\u00f6st wurde. Der Code steckt jetzt in <span class=\"lang:js decode:true crayon-inline\">msg.payload.code<\/span>\u00a0.<\/p>\n<p>Den kompletten JSON Flow findest du am Ende des Artikels.<\/p>\n<h4 style=\"padding-left: 40px;\"><span style=\"color: #ff0000;\">Hinweise zur Fehlersuche<\/span><\/h4>\n<h5 style=\"padding-left: 40px;\">Cannot get \/authcode<\/h5>\n<p style=\"padding-left: 40px;\">Wie man manchen Kommentaren entnehmen kann, kommt es gelegentlich zu Fehlern der Art \"<em><span style=\"color: #339966;\">Cannot GET \/authcode<\/span><\/em>\".<br \/>\nDer 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 <em>Achtung<\/em> markierten Absatz weiter oben. Erst der <em>http in<\/em> Node, oben mit\u00a0 <span class=\"lang:default decode:true crayon-inline\">[get] \/authcode<\/span>\u00a0 bezeichnet, erzeugt das vom Viessmann Server ben\u00f6tigte virtuelle Verzeichnis. Gern genommen wird auch die propriet\u00e4re Adressierung bei Homeassistant, Docker oder Homematic &#8211; siehe weiter unten.<\/p>\n<h5 style=\"padding-left: 40px;\"><span style=\"font-family: monospace;\">connect ECONNREFUSED<\/span><\/h5>\n<p style=\"padding-left: 40px;\">Unter bestimmten Umst\u00e4nden, z.B. wegen einer nicht ganz standardm\u00e4\u00dfgen Konfiguration auf eurer Seite, durchl\u00e4uft Node Red eine Identit\u00e4tskrise und wei\u00df auf einmal nicht mehr, dass es selbst durch localhost aufgerufen wird. Demzufolge wird der Viessmann-Callback abgelehnt und es gibt eine Fehlermeldung der Art:<\/p>\n<p style=\"padding-left: 40px;\"><span style=\"color: #204a87; font-family: monospace;\"><span class=\"lang:default decode:true crayon-inline \">RequestError: connect ECONNREFUSED ::1:1880<\/span>\u00a0<\/span><\/p>\n<p style=\"padding-left: 40px;\"><strong>Test<\/strong>: probiert mal Folgendes:<\/p>\n<pre class=\"lang:js decode:true\" style=\"padding-left: 40px;\">[{\"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\":[]}]<\/pre>\n<p style=\"padding-left: 40px;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2523\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-11-21-11_02_34-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"1193\" height=\"256\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-11-21-11_02_34-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 1193w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-11-21-11_02_34-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x64.png 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-11-21-11_02_34-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-1024x220.png 1024w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-11-21-11_02_34-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-768x165.png 768w\" sizes=\"auto, (max-width: 1193px) 100vw, 1193px\" \/><\/p>\n<p style=\"padding-left: 40px;\">Mit dem Trigger wird ein <em>http request<\/em> angestupst, der an die Adresse <span class=\"lang:default decode:true crayon-inline \">localhost:1880\/test<\/span>\u00a0 eine belanglose Nachricht schickt. Der <em>http in<\/em> Node empf\u00e4ngt diese &#8211; vorausgesetzt localhost ist nicht blockiert &#8211; und gibt an den http request eine Nachricht zur\u00fcck, die ihr im Debugfenster lesen k\u00f6nnt. Funktioniert das nicht, erscheint eine Fehlermeldung \"<span style=\"color: #339966;\"><em>Cannot GET \/test<\/em><\/span>\".<\/p>\n<p style=\"padding-left: 40px;\">Um zu sehen, ob Node-Red \u00fcberhaupt antwortet, k\u00f6nnt ihr den gerade erzeugten Microwebserver \u00fcber einen Browser auf einem anderen Ger\u00e4t im lokalen Netz aufrufen: <span class=\"lang:default decode:true crayon-inline\">http:\/\/IPdesNodeRedServers:1880\/test<\/span> . Wenn das nicht funktioniert, hat NR ein generelles Problem oder ihr habt euch irgendwo verschrieben.<\/p>\n<p style=\"padding-left: 40px;\">Dem ECONNREFUSED Problem kann man oft abhelfen, indem man durchgehend <strong>127.0.0.1<\/strong> anstatt localhost verwendet. Logisch betrachtet ist beides dasselbe aber manchmal hilft es, anstatt des lokalen Namens, die IP Adresse zu verwenden .<\/p>\n<p style=\"padding-left: 40px;\">Daf\u00fcr die Viessmann Client ID l\u00f6schen und dort die redirect URI neu mit<\/p>\n<p style=\"padding-left: 40px;\"><span class=\"lang:default decode:true crayon-inline\">http:\/\/127.0.0.1:1880\/authcode<\/span><\/p>\n<p style=\"padding-left: 40px;\">anlegen. Dann noch die neu generierte Client ID und die neue URI in den obersten Request Node \u00fcbertragen.<\/p>\n<p style=\"padding-left: 40px;\">Dank an G\u00fcnter f\u00fcrs geduldige Ausprobieren und die R\u00fcckmeldung!<\/p>\n<h5 style=\"padding-left: 40px;\">Home Assistant:<\/h5>\n<p style=\"padding-left: 40px;\">Bei einem \"embedded Node Red\" ist die Adressierung des NR internen Servers anders.<\/p>\n<p style=\"padding-left: 40px;\">Als virtuelles NR Verzeichnis f\u00fcr den Autorisierungsvorgang haben wir weiter oben <span class=\"lang:default decode:true crayon-inline \">\/authcode<\/span>\u00a0 verwendet. Der Verzeichname\u00a0 ist beim native NR wahlfrei. Bei HA allerdings nicht! Das Verzeichnis muss <span class=\"lang:default decode:true crayon-inline \">\/endpoint\/&#8230;<\/span>\u00a0 lauten. Also z.B. <span class=\"lang:default decode:true crayon-inline \">\/endpoint\/authcode<\/span>\u00a0. Und zwar \u00fcberall:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Auf der Viessmann Seite beim Anlegen der Redirect Client URI,<\/li>\n<li>beim ersten http Request &#8211; Generieren des Authorization Codes<\/li>\n<li>beim http in \"[get]\/authcode\/<\/li>\n<li>und bei den beiden \"set payload &amp; headers\" Nodes zu erstmaligen Erzeugen des Access tokens und zum Refresh desselben.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p style=\"padding-left: 40px;\">Herzlichen Dank an Alex P. f\u00fcrs Aufzeigen der L\u00f6sung!<\/p>\n<h5 style=\"padding-left: 40px;\">IO Broker:<\/h5>\n<p style=\"padding-left: 40px;\">Ich habe mir mal die M\u00fche gemacht, und den IO Broker nebst integriertem Node-Red Adapter auf einem Raspi installiert. Abgesehen davon, dass ich den IO Broker f\u00fcr ein hoffnungslos \u00fcberladenes Klickibunti halte, hat alles astrein 1:1 funktioniert. Bei der Instanziierung darauf achen, dass die NR Portnummer 1880 gesetzt wird. L\u00e4uft auch noch der Viessmann Adapter auf dem Broker, m\u00fcssen (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\u00e4\u00df Vorschrift im Broker eine 2. URI (http:\/\/localhost:4200) angelegt werden (Angabe ohne Gew\u00e4hr).<\/p>\n<h5 style=\"padding-left: 40px;\"><strong>Docker:<\/strong><\/h5>\n<p style=\"padding-left: 40px;\">Habt ihr NR in einem Docker Container laufen, dann wird das so ohne weiteres nicht funktionieren. Docker sperrt &#8211; so habe ich es verstanden &#8211; den Zugriff auf <em>localhost<\/em>. Das m\u00fcsste erst einmal freigeschaltet werden. Wie? Keine Ahnung! Ich habe f\u00fcr 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\u00f6ren.<\/p>\n<p style=\"padding-left: 40px;\">Noch eine M\u00f6glichkeit (mangels Docker Installation blind geraten): Wenn Docker <em>localhost<\/em> sperrt, dann klappt es vielleicht mit <span class=\"lang:default decode:true crayon-inline\">127.0.0.1<\/span> anstatt localhost. Siehe <em>connect ECONNREFUSED<\/em> weiter oben. <span style=\"color: #ff0000;\">Mir bitte unbedingt Bescheid geben, was daraus geworden ist.<\/span><\/p>\n<p style=\"padding-left: 40px;\"><strong>Oder dieses Link hier<\/strong>: <a href=\"https:\/\/www.kodinerds.net\/thread\/66591-docker-container-unter-hostname-nicht-erreichbar\/\" target=\"_blank\" rel=\"noopener\">Docker Container unter Hostname nicht erreichbar<\/a><br \/>\nZitat:<em><br \/>\n\"Haben Docker Container nicht eine eigene \"virtuelle\" Netzwerkinfrastruktur, die man erst nach au\u00dfen routen muss?<\/em><br \/>\n<em>Also sprich sowas wie (Beispiel nginx Server): <span class=\"lang:default decode:true crayon-inline\">docker run &#8211;name mynginx -d -p 8080:80 nginx<\/span> Das macht nginx nach au\u00dfen (localhost) auf Port 8080 erreichbar.\"<br \/>\n<\/em>Zitat Ende<em>.<\/em><\/p>\n<h5 style=\"padding-left: 40px;\">Homematic<\/h5>\n<p style=\"padding-left: 40px;\">Von Oliver kam folgender Hinweis zur Homematic:<\/p>\n<p style=\"padding-left: 40px;\"><em>\"Mit Homematic (in meinem Fall Raspberrymatic) funktioniert das Ganze in so fern, dass ich die ausgelesenen Werte in Variablen schreibe und so an das System \u00fcbergebe. Damit lassen sich dann wie gewohnt Programme etc. auf Basis der Viessmann-daten anlegen.<\/em><\/p>\n<p style=\"padding-left: 40px;\"><em>Der Kniff war wohl bei der Redirect url den Pfad mit anzugeben den der authcode auf dem lokalen System bekommt bei mir \/addons\/red\/authcode und diesen dann beim Client mit einzutragen. Die variablen lassen sich dann in node red einfach mit dem Homematic Plugin mittels Value Node \u00fcbergeben.\"<\/em><\/p>\n<h5 style=\"padding-left: 40px;\">Aktuelle Node Red Version<\/h5>\n<p style=\"padding-left: 40px;\"><strong>Noch was<\/strong>: seht zu, dass ihr die aktuellste Version von Node Red auf eurer Kiste laufen habt. Stand November 2023 ist das Version 3.1.0<\/p>\n<h5 style=\"padding-left: 40px;\">Feedback, bitte:<\/h5>\n<p style=\"padding-left: 40px;\">Ich gebe mir alle M\u00fche, meinen Lesern bei der Fehlersuche weiterzuhelfen.<br \/>\nDaher eine <strong>Bitte:<\/strong> gebt genau an, welcher Node den Fehler ausgibt, ferner die komplett ausgeklappte Fehlermeldung im Debugfenster rechts. Idealerweise auch euren &#8211; anonymisierten &#8211; Flow per Mail schicken. (Adresse steht im Impressum). Gut zu wissen w\u00e4re ebenfalls, ob ihr Node-Red direkt auf eurem Rechner betreibt oder gekapselt in Docker, IO Broker, Home Assistant etc.<br \/>\nUnd noch eine <strong>Bitte<\/strong>: Immer wieder zermartere ich mein Hirn und gebe ich Hinweise, wie ein Problem zu l\u00f6sen sein k\u00f6nnte. Vom Adressaten bekomme ich meist&#8230; <strong>nichts<\/strong>! Kein Feedback, Funkstille. Damit stochere ich mit 'ner Stange im Nebel, da ich nicht wei\u00df, ob mein Tipp geholfen hat. Also, <strong>bitte<\/strong> <strong>gebt mir Feedback<\/strong> und ich gebe mein Bestes, euch weiterzuhelfen. Auch wenn ihr eine L\u00f6sung f\u00fcr ein Problem gefunden habt, w\u00e4re ich f\u00fcr eine Mitteilung dankbar.<\/p>\n<h3>Access Token initial erzeugen<\/h3>\n<p>Wenn ihr jetzt den Authcode erzeugen konntet, geht's weiter:<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/index.php\/1_zugang_api\/cacicala_5-1664025783050\/\" rel=\"attachment wp-att-1895\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1895\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_5-1664025783050-1024x224.png\" alt=\"\" width=\"604\" height=\"132\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_5-1664025783050-1024x224.png 1024w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_5-1664025783050-300x66.png 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_5-1664025783050-768x168.png 768w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/CaCicala_5-1664025783050.png 1091w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/a><\/p>\n<p>Die drei Nodes oben links kennen bzw. haben wir schon.<\/p>\n<p>Kommen wir zum <em>Funktionsnode<\/em> set <em>payload &amp; headers, <\/em>der den darauf folgenden <em>http Request Node<\/em> mit Daten aufl\u00e4dt. Der im vorherigen Schritt gewonnene Code wird per Stringvariable hinten angeh\u00e4ngt.<br \/>\nAuch hier kommt wieder die Client ID an die entsprechende Stelle des Aufrufstrings &#8211; wird gerne vergessen, wenn man mal die ClientID neu erzeugt hat.<\/p>\n<pre class=\"lang:js decode:true\">msg.payload = 'grant_type=authorization_code&amp;client_id=DeineclientIDKommtHierhin&amp;redirect_uri=http:\/\/localhost:1880\/authcode&amp;code_verifier=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&amp;code=' + msg.payload.code;\r\nmsg.headers = {};\r\nmsg.headers['Content-Type'] = 'application\/x-www-form-urlencoded';\r\n\r\nreturn msg;<\/pre>\n<p>Anders als der oben verwendete <em>http Request<\/em> ist der hier verwendete <em>http Request Node<\/em> ein <strong>POST Request<\/strong>, d.h. es werden Daten im http header anstatt in der URL transportiert. Er wird wie folgt konfiguriert. Darauf achten, dass die R\u00fcckgabe als \"Ein parsed JSON Objekt\" erfolgen soll.<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3597 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg\" alt=\"\" width=\"600\" height=\"444\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg 600w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12-300x222.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>Auch hier sollte wieder v3 anstatt v2 verwendet werden.<\/p>\n<p>Wenn alles funktioniert, dann enth\u00e4lt das zur\u00fcck 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.<\/p>\n<p>Mit dem Access Token k\u00f6nnten wir nun 3600 Sekunden oder eine Stunde lang arbeiten bevor es verf\u00e4llt.<\/p>\n<p>Sinnvollerweise packen wir die beiden Token in Flow Variable um sie weiter zu verwenden. Hast du die Viessmann Logik auf mehreren Node-Red Bl\u00e4tter verteilt, sollten sie in Global anstatt in Flow Variablen untergebracht werden.<\/p>\n<p>Das geschieht am einfachsten mit einem Change Node:<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/index.php\/1_zugang_api\/2023-01-16-13_44_26-node-red-_-192-168-178-24-mozilla-firefox\/\" rel=\"attachment wp-att-1905\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1905 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-13_44_26-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"569\" height=\"538\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-13_44_26-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 569w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-13_44_26-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x284.png 300w\" sizes=\"auto, (max-width: 569px) 100vw, 569px\" \/><\/a><\/p>\n<p style=\"padding-left: 40px;\"><span style=\"color: #808080;\">Variable k\u00f6nnen auch innerhalb eines Function Nodes mit <span class=\"lang:js decode:true crayon-inline\">flow.set(\"FlowVariablenname\", meineVariable)<\/span>\u00a0 gesetzt werden. Das macht vor allem innnerhalb komplexerer Funktionsbl\u00f6cke Sinn.<br \/>\nAbgerufen werden die Flow Variablen mit einem Kommando der Art:<br \/>\n<span class=\"lang:js decode:true crayon-inline \">var meineVariable = flow.get(\"FlowVariablenname\");<\/span><br \/>\n<\/span><\/p>\n<p>Sind wir wie oben beschrieben vorgegangen, k\u00f6nnen wir jetzt \u00fcberall innerhalb des Flows (Tabellenblatt) auf die Tokens zugreifen.<\/p>\n<h3>Statische Parameter<\/h3>\n<p>Um mit der API zu arbeiten, ben\u00f6tigen wir noch drei statische Werte, welche am Ger\u00e4t h\u00e4ngen und sich normalerweise nie \u00e4ndern.<\/p>\n<p>Wie man sie bekommt, ist in der Viessmann Doku beschrieben oder man nutzt diesen JSON Flow f\u00fcr Node Red:<\/p>\n<p>Achtung: per Februar 2025 hat sich die Version des sogenannten Endpoints ge\u00e4ndert. Anstatt v1 hei\u00dft es jetzt v2. Die nachfolgenden Flows sind entsprechend aktualisiert.<\/p>\n<pre class=\"height-set:true height:250 lang:js decode:true\">[{\"id\":\"ca72ec87d75662bc\",\"type\":\"http request\",\"z\":\"640d4a161fb8fa28\",\"name\":\"Installation ID\",\"method\":\"GET\",\"ret\":\"obj\",\"paytoqs\":\"ignore\",\"url\":\"https:\/\/api.viessmann-climatesolutions.com\/iot\/v2\/equipment\/installations\",\"tls\":\"\",\"persist\":false,\"proxy\":\"\",\"insecureHTTPParser\":false,\"authType\":\"\",\"senderr\":false,\"headers\":[],\"x\":680,\"y\":480,\"wires\":[[\"219816b1d2aea88e\"]]},{\"id\":\"c9eda37e6defab80\",\"type\":\"function\",\"z\":\"640d4a161fb8fa28\",\"name\":\"Auth Header\",\"func\":\"let atoken = flow.get('accessToken')\\nmsg.headers = {\\n    Authorization: \\\"Bearer \\\"+ atoken\\n}\\nreturn msg;\\n\\n\",\"outputs\":1,\"timeout\":\"\",\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":[],\"x\":450,\"y\":480,\"wires\":[[\"ca72ec87d75662bc\"]]},{\"id\":\"6981e40c1dcfb357\",\"type\":\"http request\",\"z\":\"640d4a161fb8fa28\",\"name\":\"Gateway Serial\",\"method\":\"GET\",\"ret\":\"obj\",\"paytoqs\":\"ignore\",\"url\":\"https:\/\/api.viessmann-climatesolutions.com\/iot\/v2\/equipment\/gateways\",\"tls\":\"\",\"persist\":false,\"proxy\":\"\",\"insecureHTTPParser\":false,\"authType\":\"\",\"senderr\":false,\"headers\":[],\"x\":680,\"y\":520,\"wires\":[[\"6f33a94aed463e97\"]]},{\"id\":\"219816b1d2aea88e\",\"type\":\"change\",\"z\":\"640d4a161fb8fa28\",\"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\":880,\"y\":480,\"wires\":[[\"f7a004b60523f469\"]]},{\"id\":\"6f33a94aed463e97\",\"type\":\"change\",\"z\":\"640d4a161fb8fa28\",\"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\":880,\"y\":520,\"wires\":[[\"dc35dc89a8567d81\"]]},{\"id\":\"f7a004b60523f469\",\"type\":\"function\",\"z\":\"640d4a161fb8fa28\",\"name\":\"Auth Header\",\"func\":\"let atoken = flow.get('accessToken')\\nmsg.headers = {\\n    Authorization: \\\"Bearer \\\"+ atoken\\n}\\nreturn msg;\\n\\n\",\"outputs\":1,\"timeout\":\"\",\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":[],\"x\":450,\"y\":520,\"wires\":[[\"6981e40c1dcfb357\"]]},{\"id\":\"8ebef3e8da13cc88\",\"type\":\"http request\",\"z\":\"640d4a161fb8fa28\",\"name\":\"DeviceID\",\"method\":\"GET\",\"ret\":\"obj\",\"paytoqs\":\"ignore\",\"url\":\"https:\/\/api.viessmann-climatesolutions.com\/iot\/v2\/equipment\/installations\/{{iid}}\/gateways\/{{gws}}\/devices\/ \",\"tls\":\"\",\"persist\":false,\"proxy\":\"\",\"insecureHTTPParser\":false,\"authType\":\"\",\"senderr\":false,\"headers\":[],\"x\":660,\"y\":560,\"wires\":[[\"46022befd51c1c67\",\"1587e2fa47d77eaf\"]]},{\"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\":\"let 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,\"timeout\":\"\",\"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;\\nlet idx = deviceArray.findIndex( (element) =&gt; 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\":[[\"798ae186e9020315\"]]}]<\/pre>\n<p>Es bleibt dir \u00fcberlassen, wo du diesen Teil einbaust. Im Prinzip kann man die drei Parameter <em>Installation ID, Gateway Serial<\/em> und <em>Device ID<\/em> ein einziges Mal abfragen und dann als fixe Werte, also \"hard coded\" weiterverarbeiten. Oder &#8211; so habe ich es gemacht &#8211; 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.<\/p>\n<p style=\"padding-left: 40px;\"><span style=\"color: #808080;\">Erl\u00e4uterung der drei statischen Parameter:<br \/>\n<strong>InstallationID<\/strong> identifiziert eure gesamte Anlage mit allen Komponenten, Therme, W\u00e4rmepumpe, Photovoltaik etc. Normalerweise gibt es pro Haus\/Wohnung nur eine InstallationID<\/span>.<br \/>\n<span style=\"color: #808080;\"><strong>GatewaySerial<\/strong>: Hat man nur einen Viessmann W\u00e4rme-\/Energieerzeuger, dann gibt es in der Regel auch nur eine einzige GatewaySerial. Hat man deren mehrere, dann hat jeder modernere W\u00e4rmeerzeuger eine eigene WiFi Komponente (oder bei Legacy Ger\u00e4ten ein VitoConnect K\u00e4stchen).<\/span><br \/>\n<span style=\"color: #808080;\">Sind z.B. sowohl WP als auch PV installiert, musst du, um die gesamte Anlage \u00fcber die API anzusprechen,\u00a0 beide GatewaySerials heranziehen und die Abfragen bzw. Befehle f\u00fcr die Ger\u00e4te dem jeweiligen Gateway zuordnen. Auch bei einer sp\u00e4teren Nachr\u00fcstung (z.B. mit PV) muss die Programmierung entsprechend <\/span><span style=\"color: #808080;\">angepasst werden.<br \/>\n<\/span><span style=\"color: #808080;\">Jedes Gateway hat wiederum mehrere <strong>Device ID<\/strong>s. Relevant\u00a0 bzw. nutzbar f\u00fcr unsere\u00a0 Anwendungsf\u00e4lle ist das Device Nummer \"0\" &#8211; der W\u00e4rme- oder Energieerzeuger.<\/span><br \/>\n<span style=\"color: #808080;\">Nr \"1\" ist das Gateway selbst, hier gibt es keine Features, die abgerufen werden k\u00f6nnen.<br \/>\n<\/span><span style=\"color: #808080;\">Nr. \"2\" ist virtuell und bei meiner Therme etwas, das sich \"HeatDemandControl\" nennt und wohl die Sensorik (?) darstellt. Ebenfalls keine Features.<br \/>\nDevice ID \"3\" ist auch virtuell und die Einzelraumsteuerung welche in der Vitotronic wohl auch dann angelegt ist, wenn physisch es gar keine Einzelraumsteuerung gibt.<br \/>\n<strong>Update Anfang 2024<\/strong>: Leider stimmt diese Reihenfolge nicht mehr generell. Siehe untenstehendes Kapitel.<br \/>\n<\/span><\/p>\n<h4 style=\"padding-left: 40px;\"><span style=\"color: #808080;\"><br \/>\n<strong><span style=\"color: #ff0000;\">ACHTUNG NEU 2024<\/span><\/strong><\/span><\/h4>\n<p style=\"padding-left: 40px;\"><strong>Nur relevant f\u00fcr bereits bestehende Nutzer dieser Anleitung:<\/strong> Warum auch immer hat Viessmann etwas an der Position der DeviceID ge\u00e4ndert. Die Abfrage nach der Device ID in obigem Flow bzw. die Abfrage <span style=\"color: #808080;\"><span class=\"lang:js decode:true crayon-inline\">https:\/\/api.viessmann-climatesolutions.com\/iot\/v2\/equipment\/installations\/{{iid}}\/gateways\/{{gws}}\/devices\/<\/span> <\/span>generiert eine Payload bestehend aus einem Array mit vier Elementen &#8212; msg.payload.data[0] bis data[3]. Bisher stand die Device ID in msg.payload.data[0].id, <strong>seit ca. Anfang 2024 steckt die DeviceID bei mir in msg.payload.data[1].id<br \/>\n<\/strong><\/p>\n<p style=\"padding-left: 40px;\"><span style=\"color: #808080;\"><strong><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-2649 size-large\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987-1024x259.jpg\" alt=\"\" width=\"604\" height=\"153\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987-1024x259.jpg 1024w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987-300x76.jpg 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987-768x194.jpg 768w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/deviceID-e1706867576987.jpg 1205w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/a><\/strong><\/span><span style=\"color: #000000;\"><br \/>\n<\/span><span style=\"color: #000000;\"><strong>Leider ist das aber nicht bei jedem so.<\/strong> Bei W\u00e4rmepumpen kann es zum Beispiel sein, dass die deviceID im dritten Element .data[2] steckt. Auch wenn es etwas nassforsch ist, empfehle ich,\u00a0 generell einfach \"0\" als DeviceID in euren Flows zu verwenden anstatt das regelm\u00e4\u00dfig bei Viessmann abzufragen.<\/span><span style=\"color: #808080;\"><strong><br \/>\n<\/strong><\/span><\/p>\n<p style=\"padding-left: 40px;\">F\u00fcr alle Puristen, die die Device ID trotzdem gerne bei der API abfragen, hier noch der Flow, der eine hoffentlich betriebssichere Abfrage erm\u00f6glicht. 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.<\/p>\n<p style=\"padding-left: 40px;\">Bei Fotovoltaik, L\u00fcftung oder K\u00fchlung m\u00fcsst ihr nachsehen, welcher deviceType verwendet wird und den \"locate deviceID\" Node entsprechend anpassen.<\/p>\n<p style=\"padding-left: 40px;\"><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2024\/02\/deviceType-e1706958327208.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2655\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2024\/02\/deviceType-e1706958327208.png\" alt=\"\" width=\"972\" height=\"69\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2024\/02\/deviceType-e1706958327208.png 972w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2024\/02\/deviceType-e1706958327208-300x21.png 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2024\/02\/deviceType-e1706958327208-768x55.png 768w\" sizes=\"auto, (max-width: 972px) 100vw, 972px\" \/><\/a><\/p>\n<pre class=\"height-set:true height:25 lang:js decode:true\">[{\"id\":\"8ebef3e8da13cc88\",\"type\":\"http request\",\"z\":\"640d4a161fb8fa28\",\"name\":\"DeviceID\",\"method\":\"GET\",\"ret\":\"obj\",\"paytoqs\":\"ignore\",\"url\":\"https:\/\/api.viessmann-climatesolutions.com\/iot\/v2\/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) =&gt; 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\"]]}]<\/pre>\n<h3>Refresh alle 3600 Sekunden<\/h3>\n<p>Jetzt endlich k\u00f6nnen wir mit der API arbeiten. Aber nach einer Stunde ist der Spa\u00df vorbei, das Access Token ist abgelaufen. Um nun nicht wieder die gesamte obige Routine durchlaufen zu m\u00fcssen, gibt es eine Abk\u00fcrzung mit dem Refresh Token.<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" rel=\"attachment wp-att-1908\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1908 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"1419\" height=\"156\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 1419w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x33.png 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-1024x113.png 1024w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_14_17-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-768x84.png 768w\" sizes=\"auto, (max-width: 1419px) 100vw, 1419px\" \/><\/a>Hier wird der Trigger &#8211; auf \"wiederhole automatisch alle 59 Minuten\" eingestellt,<\/p>\n<p>Der Funktionsnode hat folgenden Inhalt:<\/p>\n<pre class=\"lang:js decode:true\">let refreshToken=flow.get('refreshToken');\r\nmsg.payload = 'grant_type=refresh_token&amp;client_id=HierKommtDeine ClientIDHin&amp;refresh_token=' + refreshToken;\r\nmsg.headers = {};\r\nmsg.headers['Content-Type'] = 'application\/x-www-form-urlencoded';\r\nreturn msg;<\/pre>\n<p>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\u00e4ngt.<\/p>\n<p>Es folgt ein http Request Node mit folgender Konfiguration:<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3597\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg\" alt=\"\" width=\"600\" height=\"444\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12.jpg 600w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/vcs12-300x222.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>Ferner noch ein Change Node, welcher die zur\u00fcckgegebene Payload in die Access_Token Variable schreibt.<\/p>\n<p><a href=\"https:\/\/www.rustimation.eu\/index.php\/1_zugang_api\/2023-01-16-14_19_33-node-red-_-192-168-178-24-mozilla-firefox\/\" rel=\"attachment wp-att-1910\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1910\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_19_33-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png\" alt=\"\" width=\"566\" height=\"388\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_19_33-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox.png 566w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-01-16-14_19_33-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-300x206.png 300w\" sizes=\"auto, (max-width: 566px) 100vw, 566px\" \/><\/a><\/p>\n<p>Und hier der zugeh\u00f6rige JSON Flow zum importieren:<\/p>\n<pre class=\"lang:js decode:true\">[{\"id\":\"794bf2047ed74376\",\"type\":\"function\",\"z\":\"8da86d39b73b390b\",\"name\":\"set payload and headers\",\"func\":\"let refreshToken=flow.get('refreshToken');\\nmsg.payload = 'grant_type=refresh_token&amp;client_id=DeineClientIDkommtHierhin&amp;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-climatesolutions.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\"]]}]<\/pre>\n<p>Bisherige Nutzer achten wieder auf \"v3\" in der URL des Request Nodes.<\/p>\n<p>Wird der Flow regelm\u00e4\u00dfig ausgef\u00fchrt, hat man immer ein g\u00fcltiges Access Token.<\/p>\n<h3>Refresh nach 180 Tagen erneuern<\/h3>\n<p>&#8230;zumindest f\u00fcr 180 Tage. Dann verf\u00e4llt auch das Refresh Token und wir m\u00fcssen tats\u00e4chlich wieder beim Kapitel <em><strong>Authcode abrufen<\/strong><\/em> einsteigen. Die Client ID muss daf\u00fcr <strong>nicht<\/strong> neu erzeugt werden. Das Triggern der Schritte kann nat\u00fcrlich auch automatisch erfolgen, soda\u00df es keinerlei menschlichen Eingriffs mehr bedarf. Das ist z.B. m\u00f6glich, 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:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2283 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-02-20-09_54_23-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-e1676884305846.png\" alt=\"\" width=\"633\" height=\"445\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-02-20-09_54_23-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-e1676884305846.png 633w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/2023-02-20-09_54_23-Node-RED-_-192.168.178.24-\u2013-Mozilla-Firefox-e1676884305846-300x211.png 300w\" sizes=\"auto, (max-width: 633px) 100vw, 633px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Siehe auch unten abgebildeten Flow mit Kommentar.<\/p>\n<p>Was auch m\u00f6glich w\u00e4re, aber nicht so betriebssicher,\u00a0 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\u00e4uft, damit der Trigger komplett abl\u00e4uft. In 180 Tagen kann eine Menge passieren&#8230;<\/p>\n<p>Im Prinzip spricht auch wenig dagegen, den \"Refresh Token aktualisieren\" Zyklus alle 24 Stunden oder so aufzurufen.<\/p>\n<p>&nbsp;<\/p>\n<h3>Gesamter Flow<\/h3>\n<figure id=\"attachment_2282\" aria-describedby=\"caption-attachment-2282\" style=\"width: 1004px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/refresh_refresh_token-e1676884075807.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2282 size-full\" src=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/refresh_refresh_token-e1676884075807.jpg\" alt=\"\" width=\"1004\" height=\"720\" srcset=\"https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/refresh_refresh_token-e1676884075807.jpg 1004w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/refresh_refresh_token-e1676884075807-300x215.jpg 300w, https:\/\/www.rustimation.eu\/wordpress\/wp-content\/uploads\/2023\/01\/refresh_refresh_token-e1676884075807-768x551.jpg 768w\" sizes=\"auto, (max-width: 1004px) 100vw, 1004px\" \/><\/a><figcaption id=\"caption-attachment-2282\" class=\"wp-caption-text\">Gesamter Autorisierungsflow mit Restart nach Ablauf des Refresh Tokens<\/figcaption><\/figure>\n<h3>JSON f\u00fcr dieses Kapitel<\/h3>\n<pre class=\"lang:js decode:true\">[{\"id\":\"41f5e66ea1123715\",\"type\":\"function\",\"z\":\"edb7360203dfca8a\",\"name\":\"set payload and headers\",\"func\":\"let refreshToken=flow.get('refreshToken');\\nmsg.payload = 'grant_type=refresh_token&amp;client_id=deineClientID&amp;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-climatesolutions.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-climatesolutions.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 &amp; headers\",\"func\":\"msg.payload = 'grant_type=authorization_code&amp;client_id=deineClientID&amp;redirect_uri=http:\/\/localhost:1880\/authcode&amp;code_verifier=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&amp;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 --&gt;\",\"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-climatesolutions.com\/iot\/v2\/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-climatesolutions.com\/iot\/v2\/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-climatesolutions.com\/iot\/v2\/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-climatesolutions.com\/idp\/v3\/authorize?client_id=deineClientID&amp;redirect_uri=http:\/\/localhost:1880\/authcode&amp;response_type=code&amp;code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&amp;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) =&gt; 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\"]]}]\r\n<\/pre>\n<p>Weiter gehts mit dem n\u00e4chsten Kapitel\u00a0 <a href=\"https:\/\/www.rustimation.eu\/index.php\/vicare-daten-abfragen\/\">Daten abfragen und visualisieren<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Zugriff auf die Viessmann API mit Node-Red. Die sehr komplexe Anmeldelogik wird durch Node-Red deutlich vereinfacht. Schritt f\u00fcr Schrittt Anleitung.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53,151,159],"tags":[166,167,168,165],"class_list":["post-1855","post","type-post","status-publish","format-standard","hentry","category-iot","category-node-red","category-viessmann-api","tag-authentifizierung","tag-refresh","tag-token","tag-zugriff"],"_links":{"self":[{"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/posts\/1855","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/comments?post=1855"}],"version-history":[{"count":1,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/posts\/1855\/revisions"}],"predecessor-version":[{"id":3720,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/posts\/1855\/revisions\/3720"}],"wp:attachment":[{"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/media?parent=1855"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/categories?post=1855"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rustimation.eu\/index.php\/wp-json\/wp\/v2\/tags?post=1855"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}