abbrechen
Suchergebnisse werden angezeigt für 
Anzeigen  nur  | Stattdessen suchen nach 
Meintest du: 
Beantwortet! Gehe zur Lösung.

Using Node Red to visualize ViCare data

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.

CaCicala_0-1636386292917.png

 

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.

CaCicala_1-1636386292921.png

 

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.

CaCicala_2-1636386292923.png

 

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:

CaCicala_3-1636386292929.png

 

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.

CaCicala_4-1636386292931.png

 

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.

CaCicala_5-1636386292936.png

 

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"
            ]
        ]
    }
]

 

 

 

30 ANTWORTEN 30

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!):

https://www.viessmann-community.com/t5/Gas/Vitodens-200-WB2-BJ-2000-oder-2001-Nr-7159006-1-01159-108... 

 

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:

CaCicala_0-1664954630251.png

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