Beschrijving restAPI's

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).

Aanroepen restAPI vanuit verschillende systemen

Een restAPI kan op verschillende manieren worden aangeroepen.

Javascript

    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)
        );
      });     

Unix command

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

Home Assistant

configuration.yaml:

### configuration.yaml
### DSMRloggerAPI 
  - platform: rest
    name: "Levering"
    resource: http://<ip-dsmr-logger>/api/v1/sm/fields/power_returned
    unit_of_measurement: "kWh"
    value_template: '{{ value_json.fields[1].value | round(3) }}'

  - platform: rest
    name: "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: rest
    name: "Levering l1"
    resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l1
    unit_of_measurement: "Watt"
    value_template: '{{ (value_json.fields[1].value | float * 1000.0) | round(1) }}'

  - platform: rest
    name: "Levering l2"
    resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l2
    unit_of_measurement: 'Watt'
    value_template: '{{ (value_json.fields[1].value | float * 1000.0) | round(1) }}'

  - platform: rest
    name: "Levering l3"
    resource: http://192.168.2.106/api/v1/sm/fields/power_returned_l3
    unit_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.

Arduino Mega met Ethernet shield

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 response
  httpResponseCode = 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 resources
  DSMRclient.stop();

  return true;
  
} // dsmrGETrequest()


//--------------------------------------------------------------------------
void setup()
{
  // setup Serial ..
  .
  .
  // Initialize Ethernet library
  byte 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.

ESP8266 (WiFi)

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 operation 
  DSMRclient.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 code
  
  Serial.print("HTTP Response code: ");
  Serial.println(httpResponseCode);
  
  if (httpResponseCode <= 0) 
  {
    payload = "{\"actual\":[{\"name\":\"httpresponse\", \"value\": "+String(httpResponseCode)+"}]}";
    return false;
  }

  // Skip HTTP headers
  if (!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 resources
  DSMRclient.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.

ESP32 (WiFi)

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 path 
  DSMRclient.begin(String(DSMRprotocol) + String(DSMRserverIP)+String(DSMRrestAPI));
  
  // Send HTTP GET request
  httpResponseCode = 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 resources
    DSMRclient.end();
    return false;
  }

  // Free resources
  DSMRclient.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.

Algemene functies

//--------------------------------------------------------------------------
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 var
  if (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 global
    if (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.

Andere systemen

Veel andere systemen hebben hun eigen manier om restAPI's op te vragen. Lees hiervoor de betreffende documentatie.

Last updated