Arduino freezes after 2 days

Hi all,

I'm new in programming with Arduino. I made some code to read a DS18B20 temp sensor, triggering some buttons with LED light, triggering 2 relays and sending / receiving MQTT code from / to Home Assistant.

I noticed my Arduino (Mega) hangs after a day or two. Button presses won't work anymore and nothing is received on the MQTT connection. I can still ping the Arduino Ethernetshield. Can you guys point me in the right direction? This is my code so far:

#include <Ethernet.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <neotimer.h>


// IP instellingen
byte mac[] = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 50, 20);


// MQTT instellingen
EthernetClient ethClient;
PubSubClient mqttClient(ethClient);

char x[8];
bool berichtOntvangen     = false;


// Pinouts sectie: ALGEMEEN
int knop01FrequentieregelaarKNOP            = 44;
int knop01FrequentieregelaarLED             = 45;
int knop02DoseerpompjesKNOP                 = 46;
int knop02DoseerpompjesLED                  = 47;
int knop03StopcontactenKNOP                 = 48;
int knop03StopcontactenLED                  = 49;  
  
// Pinouts sectie: DOSERING
int knop04DoseerpompjeChloorKNOP            = 38;
int knop04DoseerpompjeChloorLED             = 39;
int knop05DoseerpompjePhKNOP                = 40;
int knop05DoseerpompjePhLED                 = 41;
int led01Chloorlevel                        = 42;
int led02Phlevel                            = 43;

// Pinouts sectie: POMP INSTELLING
int knop06PompAutoKNOP                      = 22;
int knop06PompAutoLED                       = 23;
int knop07PompUitKNOP                       = 24;
int knop07PompUitLED                        = 25;
int knop08PompLaagKNOP                      = 28;
int knop08PompLaagLED                       = 29;
int knop09PompMiddenKNOP                    = 26;
int knop09PompMiddenLED                     = 27;
int knop10PompHoogKNOP                      = 30;
int knop10PompHoogLED                       = 31;
  
// Pinouts sectie: POMP INFO
int led03WaterflowR                         = 32;
int led03WaterflowG                         = 33;
int led03WaterflowB                         = 34;
int led04PompViaDakR                        = 35;
int led04PompViaDakG                        = 36;
int led04PompViaDakB                        = 37;

// Pinouts sectie: OLED DISPLAY
int knop11MenuUp                            = 5;
int knop12MenuDown                          = 6;

// Pinouts relais Arduino A: schakelcontacten frequentieregelaar
int relais01FreqentieregelaarDi1OnOff       = 14;
int relais02FreqentieregelaarDi2Hoog        = 17;
int relais03FreqentieregelaarDi3Midden      = 16;
int relais04FreqentieregelaarDi4Laag        = 15;

// Pinouts relais Arduino B: schakelcontacten doseerpompjes
int relais05DoseerpompjeChloorOnOff         = 2;
int relais06DoseerpompjePhOnOff             = 3;


// Knop variabelen
bool knop01LaatsteStatus  = LOW;
bool knop02LaatsteStatus  = LOW;
bool knop03LaatsteStatus  = LOW;
bool knop04LaatsteStatus  = LOW;
bool knop05LaatsteStatus  = LOW;
bool knop06LaatsteStatus  = LOW;
bool knop07LaatsteStatus  = LOW;
bool knop08LaatsteStatus  = LOW;
bool knop09LaatsteStatus  = LOW;
bool knop10LaatsteStatus  = LOW;

bool knop01HuidigeStatus  = LOW;
bool knop02HuidigeStatus  = LOW;
bool knop03HuidigeStatus  = LOW;
bool knop04HuidigeStatus  = LOW;
bool knop05HuidigeStatus  = LOW;
bool knop06HuidigeStatus  = LOW;
bool knop07HuidigeStatus  = LOW;
bool knop08HuidigeStatus  = LOW;
bool knop09HuidigeStatus  = LOW;
bool knop10HuidigeStatus  = LOW;

unsigned long knop01Timer = 0; 
unsigned long knop02Timer = 0; 
unsigned long knop03Timer = 0; 
unsigned long knop04Timer = 0; 
unsigned long knop05Timer = 0; 
unsigned long knop06Timer = 0;
unsigned long knop07Timer = 0;
unsigned long knop08Timer = 0;
unsigned long knop09Timer = 0; 
unsigned long knop10Timer = 0; 


