UDP Connection freezes my arduino PLC

Hi All,

First of all, here is my complete code, it's not small but i've learned before in this forum that shouldnn't be an issue. To explain the setup : i'm running a MDuino 57R+ (arduino mega clone) that is connected trough ethernet over a router to a windows computer . On that computer i have a delphi program running that connects to the PLC every 1000ms, sends a / separated string , The plc recieves the string, and sends back a simular string with all data from sensors and status.

#include <OneWire.h>
#include <DallasTemperature.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <ModbusRTUMaster.h>
#include <RS485.h>
#include "Adafruit_FONA.h"

#define FONA_RST 2

// GSM Module
HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

// Modbus 
ModbusRTUMaster master(RS485);
#define UDP_TX_PACKET_MAX_SIZE  1024
unsigned int localPort = 8001;      // local port to listen on
const uint32_t baudrate = 19200UL; 

// Modbusdata :
#define MasterModbusAdd  0
#define Cel1ModbusSensor 1    // TVOC Sensor , info here : https://www.sentera.eu/en/productdetails/outdoor-temperature--humidity--tvoc-sensor-pom/147254
#define Cel1ModbusFan    5    // VFD         , info here : https://www.sentera.eu/en/productdetails/ac-fan-speed-controller-0-10-v-din-rail-15-a/119383

// Ethernet
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 200);
EthernetUDP Udp; 

// DS18B20 sensors data : 

OneWire oneWire(3); 
DallasTemperature sensors(&oneWire);
DeviceAddress DST1 = {0x28, 0x1A, 0x6F, 0xA5, 0x13, 0x21, 0x01, 0x29};  // Temperature boiler HOT
DeviceAddress DST2 = {0x28, 0x7E, 0x65, 0x8E, 0x13, 0x21, 0x01, 0x6F};  // Temperature boiler COLD
DeviceAddress DST3 = {0x28, 0x99, 0x09, 0xD5, 0x13, 0x21, 0x01, 0xBF};  // Temperature heat exchanger IN 
DeviceAddress DST4 = {0x28, 0x07, 0xBF, 0x99, 0x13, 0x21, 0x01, 0x3C};  // Temperature heat exchanger OUT


