Alle beschikbare gegevens kunnen via restAPI call's bij de DSMR-logger worden opgevraagd. De restAPI's zijn verdeelt in drie groepen. Informatie die met de hardware en firmware te maken heeft (/dev
), informatie die met de Slimme Meter te maken heeft (/sm
) en historische gegevens die, aan de hand van de door de Slimme Meter afgegeven gegevens, door de DSMR-logger in bestanden worden opgeslagen (/hist
).
Een restAPI kan op verschillende manieren worden aangeroepen.
​Javascript​
​Unix command​
​Home Assistant​
​ESP8266​
​ESP32​
fetch("http://dsmr-api.local/api/v1/dev/time").then(response => response.json()).then(json => {console.log("parsed .., data is ["+ JSON.stringify(json)+"]");for( let i in json.devtime ){if (json.devtime[i].name == "time"){console.log("Got new time ["+json.devtime[i].value+"]");document.getElementById('theTime').innerHTML = json.devtime[i].value;}}}).catch(function(error) {var p = document.createElement('p');p.appendChild(document.createTextNode('Error: ' + error.message));});​
curl http://dsmr-api.local/api/v1/dev/time
Geeft dit als output:
{"devtime":[{"name": "time", "value": "2020-03-23 11:45:40"},{"name": "epoch", "value": 1584963941}]}
configuration.yaml:
### configuration.yaml### DSMRloggerAPI- platform: restname: "Levering"resource: http://<ip-dsmr-logger>/api/v1/sm/fields/power_returnedunit_of_measurement: "kWh"value_template: '{{ value_json.fields[1].value | round(3) }}'​- platform: restname: "Laatste Update restAPI"resource: http://192.168.2.106/api/v1/sm/fields/timestamp# value_template: '{{ value_json.fields[0].value }}'value_template: >{{ value_json.fields[0].value[4:6] + "-" +value_json.fields[0].value[2:4] + "-" +"20"+value_json.fields[0].value[0:2] + " " +value_json.fields[0].value[6:8] + ":" +value_json.fields[0].value[8:10] + ":" +value_json.fields[0].value[10:13] }}​- platform: restname: "Levering l1"resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l1unit_of_measurement: "Watt"value_template: '{{ (value_json.fields[1].value | float * 1000.0) | round(1) }}'​- platform: restname: "Levering l2"resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l2unit_of_measurement: 'Watt'value_template: '{{ (value_json.fields[1].value | float * 1000.0) | round(1) }}'​- platform: restname: "Levering l3"resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l3unit_of_measurement: 'Watt'value_template: '{{ (value_json.fields[1].value | float * 1000.0) | round(1) }}'​
geeft dit resultaat:
Met hassOS lukt het mij niet om bij resource de hostname (DSMR-API.local) te gebruiken. Met het IP adres lukt het wel.
Ik ben niet erg handig met JSON libraries (liefst parse ik de data helemaal zelf zodat ik ook alles zelf "in de hand" heb). Het zou mij daarom ook niet verbazen als onderstaande code simpeler en beter kan.
Getest door Bert Diepeveen (met dank!).
// in the main program:#include <Ethernet.h>#include <SPI.h>#include <Arduino_JSON.h> // let op! dit is een andere library dan "ArduinoJson"//#define _IS_ARDUINO_MEGA#define _DSMR_IP_ADDRESS "IP_ADDRESS_OF_YOUR_DSMR_LOGGER"#define _READINTERVAL 60000//const char *DSMRprotocol = "http://";const char *DSMRserverIP = _DSMR_IP_ADDRESS;const char *DSMRrestAPI = "/api/v1/sm/actual";String payload;int httpResponseCode;uint32_t lastRead = 0;​//--- catch specific fields for further processing -------//--- these are just an example! see readDsmrLogger() ----String timeStamp;int voltageL1, currentL1;float pwrDelivered, pwrReturned;​​//--------------------------------------------------------------------------bool dsmrGETrequest(){EthernetClient ETHclient;HttpClient DSMRclient = HttpClient(ETHclient, DSMRserverIP, 80);​payload = "";Serial.println(F("making GET request"));DSMRclient.get(DSMRrestAPI);​// read the response code and body of the responsehttpResponseCode = DSMRclient.responseStatusCode();Serial.print(F("http Response Code: "));Serial.println(httpResponseCode);​if (httpResponseCode <= 0){return false;}​payload = DSMRclient.responseBody();//--debug-Serial.print(F("payload: "));//--debug-Serial.println(payload);// Free resourcesDSMRclient.stop();​return true;} // dsmrGETrequest()​​//--------------------------------------------------------------------------void setup(){// setup Serial ....// Initialize Ethernet librarybyte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};if (!Ethernet.begin(mac)){Serial.println(F("Failed to configure Ethernet"));return;}delay(1000);..lastRead = millis() + _READINTERVAL;} // setup()​​
Verder moet je de Algemene functies onderaan deze pagina in je sketch opnemen.
Ik ben niet erg handig met JSON libraries (liefst parse ik de data helemaal zelf zodat ik ook alles zelf "in de hand" heb). Het zou mij daarom ook niet verbazen als onderstaande code simpeler en beter kan.
// Include in the main program:#include <WiFi.h>#include <Arduino_JSON.h> // let op! Niet ArduinoJson!//#define _IS_ESP8266#define _DSMR_IP_ADDRESS "IP_ADDRESS_OF_YOUR_DSMR_LOGGER"#define _WIFI_SSID "YOUR_WIFI_SSID"#define _WIFI_PASSWRD "YOUR_WIF_PASSWORD"#define _READINTERVAL 60000//const char *ssid = _WIFI_SSID;const char *password = _WIFI_PASSWRD;//const char *DSMRprotocol = "http://";const char *DSMRserverIP = _DSMR_IP_ADDRESS;const char *DSMRrestAPI = "/api/v1/sm/actual";String payload;int httpResponseCode;uint32_t lastRead = 0;​//--- catch specific fields for further processing -------//--- these are just an example! see readDsmrLogger() ----String timeStamp;int voltageL1, currentL1;float pwrDelivered, pwrReturned;​//--------------------------------------------------------------------------bool dsmrGETrequest(){WiFiClient DSMRclient;​payload = "";​Serial.print("DSMRclient.connect("); Serial.print(DSMRserverIP);Serial.println(", 80)");if (!DSMRclient.connect(DSMRserverIP, 80)){Serial.println(F("error connecting to DSMRlogger "));payload = "{\"actual\":[{\"name\":\"httpresponse\", \"value\":\"error connecting\"}]}";return false;}​//-- normal operationDSMRclient.print(F("GET "));DSMRclient.print(DSMRrestAPI);DSMRclient.println(" HTTP/1.1");DSMRclient.print(F("Host: "));DSMRclient.println(DSMRserverIP);DSMRclient.println(F("Connection: close"));DSMRclient.println();​DSMRclient.setTimeout(1000);​//--debug-Serial.println("find(HTTP/1.1)..");DSMRclient.find("HTTP/1.1"); // skip everything up-until "HTTP/1.1"//--debug-Serial.print("DSMRclient.parseInt() ==> ");httpResponseCode = DSMRclient.parseInt(); // parse status codeSerial.print("HTTP Response code: ");Serial.println(httpResponseCode);if (httpResponseCode <= 0){payload = "{\"actual\":[{\"name\":\"httpresponse\", \"value\": "+String(httpResponseCode)+"}]}";return false;}​// Skip HTTP headersif (!DSMRclient.find("\r\n\r\n")){Serial.println(F("Invalid response"));payload = "{\"actual\":[{\"name\":\"httpresponse\", \"value\": "+String(httpResponseCode)+"}]}";return false;}​while(DSMRclient.connected()){if (DSMRclient.available()){// read an incoming lines from the server:String line = DSMRclient.readStringUntil('\r');line.replace("\n", "");if ( (line[0] == '{') || (line[0] == ',')|| (line[0] == '[') || (line[0] == ']') ){//--debug-Serial.print(line);payload += line;}}}//--debug-Serial.println();// Free resourcesDSMRclient.stop();​return true;} // dsmrGETrequest()​​//--------------------------------------------------------------------------void setup(){// setup serial ....// setup WiFi ..WiFi.begin(ssid, password);Serial.println("Connecting");while(WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("");Serial.print("Connected to WiFi network with IP Address: ");Serial.println(WiFi.localIP());lastRead = millis() + _READINTERVAL;..} // setup()​
Verder moet je de Algemene functies onderaan deze pagina in je sketch opnemen.
With some help from Random Nerd Tutorials.
Ik ben niet erg handig met JSON libraries (liefst parse ik de data helemaal zelf zodat ik ook alles zelf "in de hand" heb). Het zou mij daarom ook niet verbazen als onderstaande code simpeler en beter kan.
// Include in the main program:#include <WiFi.h>#include <HTTPClient.h>#include <Arduino_JSON.h> // let op! Niet ArduinoJson!//#define _IS_ESP32#define _DSMR_IP_ADDRESS "IP_ADDRESS_OF_YOUR_DSMR_LOGGER"#define _WIFI_SSID "YOUR_WIFI_SSID"#define _WIFI_PASSWRD "YOUR_WIF_PASSWORD"#define _READINTERVAL 60000//const char *ssid = _WIFI_SSID;const char *password = _WIFI_PASSWRD;//const char *DSMRprotocol = "http://";const char *DSMRserverIP = _DSMR_IP_ADDRESS;const char *DSMRrestAPI = "/api/v1/sm/actual";String payload;int httpResponseCode;uint32_t lastRead = 0;​//--- catch specific fields for further processing -------//--- these are just an example! see readDsmrLogger() ----String timeStamp;int voltageL1, currentL1;float pwrDelivered, pwrReturned;​//--------------------------------------------------------------------------bool dsmrGETrequest(){HTTPClient DSMRclient;// Your IP address with path or Domain name with URL pathDSMRclient.begin(String(DSMRprotocol) + String(DSMRserverIP)+String(DSMRrestAPI));// Send HTTP GET requesthttpResponseCode = DSMRclient.GET();​Serial.print("HTTP Response code: ");Serial.println(httpResponseCode);payload = "";if (httpResponseCode > 0){payload = DSMRclient.getString();}else{payload = "{\"actual\":[{\"name\":\"httpresponse\", \"value\": "+String(httpResponseCode)+"}]}";// Free resourcesDSMRclient.end();return false;}​// Free resourcesDSMRclient.end();return true;​} // dsmrGETrequest()​​//--------------------------------------------------------------------------void setup(){// setup Serial ....// setup WiFi ..WiFi.begin(ssid, password);Serial.println("Connecting");while(WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("");Serial.print("Connected to WiFi network with IP Address: ");Serial.println(WiFi.localIP());lastRead = millis() + _READINTERVAL;..} // setup()​
Verder moet je de Algemene functies onderaan deze pagina in je sketch opnemen.
//--------------------------------------------------------------------------void readDsmrLogger(){int fieldNr = 0;​dsmrGETrequest();​Serial.println();Serial.println(F("==== Start parsing payload ======================="));// This is how the "actual" JSON object looks like:// {"actual":[// {"name":"timestamp","value":"200911140716S"}// ,{"name":"energy_delivered_tariff1","value":3433.297,"unit":"kWh"}// ,{"name":"energy_delivered_tariff2","value":4453.041,"unit":"kWh"}// ,{"name":"energy_returned_tariff1","value":678.953,"unit":"kWh"}// ...// ,{"name":"power_delivered_l2","value":0.071,"unit":"kW"}// ,{"name":"power_delivered_l3","value":0,"unit":"kW"}// ,{"name":"power_returned_l1","value":0,"unit":"kW"}// ,{"name":"power_returned_l2","value":0,"unit":"kW"}// ,{"name":"power_returned_l3","value":0.722,"unit":"kW"}// ,{"name":"gas_delivered","value":2915.08,"unit":"m3"}// ]}​//--debug-Serial.print(F("payload: "));//--debug-Serial.println(payload);​JSONVar dsmrJsonObject = JSON.parse(payload);// JSON.typeof(jsonVar) can be used to get the type of the varif (JSON.typeof(dsmrJsonObject) == "undefined"){Serial.println(F("Parsing failed!"));return;}//--debug-Serial.print("JSON.typeof(dsmrJsonObject) = ");//--debug-Serial.println(JSON.typeof(dsmrJsonObject));​JSONVar dsmrJsonField = dsmrJsonObject["actual"];​// dsmrJsonField.length() can be used to get the length of the array//--debug-Serial.print("dsmrJsonField.length() = ");//--debug-Serial.println(dsmrJsonField.length());//--debug-Serial.println();for (int i = 0; i < dsmrJsonField.length(); i++){fieldNr++;//--debug-Serial.print(dsmrJsonField[i]);String sName = (const char *)dsmrJsonField[i]["name"];String sValue = (const char *)dsmrJsonField[i]["value"];if (sValue == "") sValue = String((double)dsmrJsonField[i]["value"]);String sUnit = (const char *)dsmrJsonField[i]["unit"];//---- list all fields and values ----Serial.print(sName); Serial.print(" \t");Serial.print(sValue); Serial.print(" ");Serial.print(sUnit);Serial.println();//--- now catch some fields of interrest for further//--- processing//--- you need to declare the fields to be captured globalif (sName == "timestamp") timeStamp = sValue;if (sName == "voltage_l1") voltageL1 = sValue.toInt();if (sName == "current_l1") currentL1 = sValue.toInt();if (sName == "power_delivered") pwrDelivered = sValue.toFloat();if (sName == "power_returned") pwrReturned = sValue.toFloat();}​Serial.println(F("=================================================="));Serial.print(F("Parsed [")); Serial.print(fieldNr); Serial.println(F("] fields"));} // readDsmrLogger()​
In de main loop() function moet deze code komen:
​//--------------------------------------------------------------------------void loop(){if ((millis() - lastRead) > _READINTERVAL){lastRead = millis();Serial.println("\r\nread API from DSMR-logger...");readDsmrLogger();Serial.println(F("\r\nCaptured fields .."));Serial.print(F("timestamp : \t")); Serial.println(timeStamp);Serial.print(F("voltage L1 : \t")); Serial.println(voltageL1);Serial.print(F("current L1 : \t")); Serial.println(currentL1);Serial.print(F("pwrDelivered : \t")); Serial.println(pwrDelivered);Serial.print(F("pwrReturned : \t")); Serial.println(pwrReturned);}..} // loop()
De source van deze code kun je op github vinden.
Veel andere systemen hebben hun eigen manier om restAPI's op te vragen. Lees hiervoor de betreffende documentatie.