// Shelly statussen
bool shelly01Status       = LOW;
bool shelly02Status       = LOW;
bool shelly03Status       = LOW;


// Relais statussen
bool relais01Status       = LOW;
bool relais02Status       = LOW;
bool relais03Status       = LOW;
bool relais04Status       = LOW;
bool relais05Status       = LOW;
bool relais06Status       = LOW;


// Temperatuur-sensor variabelen
int sensor01Temperatuur   = 18;
OneWire oneWire(sensor01Temperatuur);
DallasTemperature sensorsTemperatuur(&oneWire);
Neotimer sensor01Timer    = Neotimer(5000); 

float sensor01TemperatuurInlaat        = 0.0; 
float sensor01TemperatuurDak           = 0.0;
float sensor01TemperatuurTuinhuis      = 0.0;



void setup() {
  
  // ------------------------------------
  // NETWERK EN SERIELE POORT STARTEN
  // ------------------------------------
  Serial.begin(9600);
  Serial.println("Arduino Tuinhuis....booting...");

  Ethernet.begin(mac, ip);
  delay(1500);
 
  mqttClient.setServer("192.168.50.6", 1883);

  if (mqttClient.connect("arduino-1","mosquitto","xxxxx"))
  {    
    // Connectie gelukt
    Serial.println("Verbonden met MQTT server");
    mqttClient.setCallback(mqttOntvangen);

    // Inschrijven op topic waarop Home Assistant gaat communiceren
    boolean r= mqttClient.subscribe("tuinhuis/callback");
    Serial.println("subscribe ");
    Serial.println(r);
    
    Serial.println("Aangemeld voor callbacks vanuit Home Assistant");
  } 
  else
  {
    // Connectie niet gelukt
    Serial.println("Het is niet gelukt om te verbinden met de MQTT server");
  }

  // ------------------------------------
  // PINOUTS TOEWIJZEN
  // ------------------------------------
  // Sectie: ALGEMEEN
  pinMode(knop01FrequentieregelaarKNOP,       INPUT_PULLUP);
  pinMode(knop02DoseerpompjesKNOP,            INPUT_PULLUP);
  pinMode(knop03StopcontactenKNOP,            INPUT_PULLUP);
  
  pinMode(knop01FrequentieregelaarLED,        OUTPUT);
  pinMode(knop02DoseerpompjesLED,             OUTPUT);
  pinMode(knop03StopcontactenLED,             OUTPUT);
  
  
  // Sectie: DOSERING
  pinMode(knop04DoseerpompjeChloorKNOP,       INPUT_PULLUP);  
  pinMode(knop05DoseerpompjePhKNOP,           INPUT_PULLUP);
  
  pinMode(knop04DoseerpompjeChloorLED,        OUTPUT);
  pinMode(knop05DoseerpompjePhLED,            OUTPUT);
  
  pinMode(led01Chloorlevel,                   OUTPUT);
  pinMode(led02Phlevel,                       OUTPUT);


  // Sectie: POMP INSTELLING
  pinMode(knop06PompAutoKNOP,                 INPUT_PULLUP);
  pinMode(knop07PompUitKNOP,                  INPUT_PULLUP);
  pinMode(knop08PompLaagKNOP,                 INPUT_PULLUP);
  pinMode(knop09PompMiddenKNOP,               INPUT_PULLUP);
  pinMode(knop10PompHoogKNOP,                 INPUT_PULLUP);

  pinMode(knop06PompAutoLED,                  OUTPUT);
  pinMode(knop07PompUitLED,                   OUTPUT);
  pinMode(knop08PompLaagLED,                  OUTPUT);
  pinMode(knop09PompMiddenLED,                OUTPUT);    
  pinMode(knop10PompHoogLED,                  OUTPUT);


  // Sectie: POMP INFO
  pinMode(led03WaterflowR,                    OUTPUT);
  pinMode(led03WaterflowG,                    OUTPUT);
  pinMode(led03WaterflowB,                    OUTPUT);
  pinMode(led04PompViaDakR,                   OUTPUT);
  pinMode(led04PompViaDakG,                   OUTPUT);
  pinMode(led04PompViaDakB,                   OUTPUT); // Spare (niet aangesloten)


  // Sectie: OLED DISPLAY
  pinMode(knop11MenuUp,                       INPUT_PULLUP);
  pinMode(knop12MenuDown,                     INPUT_PULLUP);
  

  // Relais Arduino A: schakelcontacten frequentieregelaar
  pinMode(relais01FreqentieregelaarDi1OnOff,  OUTPUT);
  pinMode(relais02FreqentieregelaarDi2Hoog,   OUTPUT);
  pinMode(relais03FreqentieregelaarDi3Midden, OUTPUT);
  pinMode(relais04FreqentieregelaarDi4Laag,   OUTPUT);


  // Relais Arduino B: schakelcontacten doseerpompjes
  pinMode(relais05DoseerpompjeChloorOnOff,    OUTPUT);
  pinMode(relais06DoseerpompjePhOnOff,        OUTPUT);

  
  // Interne LED (voor eventuele test-doeleinden
  pinMode(LED_BUILTIN, OUTPUT);


  // Start met monitoren van sensoren
  sensorsTemperatuur.begin();
  sensor01Timer.set(5000);
  
}