// Declare variables : 
int Cel1Active,Cel1Running,Cel1Prior;
String result,tmp,ch;
char caracter;
uint16_t au16data[16];
uint16_t au16dataw[16];
uint8_t u8state,ModbusFunction,CurrentModbusFunction;
int TVOCTemp,NewTVOCTemp, TVOCHum,TVOCValue,TVOCStatus,TVOCLight,SetTemp,SetHum,SetFan,FanSetting,SetTDiff,SetHDiff,SetHeatDelay,SetVatTemp,SetVatTempDiff,SetEvaporatorDiff,MaxVatT,MinVatT,PressDelay,slave,AlarmCount,LowTemp,HighTemp,LowHum,HighHum;;
String SetTempSTR,SetHumSTR,SetFanSTR,SetTempDiff,SetHumDiff,SetHeatDelaySTR,VatTempSTR,VatTempDiffSTR,EvaporatorDiffSTR,MaxVatTSTR,MinVatTSTR,PressDelaySTR,LowTempSTR,HighTempSTR,LowHumSTR,HighHumSTR;
int  temp1,temp2,temp3,temp4,Signal;
bool R01,R02,R03,R04,R05,R06,R07,R08,R11,R27,AlarmActive,SimUnlocked; // relay override statusses
bool TOk, ColdQ, HotQ,HeatDelayActive,DeHumidActive,HumidActive, Heating,Cooling,MagValve;
unsigned long HeatDelayTime, PressTime;
unsigned long u32wait;
unsigned long target_time = 0L ;
const unsigned long PERIOD = 10*1000UL;
int numReadings = 5;
int currentReading = 0;
int Deviation = 2; // 4 = 40% deviation readings are ignored
unsigned long AvgTemp1,AvgTemp2,AvgTemp3,AvgTemp4;
unsigned long AlarmDelayTime = 0; // in mS 
unsigned long AlarmInterval = 10000; // in mS 
int ActiveAlarmCode =0;
char ReceiveString[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char SendString[] ="";
String SendStr ;
uint32_t lastSentTime = 0UL;
uint32_t lastGSMTime = 0UL;
uint32_t AlarmResendTime = 0UL;
long previousMillis = 0;        
long ModbusInterval = 1000;           
long TVOCInterval = 0;
char PIN[5];
const int Cel1SensorTempAdd =  0;
const int Cel1SensorHumAdd  =  9;
const int Cel1SensorTVOCAdd = 25;
const int Cel1SensorState   = 29; 
const int Cel1SensorLightAdd= 40;
const int Cel1FanSetFanAdd  = 30;
const int Cel1FanGetFanAdd  =  1;
const char* pinchar="0000"; 
const char* phonenumber="************";   
String phonenr;
bool SMSSent = false;



void setup() {
  Serial.begin(9600);
  
  // start the Ethernet
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start UDP
  Udp.begin(localPort);
  
  Serial.println("Connecting to RS485 ");
  RS485.begin(baudrate, HALFDUPLEX, SERIAL_8E1);
  master.begin(baudrate);

  u32wait = millis() + 2000;
  
  u8state = 0; 
  slave=1;
  ModbusFunction=0;
  AlarmCount =0;
  HeatDelayActive = false;
  DeHumidActive = false;
  HumidActive = false;
  Heating = false;
  Cooling = false;
  MagValve = false;
  Cel1Active = 0;
  Cel1Running = false;

  pinMode(I0_2, INPUT);   // Pressostat
  pinMode(I0_4, INPUT);   // Analog humidity sensor
  pinMode(R0_1, OUTPUT);  // Magnetic valve
  pinMode(R0_2, OUTPUT);  // Compressor
  pinMode(R0_3, OUTPUT);  // Pump cold water
  pinMode(R0_4, OUTPUT);  // Pump hot water
  pinMode(R0_5, OUTPUT);  // Valve cold water
  pinMode(R0_6, OUTPUT);  // Valve hot water
  pinMode(R0_7, OUTPUT);  // Heat resistor boiler
  pinMode(R0_8, OUTPUT);  // Steam humidifeir
  pinMode(R1_1, OUTPUT);  // Resistor heat exchanger
  pinMode(R2_7, OUTPUT);  // Alarm relay

  R01 = false;
  R02 = false;
  R03 = false;
  R04 = false;
  R05 = false;
  R06 = false;
  R07 = false;
  R08 = false;
  R11 = false;
  R27 = false;  

  // Start Temp Sensors
  sensors.begin();
  sensors.setResolution(11);

  fonaSerial->begin(4800);
  Serial.println(F("Initializing @ 4800 baud..."));
  
  if (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    while(1);
  }
  Serial.println(F("FONA is OK"));
}

 
void loop() {

       if (millis() - lastGSMTime > 15000) {

       // Unlock PINCODE
       if (SimUnlocked==false)
        {
          if (!fona.unlockSIM(pinchar)) {
              Serial.println(F("SIM Unlock Failed"));
              Serial.println(pinchar);
          } else {
              Serial.println(F("SIM Unlock OK!"));
              SimUnlocked=true;
              Serial.println(pinchar);
          }
        }

        // Get the signal strength
        Signal = fona.getRSSI();

        // check once every 15s
        lastGSMTime = millis(); 
    }
    
    
    // Request Modbus data , every 5,5s :
    if (millis() - lastSentTime > 5500) {
     
      if (ModbusFunction==0)
      {
         CurrentModbusFunction = ModbusFunction;
          // get Temperature
         if (!master.readInputRegisters(1, 0, 1)) {
         // Failure treatment
         } 
      }
      if (ModbusFunction==1)
      {
         CurrentModbusFunction = ModbusFunction;
          // get Hum
         if (!master.readInputRegisters(1, 9, 1)) {
         // Failure treatment
         } 
      }
      if (ModbusFunction==2)
      {
         CurrentModbusFunction = ModbusFunction;
         if (TVOCInterval==0) // So we get a reading immediatly, then ignore this reading 20 times , to prevent the TVOC sensor from overloading.
         {
            // get TVOC
           if (!master.readInputRegisters(1, 25, 1)) {
             // Failure treatment
           } 
       
          
         }
         TVOCInterval++; 
         if (TVOCInterval>20) { TVOCInterval=0; }
      
      }
      if (ModbusFunction==3)
      {
         CurrentModbusFunction = ModbusFunction;
          // get Sensor Status
         if (!master.readInputRegisters(1, 29, 1)) {
         // Failure treatment
         } 
      }
      if (ModbusFunction==4)
      {
         CurrentModbusFunction = ModbusFunction;
          // get Light Sensor Status
         if (!master.readInputRegisters(1, 40, 1)) {
         // Failure treatment
         } 
      }
      if (ModbusFunction==5)
      {
         CurrentModbusFunction = ModbusFunction;
          // get fan setting
         if (!master.readInputRegisters(5, 1, 1)) {
         // Failure treatment
         } 
      }
      if (ModbusFunction==6)
      { 
         CurrentModbusFunction = ModbusFunction;
          // Set fan setting
         if (!master.writeSingleRegister(5, 30, SetFan)) 
         {
          // Failure treatment
         }
      }

      ModbusFunction++;
      if (ModbusFunction>6) { ModbusFunction=0; }


    lastSentTime = millis();
  }

  // Read Modbus data
  
  if (master.isWaitingResponse()) {
    ModbusResponse response = master.available();
    if (response) {
      if (response.hasError()) {
        // Response failure treatment. You can use response.getErrorCode()
        // to get the error code.
        Serial.print("Error ");
        Serial.println(response.getErrorCode());
      } else {
        // Get the discrete inputs values from the response
        if (response.hasError()) {
          // Response failure treatment. You can use response.getErrorCode()
          // to get the error code.
          Serial.print("Error ");
          Serial.println(response.getErrorCode());
        } else {
          if (CurrentModbusFunction==0) { TVOCTemp   = response.getRegister(0); } 
          if (CurrentModbusFunction==1) { TVOCHum    = response.getRegister(0); }
          if (CurrentModbusFunction==2) { TVOCValue  = response.getRegister(0); } 
          if (CurrentModbusFunction==3) { TVOCStatus = response.getRegister(0); } 
          if (CurrentModbusFunction==4) { TVOCLight  = response.getRegister(0); }
          if (CurrentModbusFunction==5) { FanSetting = response.getRegister(0); } 
        }
      }
    }
  }
  
  
// Build a string that we will send back to the computer over UDP. 
// It contains every data of the sensors and state of the relays.

 SendStr="";
 SendStr = SendStr + digitalRead(R0_1)+"/"; //0
 SendStr = SendStr + digitalRead(R0_2)+"/"; //1
 SendStr = SendStr + digitalRead(R0_3)+"/"; //2 
 SendStr = SendStr + digitalRead(R0_4)+"/"; //3
 SendStr = SendStr + digitalRead(R0_5)+"/"; //4
 SendStr = SendStr + digitalRead(R0_6)+"/"; //5
 SendStr = SendStr + digitalRead(R0_7)+"/"; //6
 SendStr = SendStr + digitalRead(R0_8)+"/"; //7
 SendStr = SendStr + digitalRead(R1_1)+"/"; //8
 SendStr = SendStr + digitalRead(R2_7)+"/"; //9
 SendStr = SendStr + digitalRead(I0_2)+"/"; //10
 SendStr = SendStr + TVOCTemp  + "/";       //11
 SendStr = SendStr + TVOCHum   + "/";       //12
 SendStr = SendStr + TVOCValue + "/";       //13
 SendStr = SendStr + TVOCStatus+ "/";       //14
 SendStr = SendStr + TVOCLight + "/";       //15
 SendStr = SendStr + FanSetting+ "/";       //16
 SendStr = SendStr + temp1+ "/";            //17
 SendStr = SendStr + temp2+ "/";            //18
 SendStr = SendStr + temp3+ "/";            //19
 SendStr = SendStr + temp4+ "/";            //20
 SendStr = SendStr + Cel1Active+ "/";       //21   
 SendStr = SendStr + Cel1Prior +"/" ;       //22   
 SendStr = SendStr + ActiveAlarmCode+ "/" ; //23    
 SendStr = SendStr + Signal;          //24    


// Serial.println(SendStr); // For debug purpose

 char SendString[SendStr.length()+1];
 SendStr.toCharArray(SendString, SendStr.length()+1);

 // check incoming UDP data. 
 int packetSize = Udp.parsePacket();
 
  if (packetSize) {
    Udp.read(ReceiveString, UDP_TX_PACKET_MAX_SIZE);
    // send a reply to the IP address and port that sent us the packet we received
    // does this not need a delay in between ?
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(SendString);
    Udp.endPacket();
  }
  delay(10);

 // convert the recieved data . Set the settings and switch the relays in case of manual mode 
 ConvertReceivedData(ReceiveString);       

 // All data is recieved and ready, go to the celcontrol procedure
 ControlCel1();

}
// END LOOP


void ConvertReceivedData(String inputdata)
{
      // The PC sends a string to the PLC, starting with ST and ending with E . That way i can make sure the string is complete by checking if E is present at the end;
      
      if(inputdata.indexOf("E") > 0) // check if we have complete data 
      {
        // remove the leading and end strings
        inputdata.replace("ST","");
        inputdata.replace("E","");

        // Set Vars with the data of the string
      
      if (getIntValue(inputdata, ':', 10)!=0){
         SetTemp        = getIntValue(inputdata, ':', 10);
      }
      if (getIntValue(inputdata, ':', 11)!=0){
         SetHum        = getIntValue(inputdata, ':', 11);
      }
      if (getIntValue(inputdata, ':', 12)!=0){
         SetFan        = getIntValue(inputdata, ':', 12);
      }
      if (getIntValue(inputdata, ':', 13)!=0){
         SetTDiff        = getIntValue(inputdata, ':', 13);
      }
      if (getIntValue(inputdata, ':', 14)!=0){
         SetHDiff        = getIntValue(inputdata, ':', 14);
      }
      if (getIntValue(inputdata, ':', 15)!=0){
         SetHeatDelay    = getIntValue(inputdata, ':', 15);
      }
      if (getIntValue(inputdata, ':', 16)!=0){
         SetVatTemp        = getIntValue(inputdata, ':', 16);
      }
        if (getIntValue(inputdata, ':', 17)!=0){
         SetVatTempDiff        = getIntValue(inputdata, ':', 17);
      }
        if (getIntValue(inputdata, ':', 18)!=0){
         SetEvaporatorDiff        = getIntValue(inputdata, ':', 18);
      }
        if (getIntValue(inputdata, ':', 19)!=0){
         MaxVatT        = getIntValue(inputdata, ':', 19);
      }
        if (getIntValue(inputdata, ':', 20)!=0){
         MinVatT        = getIntValue(inputdata, ':', 20);
      }
        if (getIntValue(inputdata, ':', 21)!=0){
         PressDelay        = getIntValue(inputdata, ':', 21);
      }
        if (getIntValue(inputdata, ':', 22)!=0){
         LowTemp        = getIntValue(inputdata, ':', 22);
      }
        if (getIntValue(inputdata, ':', 23)!=0){
         HighTemp        = getIntValue(inputdata, ':', 23);
      }
        if (getIntValue(inputdata, ':', 24)!=0){
         LowHum        = getIntValue(inputdata, ':', 24);
      }
        if (getIntValue(inputdata, ':', 25)>0){
         HighHum        = getIntValue(inputdata, ':', 25);
      }
      if (getIntValue(inputdata, ':', 26)==0){
         Cel1Active = 0;
      }   
      else{
        Cel1Active = 1;
      }
      if (getIntValue(inputdata, ':', 27)>0){
         Cel1Prior = 1;  // PRIOR HUM
      }   
      else{
         Cel1Prior = 0;  // PRIOR TEMP
      }
      // phone number
      if (getIntValue(inputdata, ':', 28)>0){
       phonenr = String(getValue(inputdata, ':', 28));
       phonenumber = phonenr.c_str();

      }
      

      // Set Relays : 
      // Only if the cel running process is pauzed, we can switch the relays manually.
      if ( Cel1Active==0)
      {
        
    
      // Relay 1 , magnet ventil
      if (getValue(inputdata, ':', 0).equals("1"))
      {
         digitalWrite(R0_1, HIGH); 
         R01 = true;
      }
      else
      {
        digitalWrite(R0_1, LOW); 
        R01= false;
      }
      // Relay 2 : Compressor
       if (getValue(inputdata, ':', 1).equals("1"))
      {
      
        digitalWrite(R0_2, HIGH); 
        R02 = true;
      }
      else
      {
        digitalWrite(R0_2, LOW); 
        R02 = false;
      }
      // Relay 3 :
      if (getValue(inputdata, ':', 2).equals("1"))
      {
        digitalWrite(R0_3, HIGH); 
        R03 = true;
      }
      else
      {
        digitalWrite(R0_3, LOW); 
        R03 = false;
      }
      // Relay 4 :
      if (getValue(inputdata, ':', 3).equals("1"))
      {
        digitalWrite(R0_4, HIGH); 
        R04 = true;
      }
      else
      {
        digitalWrite(R0_4, LOW); 
        R04 = false;
      }
      // Relay 5 :
      if (getValue(inputdata, ':', 4).equals("1"))
      {
        digitalWrite(R0_5, HIGH); 
        R05 = true;
      }
      else
      {
        digitalWrite(R0_5, LOW); 
        R05 = false;
      }
      // Relay 6 :
      if (getValue(inputdata, ':',5).equals("1"))
      {
        digitalWrite(R0_6, HIGH); 
        R06 = true;
      }
      else
      {
        digitalWrite(R0_6, LOW); 
        R06 = false;
      }
      // Relay 7 :
      if (getValue(inputdata, ':',6 ).equals("1"))
      {
        digitalWrite(R0_7, HIGH); 
        R07 = true;
      }
      else
      {
        digitalWrite(R0_7, LOW); 
        R07 = false;
      }
      // Relay 8 :
      if (getValue(inputdata, ':', 7).equals("1"))
      {
        digitalWrite(R0_8, HIGH); 
        R08 = true;
      }
      else
      {
        digitalWrite(R0_8, LOW); 
        R08 = false;
      }
      // Relay 9 :
      if (getValue(inputdata, ':', 8).equals("1"))
      {
        digitalWrite(R1_1, HIGH); 
        R11 = true;
      }
      else
      {
        digitalWrite(R1_1, LOW); 
        R11 = false;
      }
      // Relay 9 , ALARM :
      if (getValue(inputdata, ':', 27).equals("1"))
      {
        digitalWrite(R2_7, HIGH); 
        R27 = true;
      }
      else
      {
        digitalWrite(R2_7, LOW); 
        R27 = false;
      }
    
    }

   }
}


void ControlCel1()
{

  //Check Temp Every 10s
  if (millis () - target_time >= PERIOD)
  {
    target_time += PERIOD ;   // change scheduled time exactly, no slippage will happen
    sensors.requestTemperatures();
    sensors.setWaitForConversion(false);
    int ttemp1 =  sensors.getTempC(DST1)*10;
    int ttemp2 =  sensors.getTempC(DST2)*10;
    int ttemp3 =  sensors.getTempC(DST3)*10;
    int ttemp4 =  sensors.getTempC(DST4)*10;

    if (ttemp1>-1000) 
    {
      temp1 = ttemp1;
    }
    if (ttemp2>-1000) 
    {
      temp2 = ttemp2;
    }
    if (ttemp3>-1000) 
    {
      temp3 = ttemp3;
    }
    if (ttemp4>-1000) 
    {
      temp4 = ttemp4;
    }
    sensors.setWaitForConversion(true);
}
 
   // All relays OUT
   
   if (Cel1Active==0 && Cel1Running==true)
   {
       if (R01 == false) {
          digitalWrite(R0_1, LOW); 
       }
       if (R02 == false) {
          digitalWrite(R0_2, LOW); 
       }
       if (R03 == false) {
          digitalWrite(R0_3, LOW); 
       }
       // Pomp warm water uit
       if (R04 == false) {
          digitalWrite(R0_4, LOW); 
       }
        // Ventiel koud water dicht
       if (R05 == false) {
          digitalWrite(R0_5, LOW); 
       }
       // Ventiel warm water dicht
       if (R06 == false) {
          digitalWrite(R0_6, LOW); 
       }
       // Weerstand vat uit
       if (R07 == false) {
          digitalWrite(R0_7, LOW); 
       }
        // Stoombevochtiger uit
       if (R08 == false) {
          digitalWrite(R0_8, LOW); 
       }
       if (R11 == false) {
          digitalWrite(R1_1, LOW); 
       }
       if (R27 == false) {
          digitalWrite(R2_7, LOW); 
       }
       delay (250);
       Cel1Running = false;
  }       
    
      
  // here starts the actual controlling process. 
      
  if (TVOCTemp>0 && SetTemp>0 && TVOCHum>0 && SetHum>0 && SetHDiff>0 and SetTDiff>0 && Cel1Active>0) // Make sure we have a reading
  {
 
    Cel1Running=true;
    
    //  Temperature Controlling : 
    //  1. Stop Cooling :
   
    if (TVOCTemp<SetTemp && Cooling==true)
    {
      Cooling = false;
       //pomp koud water uit , enkel indien compressor niet draait.
       if (R03 == false && digitalRead(R0_2) == LOW && DeHumidActive==false  ) 
       {
          digitalWrite(R0_3, LOW); 
       }
        // Ventiel koud water dicht
       if (R05 == false && DeHumidActive==false) {
          digitalWrite(R0_5, LOW); 
       }
     }
     
    //  Temperature Controlling : 
    // 2:  Stop Heating 
    if (TVOCTemp>SetTemp && Heating==true)
    {
      Serial.println("--Stop Heating");
       HeatDelayActive = false;
       Heating = false;
       // Pomp warm water uit, enkel indien compressor uit
       if (R04 == false && digitalRead(R0_2) == LOW && DeHumidActive==false) {
          digitalWrite(R0_4, LOW); 
       }
       // Ventiel warm water dicht
       if (R06 == false && DeHumidActive==false) {
          digitalWrite(R0_6, LOW); 
       }
       // Weerstand batterij uit
       if (R11 == false && DeHumidActive==false) {
          digitalWrite(R1_1, LOW); 
       }
     }
     
   //  Temperature Controlling : 
   // 3 :  Start Cooling , only when Temperature is Prior OR Humididity is OK
   
    if ((TVOCTemp>(SetTemp+SetTDiff)) && ( Cel1Prior == 0 || (Cel1Prior == 1 && HumidActive == false && DeHumidActive == false)))
    {
       if (Cel1Prior == 0 && HumidActive==true) 
       {
          digitalWrite(R0_8, LOW); 
       }
       if (Cel1Prior == 0 && DeHumidActive==true) 
       {
          digitalWrite(R0_6, LOW); // warm water ventiel dicht
       }
       Serial.println("--Start Cooling");
       Cooling = true;
       // Pomp koud water aan
       digitalWrite(R0_3, HIGH); 
       // Koud water ventiel open
       digitalWrite(R0_5, HIGH); 
   }

   //  Temperature Controlling : 
   // 4: Start Heating , only when Temperature is Prior OR Humididity is OK
    
    if ((TVOCTemp<(SetTemp-SetTDiff))  && ( Cel1Prior == 0 || (Cel1Prior == 1 && HumidActive == false && HumidActive == false)))
    {
       if (Cel1Prior == 0 && HumidActive==true) 
       {
          // Stoombevochtiger UIT
          digitalWrite(R0_8, LOW); 
       }
       if (Cel1Prior == 0 && DeHumidActive==true) 
       {
          // koud water ventiel UIT
          digitalWrite(R0_5, LOW); 
       }
       
       Serial.println("--Start Heating");
       Heating = true;
       
       if (HeatDelayActive == false)
       {
          HeatDelayTime = millis();
          HeatDelayActive = true;
       }
      
       if (((millis() - HeatDelayTime) >= (SetHeatDelay*60000)) && HeatDelayActive == true)
       {
           // Activeer weerstand batterij
           digitalWrite(R1_1, HIGH);    // tijdelijk uit
       }
      
       // Pomp warm water aan
       digitalWrite(R0_4, HIGH); 
       
       // Warm water ventiel open
       digitalWrite(R0_6, HIGH); 
       
    }
    
    //  Humidity Controlling : 
    //  1: Stop Drying :

    if (TVOCHum<SetHum && DeHumidActive==true)
    {
       Serial.println("--Drying Stopped");
       DeHumidActive = false ;
       HeatDelayActive = false;

       //pomp koud water uit , enkel indien compressor niet draait.
       if (R03 == false && digitalRead(R0_2) == LOW ) {
          digitalWrite(R0_3, LOW); 
       }
       // Pomp warm water uit
       if (R04 == false && digitalRead(R0_2) == LOW ) {
          digitalWrite(R0_4, LOW); 
       }
        // Ventiel koud water dicht
       if (R05 == false) {
          digitalWrite(R0_5, LOW); 
       }
       // Ventiel warm water dicht
       if (R06 == false) {
          digitalWrite(R0_6, LOW); 
       }
       // Weerstand batterij uit
       if (R11 == false) {
          digitalWrite(R1_1, LOW); 
       }
    }

    // 2: Stop Humiding
    
    if (TVOCHum>SetHum && HumidActive==true)
    {
       HumidActive = false;
       // Stoombevochtiger uit
       if (R08 == false) {
          digitalWrite(R0_8, LOW); 
       }
    }

    // 3: Start Drying 
    if  ((TVOCHum>(SetHum+SetHDiff)) && ( Cel1Prior == 1 || (Cel1Prior == 0 && Heating ==false && Cooling== false)))
    {
      Serial.println("--Drying");
      DeHumidActive = true;

      if (temp4>temp3) // Uitgaande temperatuur van de batterij word te hoog, stop bijwarmen
      {
         // Pomp warm water UIT, enkel indien compressor uit
         if (digitalRead(R0_2) == LOW) {
            digitalWrite(R0_4, LOW); 
         }
         // Ventiel warm water DICHT
         digitalWrite(R0_6, LOW); 
         // Weerstand Batterij UIT
         digitalWrite(R1_1, LOW);     
      }
      if (temp4<temp3-10) 
      {
          // Pomp warm water AAN
          digitalWrite(R0_4, HIGH); 
          // Ventiel warm water OPEN
          digitalWrite(R0_6, HIGH); 
   
          if (HeatDelayActive == false)
          {
              HeatDelayTime = millis();
              HeatDelayActive = true;
          }
          if (((millis() - HeatDelayTime) >= (SetHeatDelay*60000)) && HeatDelayActive == true)
          {
           // Weerstand Batterij AAN
           digitalWrite(R1_1, HIGH);  
          }
      }
      
      // pomp Koud Water AAN
      digitalWrite(R0_3, HIGH); 
      // Ventiel Koud Water OPEN
      digitalWrite(R0_5, HIGH); 
      // Pomp en ventiel warm water worden hierboven geregeld.
           
      // bevochtigen uit
      digitalWrite(R0_8, LOW); 
     
    }

    // 4 : Start Humiding

    if ( (TVOCHum<(SetHum-SetHDiff)) && ( Cel1Prior == 1 || (Cel1Prior == 0 && Heating ==false && Cooling== false)) )
    {
      Serial.println("--Humiding");
      HumidActive = true;
      digitalWrite(R0_8, HIGH); 
     
    }

    //Compressor controlling
    
    // 1: When temp in boiler is too high , start compressor
    
    if ((temp2 - SetVatTempDiff)>SetVatTemp)
    {
       Serial.println("--Chiller sturing AAN");
       // Magneetventiel AAN
       Serial.println("--Magneetventiel AAN");
       digitalWrite(R0_1, HIGH); 
       if (MagValve == false)
       {
        MagValve = true;
        PressTime = millis();
       }


     if  ( (millis() - PressTime) >= (PressDelay*1000))
     {
      if (digitalRead(R0_1) == HIGH && digitalRead(I0_2) == LOW )
      {
      
           //   Alarm motor won't start , disabled for now
           //   SendAlarm(10);
           //   AlarmCount++;
           
       }
     }

       
       // When Pressostat is HIGH is , start compressor , start pumps
       if (digitalRead(I0_2)==HIGH)
       {
          Serial.println("--Pressostat HIGH = Compressor ON , pumps ON");
          digitalWrite(R0_2, HIGH); 
          digitalWrite(R0_3, HIGH); 
          digitalWrite(R0_4, HIGH); 
       }

      // When Pressostat is LOW, stop compressor :
       if (digitalRead(I0_2)==LOW)
       {
          Serial.println("--Pressostat LOW = Compressor OFF , pumps OFF");
          //Compressor uit
          digitalWrite(R0_2, LOW); 
         
   
       }
   

       
    }

    // Stop compressor when temp is reached
    if (temp2<=SetVatTemp)    
    {
       //Magnet valve OFF
       MagValve = false;
       Serial.println("--Magnet ventil OFF");
       digitalWrite(R0_1, LOW); 
       digitalWrite(R0_2, LOW);  
       if (Cooling==false && Heating==false && HumidActive==false && DeHumidActive==false)
       {
          digitalWrite(R0_3, LOW); 
          digitalWrite(R0_4, LOW); 
       }
       
       // If Pressostat LOW , compressor OFF :
       if (digitalRead(I0_2)==LOW) 
       {
          Serial.println("--Pressostat LOW = Compressor OFF");
          if (R02 == false) {
             // Compressor UIT
             digitalWrite(R0_2, LOW); 
           
          }
       }
    }
    

  } // End main controlling LOOP

 
    AlarmCount = 0;
    // Set Alarms :
    if ((LowTemp>0) && TVOCTemp>0 &&  (LowTemp)>TVOCTemp)  // Temp te laag
    {
       SendAlarm(20);
       AlarmCount++;
    }
    if (HighTemp>0 && TVOCTemp>0 && (HighTemp)<TVOCTemp) // Temp te hoog
    {
       SendAlarm(21);
       ActiveAlarmCode=21;
     
       AlarmCount++;
    }
    if (LowHum>0 && TVOCHum>0 && LowHum>TVOCHum) // Hum te laag
    {
       SendAlarm(22);
        AlarmCount++;
    }
    if (HighHum>0  && TVOCHum>0 &&  HighHum<TVOCHum) // Hum te hoog
    {
       SendAlarm(23);
       AlarmCount++;
    }

    // Als koud water vat te koud is 
    if (temp1<10 && temp1< MinVatT)
    {
       SendAlarm(24);
         AlarmCount++;
    }

    // Als warm water vat te warm is 
    if (temp2>0 && temp2> MaxVatT)
    {
       SendAlarm(25);
         AlarmCount++;
    }


    if ( AlarmCount == 0 )
    {
    //    AlarmDelay.stop(); 
        ActiveAlarmCode = 0;
    }         
 

}



void SendAlarm(int AlarmCode)
{
   ActiveAlarmCode = AlarmCode; 
   /* Disabled for now
  
   if (millis() - AlarmResendTime > 600000) {
      char message[141] = "Alarm, controleer cel";  
      if (AlarmCode==20) { char message[141] = "Temperatuur cel te hoog"; }
      if (AlarmCode==21) { char message[141] = "Temperatuur cel te laag"; }
      if (AlarmCode==22) { char message[141] = "Luchtvochtigheid te laag"; }
      if (AlarmCode==23) { char message[141] = "Luchtvochtigheid te hoog"; }
      if (AlarmCode==24) { char message[141] = "Koud vat temperatuur te laag"; }
      if (AlarmCode==25) { char message[141] = "Warm vat temperatuur te hoog"; } 
      
      if (!fona.sendSMS(phonenumber, message)) {
          Serial.println(F("SMS Failed"));
        } else {
          Serial.println(F("SMS Sent!"));
        }

      AlarmResendTime=millis();
  }
  else
  {
     //Serial.println(F("Don't send yet"));
  }*/
  
}

String getValue(String data, char separator, int index)
{
    int found = 0;
    int strIndex[] = { 0, -1 };
    int maxIndex = data.length() - 1;

    for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
            found++;
            strIndex[0] = strIndex[1] + 1;
            strIndex[1] = (i == maxIndex) ? i+1 : i;
        }
    }
    return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}

