1

I'm trying to read data being transferred via Infrared from my Smartmeter on my ESP8266 using the following sketch:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#ifndef STASSID
#define STASSID "mySSID"
#define STAPSK "myPassword"
#endif
#ifndef MQTT_HOST
#define MQTT_HOST IPAddress(192, 168, 0, 100)
#define MQTT_PORT 1883
#endif
#ifndef IR
#define SerialDebug Serial1
#define IR Serial
#endif
AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;
const char* host = "esp8266-webupdate";
const byte firstByte = 0x7E;
const byte lastByte = 0x7E;
uint8_t i;
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
void connectToWifi() {
 SerialDebug.println("Connecting to WiFi ...");
 WiFi.begin(STASSID, STAPSK);
}
void connectToMqtt() {
 SerialDebug.println("Connecting to MQTT ...");
 mqttClient.connect();
}
void onWifiConnect(const WiFiEventStationModeGotIP& event) {
 SerialDebug.println("Connected to Wi-Fi.");
 connectToMqtt();
}
void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
 SerialDebug.println("Disconnected from Wi-Fi.");
 mqttReconnectTimer.detach();
 wifiReconnectTimer.once(2, connectToWifi);
}
void onMqttConnect(bool sessionPresent) {
 SerialDebug.println("Connected to MQTT.");
 SerialDebug.print("Session present: ");
 SerialDebug.println(sessionPresent);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
 SerialDebug.println("Disconnected from MQTT.");
 if (WiFi.isConnected()) {
 mqttReconnectTimer.once(2, connectToMqtt);
 }
}
void array_to_string(byte array[], unsigned int len, char buffer[]) {
 for (unsigned int i = 0; i < len; i++) {
 byte nib1 = (array[i] >> 4) & 0x0F;
 byte nib2 = (array[i] >> 0) & 0x0F;
 buffer[i*2+0] = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA;
 buffer[i*2+1] = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA;
 }
 buffer[len*2] = '0円';
}
void setup() {
 SerialDebug.begin(115200);
 IR.begin(9600);
 SerialDebug.println();
 SerialDebug.println("Booting Sketch...");
 
 wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
 wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
 mqttClient.onConnect(onMqttConnect);
 mqttClient.onDisconnect(onMqttDisconnect);
 mqttClient.setServer(MQTT_HOST, MQTT_PORT);
 connectToWifi();
 httpUpdater.setup(&httpServer);
 httpServer.begin();
 mqttClient.setWill("smartmeter/online", 0, true, "no");
}
void loop() {
 httpServer.handleClient();
 
 uint32_t timeout = 2000;
 
 int readCnt = 0;
 uint32_t start_time = millis();
 byte tempChar = 0;
 byte *readMessage;
 uint32_t messageLen = 0;
 
 while ((tempChar != 0x7E) && (millis() - start_time < timeout)) {
 if (IR.available()) {
 tempChar = IR.read();
 }
 }
 
 start_time = millis();
 timeout = 1000;
 bool done = false;
 
 if (tempChar == firstByte) { // if first byte == 0x7E
 while ((millis() - start_time) < timeout && !done) {
 if (IR.available()) {
 tempChar = IR.read(); // second byte must be 0xA0
 if(tempChar == 0xA0) {
 while ((millis() - start_time) < timeout && !done) {
 if (IR.available()) {
 tempChar = IR.read(); // 3rd byte tells the legth of the message
 
 readMessage = new byte[tempChar+2];
 memset(readMessage, 0, tempChar+2);
 readMessage[0] = firstByte;
 readMessage[1] = 0xA0;
 readMessage[2] = tempChar;
 messageLen = ((uint32_t)(tempChar))+2;
 readCnt = 3;
 
 while ( readCnt < messageLen && ((millis() - start_time) < timeout)) { // minimum len 120 chars for 0x7E format
 if (IR.available()) {
 readMessage[readCnt] = IR.read(); 
 readCnt++; 
 
 if(readCnt == tempChar+2 && readMessage[readCnt-1] != lastByte) { // correct len but last byte not 0x7E
 done = true;
 SerialDebug.printf("Wrong end byte found - %d\n", readMessage[readCnt-1]);
 } else if(readCnt == tempChar+2) { // correct len and correct last byte
 done = true;
 char str[251] = "";
 array_to_string(readMessage, readCnt, str);
 mqttClient.publish("smartmeter/raw", 0, false, str);
 }
 }
 }
 }
 }
 }
 }
 }
 }
 mqttClient.publish("smartmeter/online", 0, true, "yes");
 char heap[6] = "";
 itoa(ESP.getFreeHeap(), heap, 10);
 mqttClient.publish("smartmeter/freeHeap", 0, false, heap);
}

I'm getting the encoded HEX-data published on my MQTT Topic as desired, the outputs length is 250 characters long (= 125 Bytes) which is correct:

7ea07bcf000200231362b1e6e700db08534d536770075f626120000e32e62addedaede38e64c8c3173035a0a853851a28efc57f7fd76a9df59dbb152f796939328ff0f28df7f257d20b5cb2a458c4eb9188e2c1c251701c891244d859ed9c159714bb4451c090d9b1ed3bbb1fc89785ebafbf59ec4f9d540eb4c90d47e

As I found out, the ESP's heap is decreasing by 100-300 by each iteration of the loop (data is being transmitted every second via Infrared from the power-grid Smartmeter) until the ESP will eventually be rebooted by the watchdog after like 5-8 minutes.

I explicitly did not use String variables in the sketch but I legit cannot find the reason for the memory leak. Tried turning off wifi, webserver and mqtt one after each other which didn't actually made a difference.

The heap-size stays at a constant level though when there is no data being received via the Infrared serial port, so I imagine something is fishy when storing the data in the byte array "readMessage".

Anything obvious that immediately pops into someones eye that I missed?

Michel Keijzers
13k7 gold badges41 silver badges58 bronze badges
asked Aug 25, 2022 at 23:18
1
  • the 'problem with Strings' is a problem with new hidden in String class. your use of new is not hidden Commented Aug 26, 2022 at 5:27

1 Answer 1

2

You do a new inside the loop

 readMessage = new byte[tempChar+2];

which causes the heap to be filled with tempChar+2 bytes, but you never delete this.

Try reusing this memory (making it a local, or make it 'dirty' global).

Probably (not tested) the above line can be rewritten as:

byte readMessage[tempChar+2];
answered Aug 25, 2022 at 23:34
3
  • 1
    By now I was already convinced it's something so obvious sigh A simple delete[] readMessage; after the MQTT publish of the "str" variable did the trick! Even if I went a different path so actually solve the problem, you gave the actual hint that guided me there, so I'll mark your answer as accepted. Thank you very much! Commented Aug 25, 2022 at 23:44
  • 3
    You are welcome ... however, take in mind that a new and delete is not needed in this case, as the data only lives within one function. Typically new / delete is used when the life span of data is higher than one function, or when the amount of data is not known beforehand/varies. Commented Aug 26, 2022 at 0:00
  • True that - I will definitely take it into account when I will be implementing parts of this sketch to the final code! Commented Aug 26, 2022 at 0:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.