// Arduino loop die oneindig herhaalt
void loop() {

  // ------------------------------------
  // UITLEZEN SENSOREN
  // ------------------------------------
  
  // Herhaal elke 5000 ms
  if(sensor01Timer.repeat())
  {
    // Lees de temperatuur sensor uit
    sensorsTemperatuur.requestTemperatures();

    // Haal temperatuur in Celcius op van eerste sensor
    sensor01TemperatuurInlaat = sensorsTemperatuur.getTempCByIndex(0);

    // Toon temperatuur op seriële monitor
    Serial.print("Temperatuur 1 is: ");       
    Serial.println(sensor01TemperatuurInlaat);

    // Stuur de temperatuur naar Home Assistant
    boolean rc17 = mqttClient.publish("zwembad/temperatuur/1",dtostrf(sensor01TemperatuurInlaat, 4, 2, x));
  }


  // ------------------------------------
  // AFHANDELEN BUTTONS
  // ------------------------------------
  
  // Sectie:        ALGEMEEN
  // Knop:          01
  // Functie:       Aan / Uitzetten van frequentieregelaar via Shelly 4PM Pro relais
  // Opmerkingen:   De schakeling van de Shelly relais loopt via Home Assistant
  
  knop01HuidigeStatus = digitalRead(knop01FrequentieregelaarKNOP);

  if(knop01HuidigeStatus == HIGH && knop01LaatsteStatus == LOW && millis() - knop01Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop frequentieregelaar is ingedrukt");

    // Knop is aangezet
    if (shelly01Status == LOW)
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/frequentieregelaar","ON"))
      {
        // Zet LED van knop aan
        digitalWrite(knop01FrequentieregelaarLED, HIGH);

        // Zet status op aan
        shelly01Status = HIGH;
      }
    }

    // Knop is uitgezet
    else
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/frequentieregelaar","OFF"))
      {
        // Zet LED van knop uit
        digitalWrite(knop01FrequentieregelaarLED, LOW);

        // Zet status op uit
        shelly01Status = LOW;
      }
    } 

    // Update timer met de laatste tijd van uitvoering
    knop01Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop01LaatsteStatus = knop01HuidigeStatus;


  // Sectie:        ALGEMEEN
  // Knop:          02
  // Functie:       Aan / Uitzetten van doseerpompjes via Shelly 4PM Pro relais
  // Opmerkingen:   De schakeling van de Shelly relais loopt via Home Assistant
  
  knop02HuidigeStatus = digitalRead(knop02DoseerpompjesKNOP);

  if(knop02HuidigeStatus == HIGH && knop02LaatsteStatus == LOW && millis() - knop02Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop doseerpompjes is ingedrukt");

    // Knop is aangezet
    if (shelly02Status == LOW)
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/doseerpompjes","ON"))
      {
        // Zet LED van knop aan
        digitalWrite(knop02DoseerpompjesLED, HIGH);

        // Zet status op aan
        shelly02Status = HIGH;
      }
    }

    // Knop is uitgezet
    else
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/doseerpompjes","OFF"))
      {
        // Zet LED van knop uit
        digitalWrite(knop02DoseerpompjesLED, LOW);

        // Zet status op uit
        shelly02Status = LOW;
      }
    } 

    // Update timer met de laatste tijd van uitvoering
    knop02Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop02LaatsteStatus = knop02HuidigeStatus;


  // Sectie:        ALGEMEEN
  // Knop:          03
  // Functie:       Aan / Uitzetten van stopcontacten via Shelly 4PM Pro relais
  // Opmerkingen:   De schakeling van de Shelly relais loopt via Home Assistant
  
  knop03HuidigeStatus = digitalRead(knop03StopcontactenKNOP);

  if(knop03HuidigeStatus == HIGH && knop03LaatsteStatus == LOW && millis() - knop03Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop stopcontacten is ingedrukt");

    // Knop is aangezet
    if (shelly03Status == LOW)
    {
      setStopcontacten(HIGH);
    }

    // Knop is uitgezet
    else
    {
      setStopcontacten(LOW);
    } 

    // Update timer met de laatste tijd van uitvoering
    knop03Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop03LaatsteStatus = knop03HuidigeStatus;
 

  // Sectie:        DOSERING
  // Knop:          04
  // Functie:       Aan / Uitzetten van Chloor doseringspompje via Arduino relais B
  // Opmerkingen:   Het relais is een schakelcontact dat een level-schakelaar op het pompje aan / uitzet waardoor de pomp in standby gaat
  
  knop04HuidigeStatus = digitalRead(knop04DoseerpompjeChloorKNOP);

  if(knop04HuidigeStatus == HIGH && knop04LaatsteStatus == LOW && millis() - knop04Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop chloor is ingedrukt");

    // Knop is aangezet
    if (relais05Status == LOW)
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/chloor","ON"))
      {
        // Zet LED van knop aan
        digitalWrite(knop04DoseerpompjeChloorLED, HIGH);

        // Zet relais 5 (chloor) aan
        digitalWrite(relais05DoseerpompjeChloorOnOff, HIGH);

        // Zet status op aan
        relais05Status = HIGH;
      }
    }

    // Knop is uitgezet
    else
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/chloor","OFF"))
      {
        // Zet LED van knop uit
        digitalWrite(knop04DoseerpompjeChloorLED, LOW);
        
        // Zet relais 5 (chloor) uit
        digitalWrite(relais05DoseerpompjeChloorOnOff, LOW);
        
        // Zet status op uit
        relais05Status = LOW;
      }
    } 

    // Update timer met de laatste tijd van uitvoering
    knop04Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop04LaatsteStatus = knop04HuidigeStatus;


  // Sectie:        DOSERING
  // Knop:          05
  // Functie:       Aan / Uitzetten van PH doseringspompje via Arduino relais B
  // Opmerkingen:   Het relais is een schakelcontact dat een level-schakelaar op het pompje aan / uitzet waardoor de pomp in standby gaat
  
  knop05HuidigeStatus = digitalRead(knop05DoseerpompjePhKNOP);

  if(knop05HuidigeStatus == HIGH && knop05LaatsteStatus == LOW && millis() - knop05Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop PH is ingedrukt");

    // Knop is aangezet
    if (relais06Status == LOW)
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/ph","ON"))
      {
        // Zet LED van knop aan
        digitalWrite(knop05DoseerpompjePhLED, HIGH);

        // Zet relais 5 (chloor) aan
        digitalWrite(relais06DoseerpompjePhOnOff, HIGH);

        // Zet status op aan
        relais06Status = HIGH;
      }
    }

    // Knop is uitgezet
    else
    {
      // Stuur trigger naar Home Assistant
      if(mqttClient.publish("tuinhuis/ph","OFF"))
      {
        // Zet LED van knop uit
        digitalWrite(knop05DoseerpompjePhLED, LOW);
        
        // Zet relais 5 (chloor) uit
        digitalWrite(relais06DoseerpompjePhOnOff, LOW);
        
        // Zet status op uit
        relais06Status = LOW;
      }
    } 

    // Update timer met de laatste tijd van uitvoering
    knop05Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop05LaatsteStatus = knop05HuidigeStatus;
  

  // Sectie:        POMP INSTELLING
  // Knop:          06
  // Functie:       Aanzetten automatische stand frequentieregelaar via Arduino relais A
  // Opmerkingen:   Met deze knop worden alle contacten op relais A opengezet zodat de frequentieregelaar in de clockmode gaat
  
  knop06HuidigeStatus = digitalRead(knop06PompAutoKNOP);

  if(knop06HuidigeStatus == HIGH && knop06LaatsteStatus == LOW && millis() - knop06Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop pomp op auto is ingedrukt");

    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/pomp","AUTO"))
    {
      // Zet LED van knop aan
      digitalWrite(knop06PompAutoLED, HIGH);

      // Zet andere LEDS uit
      digitalWrite(knop07PompUitLED, LOW);
      digitalWrite(knop08PompLaagLED, LOW);
      digitalWrite(knop09PompMiddenLED, LOW);
      digitalWrite(knop10PompHoogLED, LOW);
      
      // Zet relais 1, 2, 3 en 4 uit
      digitalWrite(relais01FreqentieregelaarDi1OnOff, HIGH);
      digitalWrite(relais02FreqentieregelaarDi2Hoog, HIGH);
      digitalWrite(relais03FreqentieregelaarDi3Midden, HIGH);
      digitalWrite(relais04FreqentieregelaarDi4Laag, HIGH);
    }

    // Update timer met de laatste tijd van uitvoering
    knop06Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop06LaatsteStatus = knop06HuidigeStatus;


  // Sectie:        POMP INSTELLING
  // Knop:          07
  // Functie:       Aanzetten uit stand frequentieregelaar via Arduino relais A
  // Opmerkingen:   Belangrijk is om alle contacten op het relais te schakelen zodat er maar 1 hoog is
  
  knop07HuidigeStatus = digitalRead(knop07PompUitKNOP);

  if(knop07HuidigeStatus == HIGH && knop07LaatsteStatus == LOW && millis() - knop07Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop pomp op uit is ingedrukt");

    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/pomp","UIT"))
    {
      // Zet LED van knop aan
      digitalWrite(knop07PompUitLED, HIGH);

      // Zet andere LEDS uit
      digitalWrite(knop06PompAutoLED, LOW);
      digitalWrite(knop08PompLaagLED, LOW);
      digitalWrite(knop09PompMiddenLED, LOW);
      digitalWrite(knop10PompHoogLED, LOW);
      
      // Zet relais 1 aan en 2, 3 en 4 uit
      digitalWrite(relais01FreqentieregelaarDi1OnOff, LOW);
      digitalWrite(relais02FreqentieregelaarDi2Hoog, HIGH);
      digitalWrite(relais03FreqentieregelaarDi3Midden, HIGH);
      digitalWrite(relais04FreqentieregelaarDi4Laag, HIGH);
    }

    // Update timer met de laatste tijd van uitvoering
    knop07Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop07LaatsteStatus = knop07HuidigeStatus;


  // Sectie:        POMP INSTELLING
  // Knop:          08
  // Functie:       Aanzetten laag stand frequentieregelaar via Arduino relais A
  // Opmerkingen:   Belangrijk is om alle contacten op het relais te schakelen zodat er maar 1 hoog is
  
  knop08HuidigeStatus = digitalRead(knop08PompLaagKNOP);

  if(knop08HuidigeStatus == HIGH && knop08LaatsteStatus == LOW && millis() - knop08Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop pomp op laag is ingedrukt");

    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/pomp","LAAG"))
    {
      // Zet LED van knop aan
      digitalWrite(knop08PompLaagLED, HIGH);

      // Zet andere LEDS uit
      digitalWrite(knop06PompAutoLED, LOW);
      digitalWrite(knop07PompUitLED, LOW);
      digitalWrite(knop09PompMiddenLED, LOW);
      digitalWrite(knop10PompHoogLED, LOW);
      
      // Zet relais 1 aan en 2, 3 en 4 uit
      digitalWrite(relais01FreqentieregelaarDi1OnOff, HIGH);
      digitalWrite(relais02FreqentieregelaarDi2Hoog, HIGH);
      digitalWrite(relais03FreqentieregelaarDi3Midden, HIGH);
      digitalWrite(relais04FreqentieregelaarDi4Laag, LOW);
    }

    // Update timer met de laatste tijd van uitvoering
    knop08Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop08LaatsteStatus = knop08HuidigeStatus;


  // Sectie:        POMP INSTELLING
  // Knop:          09
  // Functie:       Aanzetten midden stand frequentieregelaar via Arduino relais A
  // Opmerkingen:   Belangrijk is om alle contacten op het relais te schakelen zodat er maar 1 hoog is
  
  knop09HuidigeStatus = digitalRead(knop09PompMiddenKNOP);

  if(knop09HuidigeStatus == HIGH && knop09LaatsteStatus == LOW && millis() - knop09Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop pomp op midden is ingedrukt");

    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/pomp","MIDDEN"))
    {
      // Zet LED van knop aan
      digitalWrite(knop09PompMiddenLED, HIGH);

      // Zet andere LEDS uit
      digitalWrite(knop06PompAutoLED, LOW);
      digitalWrite(knop07PompUitLED, LOW);
      digitalWrite(knop08PompLaagLED, LOW);
      digitalWrite(knop10PompHoogLED, LOW);
      
      // Zet relais 1 aan en 2, 3 en 4 uit
      digitalWrite(relais01FreqentieregelaarDi1OnOff, HIGH);
      digitalWrite(relais02FreqentieregelaarDi2Hoog, HIGH);
      digitalWrite(relais03FreqentieregelaarDi3Midden, LOW);
      digitalWrite(relais04FreqentieregelaarDi4Laag, HIGH);
    }

    // Update timer met de laatste tijd van uitvoering
    knop09Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop09LaatsteStatus = knop09HuidigeStatus;


  // Sectie:        POMP INSTELLING
  // Knop:          10
  // Functie:       Aanzetten hoog stand frequentieregelaar via Arduino relais A
  // Opmerkingen:   Belangrijk is om alle contacten op het relais te schakelen zodat er maar 1 hoog is
  
  knop10HuidigeStatus = digitalRead(knop10PompHoogKNOP);

  if(knop10HuidigeStatus == HIGH && knop10LaatsteStatus == LOW && millis() - knop10Timer > 200)
  {
    // Knop is ingedrukt omdat status anders is dan de vorige loop
    Serial.println("Knop pomp op hoog is ingedrukt");

    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/pomp","HOOG"))
    {
      // Zet LED van knop aan
      digitalWrite(knop10PompHoogLED, HIGH);

      // Zet andere LEDS uit
      digitalWrite(knop06PompAutoLED, LOW);
      digitalWrite(knop07PompUitLED, LOW);
      digitalWrite(knop08PompLaagLED, LOW);
      digitalWrite(knop09PompMiddenLED, LOW);
      
      // Zet relais 1 aan en 2, 3 en 4 uit
      digitalWrite(relais01FreqentieregelaarDi1OnOff, HIGH);
      digitalWrite(relais02FreqentieregelaarDi2Hoog, LOW);
      digitalWrite(relais03FreqentieregelaarDi3Midden, HIGH);
      digitalWrite(relais04FreqentieregelaarDi4Laag, HIGH);
    }

    // Update timer met de laatste tijd van uitvoering
    knop10Timer = millis();
  }

  // Sla status weer op zodat niet steeds opnieuw getriggerd wordt
  knop10LaatsteStatus = knop10HuidigeStatus;


  // Zet MQTT client in loop mode zodat deze continue blijft zoeken naar nieuwe binnenkomende berichten
  mqttClient.loop();
}


void mqttOntvangen(char* topic, byte* payload, unsigned int length)
{
  berichtOntvangen = true;
  
  payload[length] = '\0';
  String strPayload = String((char*)payload);

  Serial.print("MQTT bericht ontvangen: ");
  Serial.println(strPayload);

  if(strPayload == "DOSEER-AAN\0")
  {
    Serial.print("Doseerpompjes AAN");
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH); 
    
  }
  if(strPayload == "DOSEER-UIT\0")
  {
    Serial.print("Doseerpompjes UIT");
    digitalWrite(2, LOW);
    digitalWrite(3, LOW); 
  }
}

void setStopcontacten(bool state)
{
  // Zet stopcontacten aan
  if(state == HIGH)
  {
    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/stopcontacten","ON"))
    {
      // Zet LED van knop aan
      digitalWrite(knop03StopcontactenLED, HIGH);

      // Zet status op aan
      shelly03Status = HIGH;
    }
  }

  // Zet stopcontacten uit
  else
  {
    // Stuur trigger naar Home Assistant
    if(mqttClient.publish("tuinhuis/stopcontacten","OFF"))
    {
      // Zet LED van knop uit
      digitalWrite(knop03StopcontactenLED, LOW);

      // Zet status op uit
      shelly03Status = LOW;
    }
  }
}

You might be having memory problems. To help with that, replace Serial.print() lines like this

with this (to put strings in Program Memory instead of SRAM):

    Serial.println(F("Knop chloor is ingedrukt"));

Things I learned from doing the MQTT thing.

Before trying to send MQTT data make sure that there is a network connection.

I use a MQTT keep alive task to run loop

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}

Might be something to consider.

Hello

Buffer overflow here : payload[length] = '\0';

Thanks guys!

  • I will replace all my Serial.println lines
  • I'm going to add the KeepAlive function. How do you send your MQTT data? Check every time if there is a connection and then send?
  • How can I avoid this buffer overflow? I tried some things but the only thing I found was adding this '\0' to the array and then convert to String but I don't think this is the best way. How can I check the payload for a string and trigger some functions best?

What buffer overflow?

here

OP should not mess with the buffer and there is no need to duplicate the memory... something like this might do the job

void mqttOntvangen(char* topic, byte* payload, unsigned int length) {
  berichtOntvangen = true;

  Serial.print("MQTT bericht ontvangen: ");
  Serial.write(payload, length);
  Serial.println();

  if (strncmp((const char*) payload, "DOSEER-AAN", 10) == 0) {
    Serial.print("Doseerpompjes AAN");
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
  }
  else if (strncmp((const char*) payload, "DOSEER-UIT", 10) == 0) {
    Serial.print("Doseerpompjes UIT");
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
  }
}

You guys are great!! Thanks so much. Will try with this changes.

I added a cast while you were typing as the compiler might complain strncmp() expects a (const char*) and not a (byte*)

I use a semaphore to determine if all is well before transmitting.

      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
      MQTTclient.publish( topicWSWDRF, MQTTinfo.c_str() );
      xSemaphoreGive( sema_MQTT_KeepAlive );

If the MQTTKeepAlive function needs to make or retablish a WiFi or MQTT connection all MQTT transmissions are held by all tasks until the semaphore
sema_MQTT_KeepAlive is freed.

I have separated the code to check for a MQTT payload and the parsing of the MQTT payload.

Here is my MQTT callback.

void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
  memset( x_message.payload, '\0', payloadSize ); // clear payload char buffer
  x_message.topic = ""; //clear topic string buffer
  x_message.topic = topic; //store new topic
  int i = 0; // extract payload
  for ( i; i < length; i++)
  {
    x_message.payload[i] = (char)payload[i];
  }
  x_message.payload[i] = '\0';
  xQueueOverwrite( xQ_Message, (void *) &x_message );// send data to queue
} // void mqttCallback(char* topic, byte* payload, unsigned int length)

