Während der Woche der Wärmepumpe haben Sie bundesweit die Möglichkeit, die innovative Wärmepumpentechnologie näher kennenzulernen. Mit über 50 Informationsveranstaltungen beteiligt sich Viessmann Climate Solutions an der Aktionswoche und lädt Sie herzlich ein – vor Ort oder online – dabei zu sein.
Mehr erfahren →The ViCare App is nice and easy to use, however not really good at visualizing things.
So I chose Node Red to construct a number of dashboards for my Vitodens installation that has additional Viessmann thermal panels and a fireplace attached to the heating system's 1000 litre buffer.
Node-Red allows constructing simple to quite complex data-flows with only a minimal programming effort. One of the key features is the construction of dashboards to visualize and manipulate data without in depth knowledge of html, CSS etc. Basic Javascript experience is helpful however.
I'm just a hobbyist, no professional programmer so bear with me in case something seems strange, unclear or too trivial.
Refreshing the Access Token
I am assuming that you already have generated an access token and further on the static refresh token. So, we can start by enabling Node Red to refresh the access token regularly and in time before it expires - e.g., every 59 minutes. See refreshAccessToken.json below.
Flow variables accessToken, deviceID, installationID, and gatewaySerial are used to store the respective values. The latter three values are static and are derived from the “getting started” preparation steps. In the example shown here, I have used generic values.
The “Extract Refresh Token” branch is for informational purposes only.
Request Authorization
All of the variables necessary for authorizing the user are used in my “universal header node”. They prime the http request that is retrieving data from the API. It is a function node consisting of the following Java Script snippet:
var atoken = flow.get('accessToken')
msg.headers = {Authorization: "Bearer "+ atoken}
msg.installationID = flow.get('installationID');
msg.gatewaySerial = flow.get('gatewaySerial');
msg.deviceId = flow.get('deviceID');
return msg;
No matter by which request you retrieve data from the API using Node-Red, the method is always through a http request node.
Feature overview
This is a good continuation point after you’ve solved the preliminaries. The Feature Overview contains all parameters that are available from your specific installation – i.e. it varies from customer to customer. It helps to select the features that you want to observe and/or manipulate.
The timestamp is used to trigger the flow; the universal header is described above; the http request “Read Feature List” calls the URL https://api.viessmann.com/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatewaySerial... and is configured as follows:
The msg.payload of debug node “Feature List” contains a large JSON structure that can be analysed by using the debug feature of Node Red. Alternatively a JSON Viewer can be used (Firefox, Notepad++ with JSON plugin etc.)
See attached: FeatureOverviewRequest.json
Reading only few datapoints
As you probably know, there is a an access limitation of 1440 per 24h. If you’re interested in a few data points only and don’t need to update your data very often, direct feature access by URL is the easiest way.
To retrieve the common supply temperature for example, the http request node “Read Feature” uses the following URL: https://api.viessmann-platform.io/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatew...
The rest of the http request node is configured as in the chapter above.
As a result, the API delivers a small JSON object from which we can extract the datapoint of interest by using another function node:
msg.payload=msg.payload.data.properties.value.value;
msg.topic="Common Supply";
return msg;
The msg.topic is optional but comes in handy when generating multi value graph charts.
See attached file: singleRequest.json
If you would trigger this request every minute, you’d use up all the 1440 accesses per day; furthermore, you wouldn’t be able to refresh the access token anymore. I’ve been told, also the Vicare App would be blocked – to be verified.
Reading more datapoints more often
Since the installation features requests returns all datapoints available for your specific installation in one go, you can access many more datapoints by performing only one single request.
In my specific case the installation features JSON consists of 165kB which creates quite a big data footprint in relation to the data actually used.
The first 3 nodes are identical to the ones in chapter Feature Overview
The Feature JSON structure mainly consists of a data array with – in my case – 150 elements. You could now address each feature of interest by using its specific index.
WW Solar would have index 92 and can be extracted like msg.payload=msg.payload.data[92].properties.value.value;
However, the index is different for each installation and is prone to vary in case Viessmann decides to add new datapoints to the API.
In order to be reliable, we have to parse the JSON to find the appropriate elements. This can be achieved by the findIndex function of Javascript. It retrieves the index number for any given feature name which is then used to access the feature:
featureArray=msg.payload.data;
idx = featureArray.findIndex((element) => element.feature === 'heating.solar.sensors.temperature.dhw');
msg.payload=msg.payload.data[idx].properties.value.value;
msg.topic = "WWSolar"; //optional - necessary for multi value charts
return msg;
I hope that you find this useful. Thanks to Michael Hanna for his support!
Christoph Krzikalla
JSON files for copy & paste into Node Red - the forum doesn't allow upload of text or JSON files...
refreshAccessToken.json
[
{
"id": "eb3f132b.f55c48",
"type": "tab",
"label": "Heatingsystem",
"disabled": false,
"info": ""
},
{
"id": "8e64bcb1.3a6198",
"type": "function",
"z": "eb3f132b.f55c48",
"name": "set payload and headers",
"func": "msg.payload = \"grant_type=refresh_token&client_id=yourClientID&refresh_token=theRefreshToken\";\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded';\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 410,
"y": 160,
"wires": [
[
"8eed9ce.e975a6"
]
]
},
{
"id": "2f0fb613.30912a",
"type": "inject",
"z": "eb3f132b.f55c48",
"name": "Refresh Access Token",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "3540",
"crontab": "",
"once": true,
"onceDelay": "",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 170,
"y": 160,
"wires": [
[
"8e64bcb1.3a6198"
]
]
},
{
"id": "8eed9ce.e975a6",
"type": "http request",
"z": "eb3f132b.f55c48",
"name": "refreshtoken",
"method": "POST",
"ret": "obj",
"paytoqs": "ignore",
"url": "https://iam.viessmann.com/idp/v2/token",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 610,
"y": 160,
"wires": [
[
"caf45d2a.5b914"
]
]
},
{
"id": "caf45d2a.5b914",
"type": "function",
"z": "eb3f132b.f55c48",
"name": "Extract Token",
"func": "msg.payload=msg.payload.access_token;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 820,
"y": 160,
"wires": [
[
"6c93aa04.283ec4",
"b330b072.f48968"
]
]
},
{
"id": "6c93aa04.283ec4",
"type": "debug",
"z": "eb3f132b.f55c48",
"name": "access_token",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1040,
"y": 220,
"wires": []
},
{
"id": "b330b072.f48968",
"type": "change",
"z": "eb3f132b.f55c48",
"name": "",
"rules": [
{
"t": "set",
"p": "accessToken",
"pt": "flow",
"to": "payload",
"tot": "msg"
},
{
"t": "set",
"p": "deviceID",
"pt": "flow",
"to": "0",
"tot": "str"
},
{
"t": "set",
"p": "installationID",
"pt": "flow",
"to": "123456",
"tot": "num"
},
{
"t": "set",
"p": "gatewaySerial",
"pt": "flow",
"to": "yourGatewaySerialNo",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1040,
"y": 160,
"wires": [
[]
]
}
]
featureOverviewRequest.json
[
{
"id": "28ce4ad9.56b3ee",
"type": "inject",
"z": "60e7ff21.b1ce48",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 140,
"y": 480,
"wires": [
[
"efd9bd12.35253"
]
]
},
{
"id": "7c34263e.a7791",
"type": "http request",
"z": "60e7ff21.b1ce48",
"name": "Read Feature List",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "https://api.viessmann.com/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices/{{deviceId}}/features/",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 550,
"y": 480,
"wires": [
[
"92f53cc2.4ba79"
]
]
},
{
"id": "efd9bd12.35253",
"type": "function",
"z": "60e7ff21.b1ce48",
"name": "Universal Header",
"func": "var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.installationID = flow.get('installationID');\nmsg.gatewaySerial = flow.get('gatewaySerial');\nmsg.deviceId = flow.get('deviceID');\nreturn msg;\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 330,
"y": 480,
"wires": [
[
"7c34263e.a7791"
]
]
},
{
"id": "92f53cc2.4ba79",
"type": "debug",
"z": "60e7ff21.b1ce48",
"name": "Feature List (JSON)",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 780,
"y": 480,
"wires": []
}
]
singleRequest.json
[
{
"id": "619f461a.3caf38",
"type": "http request",
"z": "60e7ff21.b1ce48",
"name": "Read Feature",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "https://api.viessmann-platform.io/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices/0/features/heating.boiler.sensors.temperature.commonSupply",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 600,
"y": 1600,
"wires": [
[
"ea81b906.b45e3"
]
]
},
{
"id": "996c1677.deb32",
"type": "debug",
"z": "60e7ff21.b1ce48",
"name": "Example",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 920,
"y": 1600,
"wires": []
},
{
"id": "954542bb.556178",
"type": "function",
"z": "60e7ff21.b1ce48",
"name": "Universal Header",
"func": "var atoken = flow.get('accessToken')\nmsg.headers = {\n Authorization: \"Bearer \"+ atoken\n}\nmsg.installationID = flow.get('installationID');\nmsg.gatewaySerial = flow.get('gatewaySerial');\nmsg.deviceId = flow.get('deviceID');\nreturn msg;\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 410,
"y": 1600,
"wires": [
[
"619f461a.3caf38"
]
]
},
{
"id": "8ab5e8c0.40a968",
"type": "inject",
"z": "60e7ff21.b1ce48",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 1600,
"wires": [
[
"954542bb.556178"
]
]
},
{
"id": "ea81b906.b45e3",
"type": "function",
"z": "60e7ff21.b1ce48",
"name": "Extract Value",
"func": "msg.payload=msg.payload.data.properties.value.value;\nmsg.topic=\"Common Supply\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 770,
"y": 1600,
"wires": [
[
"996c1677.deb32"
]
]
}
]
Gelöst! Gehe zu Lösung.
Hallo qwert089,
prima, um so besser!! Das hilft den Kollegen mit alten Heizungen bzw. denen die nicht bis Q2/2023 warten wollen..
viele Grüße
Chris
Vielen Dank für deine Infos!
Aber genau das (lange Winterabende...) möchte ich vermeiden.
Und was "Vitocontrol mit 22 Jahre alter Vitodens 200" angeht: Die Frage hatte ich schon gestellt; sie wurde wie folgt beantwortet (funktioniert!):
Kann es sein, dass das nicht stimmt?
Wie kann ich das genau herausfinden? Viessmann Kundendienst fragen?
Danke und Gruß
Thomas
Also von Vcontrol bin auf FHEM gekommen. Und das läuft zwar auf meinem Raspberry, aber ich nutze es nicht weil ich mit dem Syntax und Perl überhaupt nicht zurecht komme. Also das wir vermutlich nix.
Aber ich schau jetzt mal hier weiter:
https://github.com/openv/openv/wiki/Bauanleitung-USB
Das steht auch was von kaufen...
@qwert089Vielen Dank für diesen Hinweis!
WB2 scheint auch zu funktionieren
https://github.com/openv/openv/issues/437
Da hat auch jemand eine zip-Kopie seines Raspberry hoch geladen mit den XML der Adressen der DP
Hallo Thomas,
ich meinte natürlich Vitoconnect und nicht Votocontrol.
Bei Löbbeshop habe ich folgende Aussage zur OPTO2 gefunden:
Ob deine Anlage mit der OPTO1 funktioniert, kann ich nicht sagen.
Meine Herangehensweise wäre, erst mal ein Optolink Kabel kaufen und dann experimentieren, was du da an Daten rausziehen kannst. Im Netz steht ja so Einiges darüber...
Viele Grüße
Chris
Mittlerweile habe ich einige meiner Tutorials auf Deutsch umgestellt, aktualisiert und auf meinem kleinen Tech-Blog veröffentlicht. Ihr findet das auf https://rustimation.eu - wird je nach Erkenntnisfortschritt erweitert und ergänzt.
Chris
Hallo,
vielen Dank für die MQTT-Tutorials. Leider ist die Webseite https://rustimation.eu nicht erreichbar ("Error 404. You have reached the end of the Internet. Do not proceed beyond this point, HIC SUNT DRAGONES!").
Ist das nur ein temporäres Problem?
Vielen Dank und viele Grüße
Falk
Hallo Falk,
das tut mir leid. Ich beschränke meine site auf Europa und einige wenige außereuropäische Staaten. Aus welchem Land greifst du auf rustimation.eu zu?
Gerne schalte ich dich frei - vllt habe ich ja ein Land übersehen
Chris
Hallo Chris,
vielen Dank für den Hinweis. Ich war beim Zugriff auf sie Seite tatsächlich gerade in Asien.
Mittels VPN über meine heimische FritzBox funktioniert der Zugriff nun.
Ich habe gerade angefangen, den Flow zu basten.
Vielen Dank für deine Arbeit, und dass du uns die Dokumentation zur Verfügung stellst! 🙂
Viele Grüße
Falk
Zur Info es gibt inzwischen auch das open E3 Projekt mit direktem Zugriff per CAN Bus, ohne VM Cloud dazwischen.
VG
Vielen Dank für den Hinweis. Das habe ich schon gesehen. Mittelfristig möchte ich von der Vitoconnect und der Viessmann-Cloud weg und alles auf eigener Hardware laufen haben. Aber kurzfristig ist die Lösung mit Node-Red am schnellsten umzusetzen 🙂
Das open E3 Projekt sehe ich mir im Winter mal genauer an.
Sorry, du hast noch einen alten Vitodens mit Vitotronic.
Der hat noch keinen CAN-Bus. 🙂
Da gibt es als lokale Alternative den Splitter von Phil:
oder das vcontrold project auf Github.
Auch gut, dann wird es eben die Optlink-Splitter-Lösung 🙂
vcontrold hatte ich auch schon länger im Auge. Ich wollte eigentlich ohne einen zusätzlichen Raspi an der Heizung auskommen. Ich habe einen Server im Keller, auf dem Portainer läuft. Und LAN an beiden Enden. Ich dachte ich könnte die USB-Optolink-Leitung über LAN verlängern um alles gleich auf dem Server laufen zu lassen. Aber keine der USB-via-Ethernet-Bridges, die ich ausprobiert habe, funktioniert.
Hat dazu jemand eine gute Idee?
Im Idealfall würde ich sogar die Umsetzung von
- Optolink auf USB
- USB auf LAN
- LAN auf USB
- USB nach Portainer
verkürzen, wenn man über eine USB-LAN-Schnittstelle direkt von Portainer über das Netzwerk auf die Optolink-Schnittstelle zugreifen kann.
Hat das schon mal jemand erfolgreich realisiert?
Vielen Dank und viele Grüße
Falk