int getIntValue(String data, char separator, int index)
{  
    int found = 0;
    int strIndex[] = { 0, -1 };
    int maxIndex = data.length() - 1;
    String result;
    for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
            found++;
            strIndex[0] = strIndex[1] + 1;
            strIndex[1] = (i == maxIndex) ? i+1 : i;
        }
    }
    result = found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    return result.toInt();
}



void ResetAlarm()
{
     // Reset alarm relay , not used for now
     if (R27 == false) {
          digitalWrite(R2_7, LOW); 
     }
     AlarmActive = false;
     AlarmDelayTime = 0; // Set it to 0 to make the next alarm trigger immediatly
}

void flushSerial() {
   while (Serial.available())
   Serial.read();
}

char readBlocking() {
 while (!Serial.available());
 return Serial.read();
}

Anyway, for some reason, my code seems to make my MDuino freeze. Here in the test location at home i had never any issues. In the live situation it happens anywhere from every 2 hours to every 2 days. The communication seems to stop , and most of the time so does the PLC (code freezes). I tried to add a watchdog but the PLC became very unstable.

Do i need to check the packets before sending / recieving? or do i miss something?

Any help is very much appreciated . Thanks !

I suspect it's a memory issue. Mega doesn't have that much RAM, and you're using pretty heavy libraries. Try, for beginning, to reduce your UDP transmitted data to 2-3 parameters and see if the freezes stop.
If not, then you'll have to tackle the problem more seriously. I doubt that anyone would dive into someone else's hundreds of lines of code. To make things easier, you need to prepare a minimally reproducible example - a short sketch that demonstrates the problem. Remove procedure by procedure from your code and see if the problem is gone.

