Hello all!
I have this problem for several months now and since I’m not the big coding insider, it really gives me gray hairs
Googling and reading postings did not help me to find a solution yet, also weird code behavior puzzles me, so I will write about all of that now and maybe someone has some hints for me.
I have 3 smartmeters here that I want to read out using an ESP32.
The smartmeter shoots out data via an optical port every second (AFAIK this interval is not fix), I successfully get the data into the ESP but here my problems begin.
Currently I use a serial command I manually send to the ESP and a sub to trigger that starts to look for serial data from the smartmeter. Later on I want to put that in a task or using a timer to start the read out and parsing.
I started using a byte array where I store the serial data:
byte Arr_RX1[1000];
To be able to see what the smartmeter sends, I fill the array using this:
Z1_ser.setTimeout(700);
Z1_ser.readBytes(Arr_RX1,500);
for (byte gg = 0; gg < 500; gg++)
{
char hexChar[3];
sprintf(hexChar, "%02X", Arr_RX1[gg]);
Serial.print(hexChar); Serial.print(" ");
}
I want to see hexadecimal values, that’s why I use sprintf.
But here I have a problem: The serial send never ends. It sends a never ending stream of hex values!
gg < 10 for example works. I guess I run into a buffer overload, could it be?
I splitted up the for loop into 5, 100 values at once, but the same neverending send happens in the middle of the 2nd loop.
If I use Serial.write(Arr_RX1,500) it works, but then I have to use a serial monitor with hex view, that’s a little uncomfortable.
How can I serial send an array (or 500 values) to be able to look at the data?
Using google, I found a thread in the German section of this forum and also an example code that I altered a little bit. The original code does not work for me because I don’t know the correct sequences without being able to look at the serial data in hex format (except I use a serial monitor with hex view and get correct data, see the following experience).
This is the thread with the code at the end: https://forum.arduino.cc/index.php?topic=548325.15
I altered this code a little and also edited the start/stop/power sequences (which ich got from a sermon with hex view and the smart meter manual). It looks like this:
defs:
byte Arr_RX1[1000];
const byte startSequence[] = { 0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01 };//start sequence of SML protocol
const byte stopSequence[] = { 0x1B, 0x1B, 0x1B, 0x1B, 0x18 };//end sequence of SML protocol
const byte powerSequence[] = { 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x64, 0x01, 0x02, 0xE2, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x56 }; //sequence preceeding the current "pos Wirkenergie, 1.0.8." value (4 Bytes)
int startIndex = 0;//start index for start sequence search
int stopIndex = 0;//start index for stop sequence search
byte power[4]; //array that holds the extracted 4 byte "Wirkleistung" value
int currentpower;
byte inByte;
unsigned int RXx_stage = 0;
unsigned int Arr_RX1_idx = 0;
RXx_stage = 0;
if (RXx_stage == 0)
{
while (Z1_ser.available())
{
inByte = Z1_ser.read();//read serial buffer into array
if (inByte == startSequence[startIndex])//in case byte in array matches the start sequence at position 0,1,2...
{
Arr_RX1[startIndex] = inByte;//set smlMessage element at position 0,1,2 to inByte value
startIndex++;
if (startIndex == sizeof(startSequence))//all start sequence values have been identified
{
Serial.println("st0 Match found");
RXx_stage = 1;
Arr_RX1_idx = startIndex;
startIndex = 0;
}
}
else {startIndex = 0;}
if (RXx_stage == 1) {break;} //I added this because else it would read all ser_data and not find the stop sequence (at least it did until I added it)
}
}
if (RXx_stage == 1)
{
Serial.println("st1 start");
while (Z1_ser.available())
{
inByte = Z1_ser.read();
Arr_RX1[Arr_RX1_idx] = inByte;
Arr_RX1_idx++;
if (inByte == stopSequence[stopIndex])
{
stopIndex++;
if (stopIndex == sizeof(stopSequence))
{
RXx_stage = 2;
stopIndex = 0;
// after the stop sequence, ther are sill 3 bytes to come.
// One for the amount of fillbytes plus two bytes for calculating CRC.
for (int c = 0 ; c < 3 ; c++)
{
Arr_RX1[Arr_RX1_idx++] = Z1_ser.read();
if (stopIndex == sizeof(stopSequence))
{
RXx_stage = 2;
stopIndex = 0;
// after the stop sequence passed, there are sill 3 bytes to come.
// One for the amount of fillbytes plus two bytes for calculating CRC.
delay(3); // wait for the 3 bytes to be received.
for (int c = 0 ; c < 3 ; c++)
{
Arr_RX1[Arr_RX1_idx++] = Z1_ser.read();
}
// smlIndex is at this point one bigger than the amount of stored inBytes because it is incremented evreytime after reading.
// To store the real smlIndex, we have to substract the last incrementation.
Arr_RX1_idx--;
}
}
Serial.println("st1 done");
}
}
else {stopIndex = 0;}
}
}
if (RXx_stage == 2)
{
Serial.println("st2 start");
byte temp; //temp variable to store loop search data
startIndex = 0; //start at position 0 of exctracted SML message
for(int x = 0; x < sizeof(Arr_RX1); x++) //for as long there are element in the exctracted SML message
{
temp = Arr_RX1[x]; //set temp variable to 0,1,2 element in extracted SML message
if (temp == powerSequence[startIndex]) //compare with power sequence
{
startIndex++;
if (startIndex == sizeof(powerSequence)) //if complete sequence is found
{
for(int y = 0; y< 4; y++) //read the next 4 bytes (the actual power value)
{
power[y] = Arr_RX1[x+y+1]; //store into power array
}
RXx_stage == 3; // go to stage 3
startIndex = 0;
Serial.println("st2 Match found");
currentpower = (power[0] << 24 | power[1] << 16 | power[2] << 8 | power[3]); //merge 4 bytes into single variable to calculate power value
Serial.print("power:"); Serial.println(currentpower);
}
}
else {startIndex = 0;}
}
//currentpower = (power[0] << 24 | power[1] << 16 | power[2] << 8 | power[3]); //merge 4 bytes into single variable to calculate power value
}
if (RXx_stage == 3)
{
//Serial.print("power:"); Serial.println(currentpower);
RXx_stage = 0;
}
I put that in a task and let it run all the time.
edit: continued in next posting