quite simple and pared down with nothing but the code necessary to receive the payload and pass the payload to a parsing task.

Here is a parse MQTT payload task


void fparseMQTT( void *pvParameters )
{
  struct stu_message px_message;
  for (;;)
  {
    if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
    {
      // parse the time from the OK message and update MCU time
      if ( String(px_message.topic) == topicOK )
      {
        if ( !TimeSet)
        {
          String temp = "";
          temp =  px_message.payload[0];
          temp += px_message.payload[1];
          temp += px_message.payload[2];
          temp += px_message.payload[3];
          int year =  temp.toInt();
          temp = "";
          temp =  px_message.payload[5];
          temp += px_message.payload[6];
          int month =  temp.toInt();
          temp =  "";
          temp =  px_message.payload[8];
          temp += px_message.payload[9];
          int day =  temp.toInt();
          temp = "";
          temp = px_message.payload[11];
          temp += px_message.payload[12];
          int hour =  temp.toInt();
          temp = "";
          temp = px_message.payload[14];
          temp += px_message.payload[15];
          int min =  temp.toInt();
          rtc.setTime( 0, min, hour, day, month, year );
          log_i( "rtc  %s ", rtc.getTime() );
          TimeSet = true;
        }
      }
      //
    } //if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
    xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
    mqttOK = 0;
    xSemaphoreGive( sema_mqttOK );
  }
} // void fparseMQTT( void *pvParameters )#include <ESP32Time.h>

The task runs in an infinite for loop for (;;) but is held up waiting for queue data to become available with this line of code if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE ).

I make this structure

const int payloadSize = 100;
struct stu_message
{
  char payload [payloadSize] = {'\0'};
  String topic ;
} x_message;

for payload receipt.

String topic is turned into a buffer in setup x_message.topic.reserve(100); and proper String handling is used in the MQTT callback routine to prevent String use fragmenting the memory.