Make sure you are not over writing the end of your arrays. Not looked in detail but getting the zero reference wrong is a common cause of unexplained crashes

Good tip, have to check into this.

Ya i tried to do that in the past, shorten my code. But some of the people willing to help didn't like that and wanted the complete code. That's why i did it this way.

Nevertheless : i used the same code here when i developed the system at home. And it has been running for days and weeks in a row without a problem. So i'm not sure if memory could be an issue ?

I could get rid of the Fona library for starters , and see if that helps. The other libraries are somewhat needed in any way.

People don't like snippets; so full code is great. I think that @b707 is indicating that it would be easier for helpers if you could strip down your code to a minimum that still exhibits the problematic behaviour.

Please note that Installation and Troubleshooting is not for problems with (nor for advice on) your project; see About the IDE 1.x category. Hence your topic has been moved.

// Edit
I suggest that your remove your phone number from the code that you posted here. People might start calling it :wink:

This kind of String usage can fragment your memory

either use a String.reserve or better get rid off the String class.

Furthermore you can save some RAM usage, if you put all your Fix-Text for Serial printouts in the F-Makro

furthermore I don't think your messages gets printed like you want to have.
I've just a part of your code in a MRE

void setup() {
  Serial.begin(115200);

  int AlarmCode = 20;

  char message[141] = "Alarm, controleer cel";  
      if (AlarmCode==20) { char message[141] = "Temperatuur cel te hoog"; }
      if (AlarmCode==21) { char message[141] = "Temperatuur cel te laag"; }
      if (AlarmCode==22) { char message[141] = "Luchtvochtigheid te laag"; }
      if (AlarmCode==23) { char message[141] = "Luchtvochtigheid te hoog"; }
      if (AlarmCode==24) { char message[141] = "Koud vat temperatuur te laag"; }
      if (AlarmCode==25) { char message[141] = "Warm vat temperatuur te hoog"; }

  Serial.println(message);

}

