DSMR Decoding

Hardware

Based on an ESP32-S3 dongle from tinytronics that provides two RJ12 connecctors.

The Software provided on github is dustch oriented, ans thus needs to be adapted to the Belgian encoding.

Initially I could not get data out of the meter, whereas my esp8266 worked perfectly. So I fiddled a bit with a couple of S3 to check the signal that needed to be present on the pins.

As it turned out, the board has an output pin configured to enable the data transmission of the meter, and needs to be activated to enable the S3 RX pin.

Once programmed, it worked.

At the moment the firmware in the module is doing the following:

  • Connects the WiFi
  • Initiates a Web Server
  • Initiate a WebSocket server, this works as expected
  • Initializes a WiFi server on port 2021, this doesn’t work well, I can’t maintain a permanent connection on the socket.
  • Initiates a telnet server (which redirects the serial console I/O)
  • Synchronizes its internal Clock with NTP via WiFi
  • Reading data from the input serial port and forwarding them to the output port.
  • Recognizes a frame (all data betwee / and ! plus 3 bytes of CRC).
  • Converts the frame to json
  • Send the json frame to the websocket clients.
  • Reuse the page developped for the openwatt dognel to display the frame
  • Reuse the graphic tool

The software ingest the bytes provided on the Serial port, no frame recognition is performed, which I don’t like to much.

DSMR frames are define as:

/XXXZ Ident CR LF CR LF Data ! CRC CR LF /XXX5 Identification CR LF CR LF Data ! CRC CR LF

CRC is a CRC16 value calculated over the preceding characters in the data message (from “/” to “!” using the polynomial: x16+x15+x2+1). CRC16 uses no XOR in, no XOR out and is computed with least significant bit first. The value is represented as 4 hexadecimal characters (MSB first). XOR is a bit operation that results in true if and only if one of the inputs is true.

For exapmle as pîcked up bey the module:

/FLU5\253769484_A

0-0:96.1.4(50221)
1-0:94.32.1(400)
0-0:96.1.1(3153414733313035313030313830)
0-0:96.1.2(2D2D2D2D29*A)
0-1:96.3.10(1)
0-2:96.3.10(1)
0-3:96.3.10(1)
0-4:96.3.10(1)
0-0:96.13.0(546F553031)
!8700

Algorithm:

Structure frame char *buffer[] String text

read bytes into frame.buffer

A frame is all characters between indexof(’/’) and indexof(’|’)+3

check regexp for /(4 ascii Bytes)[bytes]crlfcrlf(many bytes)![4bytes]

void frame(char c){
static bool CRC;
static int crcount;
static char buffer[BUFFERSIZE]; // Buffer size
static char crc[3];
static uint16_t plength=0;
if (CRC) {
    //CRC on going
    crc[crcount]=c;
    crcount+=1;
    if (crcount > 2) {
    console->print(F("CRC "));
    console->println(crc);
    CRC=false;
    crcount=0;
    P1msg=buffer;
    plength=0;
    return;
    }
} else if (c == 47) {
    console->print(F("Start Of Frame detected"));
    plength=0; // reset frame pointer
    buffer[0] = c;
    plength+=1;
    buffer[plength]=0;
    console->print(F("plength: "));
    console->println(plength);
    return;
} else if (c == 33) {
    //CRC detected reset frame
    CRC = true; //set CRC flag to true
    crcount = 0; //point to girst bytes
    console->println(F("CRC detected"));
    plength=0;
    return;
} else if (plength < 1022) {
    //store in buffer and increment buffer lenght
    buffer[plength] = c;
    plength+=1;
    buffer[plength]='\0';
}
if (plength >= 1023) {  
    console->println("[BUFFER WARNING] Buffer limit reached, buffer reset");
    console->println(BUFFERSIZE);
    console->println(plength);
    plength=0;
    buffer[0]=0;
}
}