void loop() {
  // put your main code here, to run repeatedly:

}

this prints

Alarm, controleer cel

because your if's will just declare a new variable which will not be used later.

in general:
split your code in parts.
Test each part for it's own.
Put together your code parts one by one.

You have indeed a very good point about the string.reserve. I'll add it today and test this futhermore. About the alarm , i intentionally build it this way so when something is wrong it sends a text message no matter what. But all the GSM code will be removed today to see if this in not the cause.

Still, i don't think memory is the reason why the code hangs, there is something going on with the connection i think. But the arduino shouldn't lock up whenever packets don't get send or badly recieved. Isn't there anything that i can do to prevent that?

have you activated the compiler warnings in the IDE and does it show no warnings?

if not activate them and solve all warnings.

I haven't digged into the UDP library, but the Reference says

Syntax

EthernetUDP.write(message);
EthernetUDP.write(buffer, size);

Parameters

  • message: the outgoing message (char)
  • buffer: an array to send as a series of bytes (byte or char)
  • size: the length of the buffer

you are sending an Arduino String Object - which is not according to the reference.

https://www.arduino.cc/reference/en/libraries/ethernet/ethernetudp.write/

Thanks for the reply.


 char SendString[SendStr.length()+1];
 SendStr.toCharArray(SendString, SendStr.length()+1);
  
 int packetSize = Udp.parsePacket();
 
  if (packetSize) {
    Udp.read(ReceiveString, UDP_TX_PACKET_MAX_SIZE);
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(SendString);
    Udp.endPacket();
  }

I don't think i'm sending a string but a char. Maybe i should set the char buffer length fixed to a higher number?

I've set the verbose output while compiling and that only gives me an overview of the libraries used. No real warnings

you are right, I mixed it up.

however:
Get rid of the String at all.
A large enough buffer, strcat(), itoa(), dtostrf().. are your friends.

(and now someone will come up and shout out ... hey use the safe variants... )

Quiet :laughing:

How do you know? I suggest that you add some debugging to make sure that it is frozen / not frozen
e.g

void loop()
{
  heartBeat();
  
  YOUR CODE HERE
}

void hearBeat()
{
  static uint32_t lastBlink;
  if(millis() - lastBlink >=2000)
  {
    lastBlink = millis();
    digitalWrite(!digitalRead(heartbeatPin));
    Serial.print(F("Heartbeat = "));
    Serial.println(digitalRead(heartbeatPin));
  }
}

You need to add the heartbeatPin before setup() and in setup() set it as output. This should flash your the heartbeat LED (2 seconds on, two seconds off); if it stops flashing, your Mega is frozen. It also displays a message in the serial monitor; you can choose to either remove the blinking or the serial prints. Note that your use of delays can influence the rate.

Have you considered that your home setup might not be the same as your live setup; e.g. you don't have things connected to your relays or not even have relays connected.

I did not dig deep enough into your code to be sure but what if you never receive a "ST" or "E" in one packet? I would add some Serial print statements, e.g.

  if (packetSize) {
    Udp.read(ReceiveString, UDP_TX_PACKET_MAX_SIZE);
    // send a reply to the IP address and port that sent us the packet we received
    // does this not need a delay in between ?
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(SendString);
    Udp.endPacket();
  }
  delay(10);
  
  // convert the recieved data . Set the settings and switch the relays in case of manual mode
  Serial.println(F("Received: "));
  Serial.println(ReceiveString);
  ConvertReceivedData(ReceiveString);

and/or

void ConvertReceivedData(String inputdata) {
  Serial.println(F("inputdata: "));
  Serial.println(inputdata);
  
  YOUR CODE HERE

I was preparing the below and @noiasca beat me (partially) to it.

This is the way how you should not use String. It will create temporary String objects. Rather use

SendStr += digitalRead(R0_1);
SendStr += "/";

ReceiveString is a character array and ConvertReceivedData expects a String object. I suspect that this will convert a character array to a String and next the copy of the String object is passed to the function; hence you loose 1024 plus 6 bytes of memory.

When passing a String object to a function the way you do, a copy of the String object is passed to the function and hence you loose memory. If you change the function to use a reference as shown below, only the reference is passed (which is 2 bytes on a Mega).

int getIntValue(&String data, char separator, int index) {

Note 1:
I'm not quite sure if I understand how your getValue functions work; that's me, not, you. Can you post a typical message that you receive?
Note 2:
To determine if you possibly have memory issues, do a search for arduino freememory; use it in strategic places (e.g. before a function call and immediately in the function) to show how much memory you have available.

You have to be close :heart:

I feel so stupid now, amazing tips and i've implemented them all . Sadly no real improvement in keeping the system running.

To have the PLC at least running without interruption, i make it send the Millis() value to the windows computer. Whenever that locks up, i open the serial port to it and that makes the PLC reboot and back online. So far that works ok, but i want the root of the problem to be fixed. Back to the drawing board :smiley:

So what happened when you implemented heartBeat()? Did it stop beating or happily continued?

Forgot to mention this :smiley:

In the previous setup we sent the data packets over the serial port. That gave communication problems because the PLC and the pc were too far apart, at least 5m. I solved this issue by changing it to UDP and that worked fine . Now we changed the PLC because the older one didn't have modbus onboard.

In my home setup i indeed had the relays working , even under a load. Hard to believe they would cause any problem.

The ST and E is obviously a start and end indicator , that way i know that the packet should be complete. Might sound a weird way but i've used this way a dozen times before withour real issues .

About the heartBeat(), i haven't added that (yet). I don't really want to keep the serial communication open for the reason described above. Sending the millis() value to the computer
every second and every 10 seconds on the computer i check if that value changes. If it doesn't, i've lost connection or the PLC is locked up (both happen) .
Then i just open the serial connection , the PLC reboots and i wait for the message that it gets and then i close the port again, preventing any serial lockups.

You don't have to. I mentioned that you could either use the LED or Serial or both so strip the serial out.

It's far for TTL but not far for RS232/RS422/RS485 :wink:

Ya, but the system is now running at 1.5h distance from my home, so no real way to use a LED to see if it's running ok.