something is causing my communication to freeze

something is wrong with this sketch that is causing udp not to read the messages after some time.

This program sends a struct every second and i can verify that the struct is still being sent and the code is running like normal, then all of a sudden the udp receive part of this code just stops and the rest continues. i have been looking over it for a couple days now but i still have not found the problem. anyone have any idea whats causing this behavior?

i have verified it is not the sender,

main sketch,

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <EEPROM.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ArduinoOTA.h>
#include <FS.h>   //Include File System Headers

ESP8266WebServer OTA_httpServer(81);
ESP8266HTTPUpdateServer OTA_httpUpdater;
ESP8266WebServer server(80);

IPAddress sta_local_IP(192, 168, 4, 7);
IPAddress sta_gateway(192, 168, 4, 1);
IPAddress sta_subnet(255, 255, 255, 0);

bool debug = false;

WiFiUDP Udp;
unsigned int ServerPort = 4210;
unsigned int localUdpPort = 4220;
unsigned long now4=0;
const char* sta_ssid = "LCS2";
const char* sta_password = "xxxxxxxx";

void ICACHE_RAM_ATTR PwmPinISR();
void ICACHE_RAM_ATTR getPwmReading();

char incomingPacket[255];  // buffer for incoming _packets
int addr = 0;

const byte WaterSolenoid1 = 12;
const byte WaterSolenoid2 = 14;
const byte FlowSensorInterrupt = 13;  // 0 = digital pin 2
byte pulseCount;


struct {
  unsigned long SavedTotal;
  int maxgallons;
  int AlertError;
  unsigned long EEPROMWriteCountTotal;
  float flowRate;
  float FlowSensorCalibrationFactor = 26;
  float flowMilliLitres;
  float totalMilliLitres;
  bool s1 = false;
  bool s2 = false;
  unsigned long runtime = 0;
  bool command = false;
} _packet;

struct {
  unsigned long SavedTotal;
  int maxgallons;
  unsigned long EEPROMWriteCountTotal;
} waterParams;
unsigned long now = 0;
unsigned long now2 = 0;
void sendStruct(IPAddress to, char delimiter[], char delimiter2[]) {
  _packet.SavedTotal = waterParams.SavedTotal;
  _packet.maxgallons = waterParams.maxgallons;
  _packet.EEPROMWriteCountTotal = waterParams.EEPROMWriteCountTotal;
  if (digitalRead(WaterSolenoid1) == LOW) {
    _packet.s1 = true;
  } else {
    _packet.s1 = false;
  }
  if (digitalRead(WaterSolenoid2) == LOW) {
    _packet.s2 = true;
  } else {
    _packet.s2 = false;
  }
  Udp.beginPacket(to, ServerPort);
  Udp.write(delimiter);
  Udp.write((uint8_t*)&_packet, sizeof(_packet)); //cast to bytes
  Udp.write(delimiter2);
  Udp.endPacket();
}

void _writeEEPROM () {
waterParams.EEPROMWriteCountTotal++;  EEPROM.put(addr, waterParams);
  EEPROM.commit();    //Store data to EEPROM
  Serial.println("EEPROM WRITE");
}

void PwmPinISR() {
  pulseCount++;
}

void getPwmReading() {
  detachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt));
  _packet.flowRate = ((1000.0 / (millis() - now)) * pulseCount) / _packet.FlowSensorCalibrationFactor;
  _packet.flowMilliLitres = (_packet.flowRate / 60) * 1000;
  _packet.totalMilliLitres += _packet.flowMilliLitres;
  pulseCount = 0;
  attachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt), PwmPinISR, FALLING);

}
#include "watersched.h"
#include "packetHelper.h"
void setup() {
  pinMode(WaterSolenoid1, OUTPUT);
  pinMode(WaterSolenoid2, OUTPUT);
  digitalWrite(WaterSolenoid1, LOW);
  digitalWrite(WaterSolenoid2, LOW);
  Serial.begin(115200);
  SPIFFS.begin();
  EEPROM.begin(256);  //Initialize EEPROM
  EEPROM.get(addr, waterParams);
  WiFi.persistent(0);
  WiFi.mode(WIFI_STA);
  WiFi.begin(sta_ssid, sta_password);
  WiFi.config(sta_local_IP, sta_subnet, sta_gateway);
#include "OTA.h"
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  attachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt), PwmPinISR, FALLING);
  server.begin();
  Udp.begin(localUdpPort);
}

void loop() {
  OTA_httpServer.handleClient(); //ota server "htt p://x.x.x.x :81/update"
  ArduinoOTA.handle();
  server.handleClient();//Checks for web server activity
  handleWater();
  rec_packet();
  if (millis()-now4>=1000){
   _packet.command = false;
   now4=millis();
  }
  if (millis() - now >= 1000) {
    getPwmReading();
    _packet.runtime++;
    if (debug) {
      Serial.println(F("Realtime Flow Rates,"));
      Serial.print(int(_packet.flowRate));  // Print the integer part of the variable
      Serial.print(F("."));
      unsigned int frac;
      frac = (_packet.flowRate - int(_packet.flowRate)) * 10;
      Serial.print(frac, DEC) ;
      Serial.print(F(" "));
      Serial.println(F("L/min"));
      Serial.print(_packet.flowMilliLitres);
      Serial.print(F(" "));
      Serial.println(F("mL/Sec"));
      Serial.println(F("Total Quanity,"));
      Serial.print(_packet.totalMilliLitres);
      Serial.print(F(" "));
      Serial.println(F("mL"));
      Serial.print(_packet.totalMilliLitres / 3785);
      Serial.print(F(" "));
      Serial.println(F("Gallons"));
    }
    sendStruct(sta_gateway, "NODWTR", "RTWODE");
    now = millis();
  }

  if (millis() - now2 >= 1000) {

    now2 = millis();
  }



}

packetHelper.h,

void rec_packet() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(incomingPacket, 255);
    char verifyStart[7]; //NODEC1 plus null
    char verifyEnd[7]; //C1NODE plus null
    int _data;
    strncpy (verifyStart, (char*)incomingPacket, 6);//6 bytes
    strncpy (verifyEnd, (char *)incomingPacket + len - 6 , 6 );//6 bytes
    verifyStart[6] = 0; //null terminate
    verifyEnd[6] = 0; //null terminate
    if (strcmp(verifyStart, "WCT1FA") == 0) {
      if (strcmp(verifyEnd, "AF1TCW") == 0) { //FILL BOTH TANKS
        _packet.command = true;
        now4 = millis();
        _packet.totalMilliLitres = 0;
        digitalWrite(WaterSolenoid1, HIGH); //ON
        WaterWaitComp = millis();
        Serial.println(F("Both Tanks Will Fill For 9 Hours"));
        WaterSched = 1;
        Serial.println(F("$"));
      }
    }

    if (strcmp(verifyStart, "WCT1F1") == 0) {
      if (strcmp(verifyEnd, "1F1TCW") == 0) { //FILL  TANK 1
        _packet.command = true;
        now4 = millis();
        _packet.totalMilliLitres = 0;
        digitalWrite(WaterSolenoid1, HIGH); //ON
        WaterWaitComp = millis();
        Serial.println(F("Tank 1 Will Fill For 9 Hours"));
        WaterSched = 4;
        Serial.println(F("$"));
      }
    }
    if (strcmp(verifyStart, "WCT2F1") == 0) {
      if (strcmp(verifyEnd, "1F2TCW") == 0) { //FILL  TANK 2
        _packet.command = true;
        now4 = millis();
        _packet.totalMilliLitres = 0;
        digitalWrite(WaterSolenoid2, HIGH); //ON
        WaterWaitComp = millis();
        Serial.println(F("Tank 2 Will Fill For 9 Hours"));
        WaterSched = 5;
        Serial.println(F("$"));
      }
    }
    if (strcmp(verifyStart, "WCT1FC") == 0) {
      if (strcmp(verifyEnd, "CF1TCW") == 0) { //TANK 1 CUSTOM
        _packet.command = true;
        now4 = millis();
        memcpy(&_data, incomingPacket + 6 , 4); //copy 4 bytes to _data
        CustomMaxGallons = _data;
        digitalWrite(WaterSolenoid1, HIGH); //ON
        Serial.println(F("Filling with "));
        Serial.print(CustomMaxGallons);
        Serial.print(" Gallons");
        WaterSched = 8;
      }
    }
    if (strcmp(verifyStart, "WCT2FC") == 0) {
      if (strcmp(verifyEnd, "CF2TCW") == 0) { //TANK 2 CUSTOM
        _packet.command = true;
        now4 = millis();
        memcpy(&_data, incomingPacket + 6 , 4); //copy 4 bytes to _data
        CustomMaxGallons = _data;
        digitalWrite(WaterSolenoid2, HIGH); //ON
        Serial.println(F("Filling with "));
        Serial.print(CustomMaxGallons);
        Serial.print(" Gallons");
        WaterSched = 8;
        Serial.println(F("$"));
      }
    }

    if (strcmp(verifyStart, "WCTSTP") == 0) {
      if (strcmp(verifyEnd, "PTSTCW") == 0) { //TANK 2 stop
        _packet.command = true;
        now4 = millis();
        waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
        WaterSched = 0;
        digitalWrite(WaterSolenoid1, LOW);
        digitalWrite(WaterSolenoid2, LOW);
        Serial.println(F("Solenoids Closed"));
        Serial.println(F("$"));
      }
    }
    if (strcmp(verifyStart, "WCTSMG") == 0) {
      if (strcmp(verifyEnd, "GMSTCW") == 0) { //set max gallon
        _packet.command = true;
        now4 = millis();
        memcpy(&_data, incomingPacket + 6 , 4); //copy 4 bytes to _data
        waterParams.maxgallons = _data;
        _writeEEPROM();
        Serial.println(F("$"));
      }
    }
    if (strcmp(verifyStart, "WCTRFL") == 0) {
      if (strcmp(verifyEnd, "LFRTCW") == 0) { //RESET FLOW RATE EEPROM
        _packet.command = true;
        now4 = millis();
        waterParams.SavedTotal = 0;
        _writeEEPROM();
        Serial.println(F("Flow Quanity Reset"));
        Serial.println(F("$"));
      }
    }
  }
}

waterSched.h,

int TankNext = 0;
int  WaterSched = 0;
unsigned long WaterWaitComp = 0;
unsigned long WaterWaitFill = 32400000; //9hr //FILL MODE TIMER
unsigned long WaterWaitCustom = 0;
int CustomMaxGallons = 0;

void handleWater() {
  if (WaterSched == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid1, LOW); //off
      //Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid1, LOW); //off4
      // Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _writeEEPROM();
    }
  }
  if (TankNext == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
  if (WaterSched == 3) {
    if (millis() - WaterWaitComp >= WaterWaitCustom) {
      digitalWrite(WaterSolenoid1, LOW); //Off
      Serial.println(F("Done"));
      WaterWaitComp = millis();
      WaterWaitCustom = 0;
      WaterSched = 0;
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
  if (WaterSched == 4) {
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid1, LOW); //Off
      Serial.println(F("Done"));
      WaterWaitComp = millis();
      WaterSched = 0;
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
  if (WaterSched == 5) {
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid2, LOW); //Off
      Serial.println(F("Done"));
      WaterWaitComp = millis();
      WaterSched = 0;
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
  if (WaterSched == 6) {
    if (millis() - WaterWaitComp >= WaterWaitCustom) {
      digitalWrite(WaterSolenoid2, LOW); //Off
      Serial.println(F("Done"));
      WaterWaitComp = millis();
      WaterWaitCustom = 0;
      WaterSched = 0;
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
  if (WaterSched == 8) {
    if ( _packet.totalMilliLitres / 3785 >= CustomMaxGallons) {
      digitalWrite(WaterSolenoid2, LOW); //off
      digitalWrite(WaterSolenoid1, LOW); //off
      waterParams.SavedTotal = waterParams.SavedTotal +  _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      WaterSched = 0;
      _writeEEPROM();
    }
  }
}

packetHelper.h is where the code that stop respond is. the function recv(); i have many other modules with slightly different code but the same communication method and they all seem fine have not had any problems yet.

The SecondsOn; keeps counting up but its not parsing anymore udp packets.

Why is there an (apparently) identical millis() check in every single case in your switch/case? Can't you do it just once, outside that structure?

aarg:
Why is there an (apparently) identical millis() check in every single case in your switch/case? Can't you do it just once, outside that structure?

in this expression,

  if (WaterSched == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid1, LOW); //off
      //Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid1, LOW); //off4
      // Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _writeEEPROM();
    }
  }

if waterSched == 1 then Either this part will complete first,

    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid1, LOW); //off
      //Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }

or this one will complete first,

    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid1, LOW); //off4
      // Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _writeEEPROM();
    }

which ever one of those if statements complete first TankNext=1 then the same thing for the next if statement,

  if (TankNext == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }

What i have done is i added "runtime" which basically counts how many seconds the system has been running. then runtime is sent to the master node and displayed to me in webpage or serial monitor. I also added "command" that will stay true for a second after receiving a command from the master. command will be set to true and that parameter is also sent to the master for debugging reasons to see if a command is received.

for a little bit the whole system works fine. then after some time, 5 minutes-1 hour, then system will stop receiving udp packets it seems. the rest of the system works. the flow rate, the sendStruct() but Udp stops responding to send udp packets. it will work again after restart.

Yeah, okay. Sorry, I don't have time to go through all of that undocumented code, but maybe there is something wrong in the UDP routine.

aarg:
Yeah, okay. Sorry, I don't have time to go through all of that undocumented code, but maybe there is something wrong in the UDP routine.

thanks.. do you see anything wrong in the udp code? i didnt think the code was that advanced that its hard to read. and the entire packHelper is commented. were talking about 300 lines not not 2k

Here i shortened it. is this easier to look at?

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <EEPROM.h>eaders


IPAddress sta_local_IP(192, 168, 4, 7);
IPAddress sta_gateway(192, 168, 4, 1);
IPAddress sta_subnet(255, 255, 255, 0);

WiFiUDP Udp;
unsigned int ServerPort = 4210;
unsigned int localUdpPort = 4220;
unsigned long now4 = 0;
const char* sta_ssid = "LCS2";
const char* sta_password = "xxxxxxxx";

void ICACHE_RAM_ATTR PwmPinISR();
void ICACHE_RAM_ATTR getPwmReading();

char incomingPacket[255];  // buffer for incoming _packets
int addr = 0;

const byte WaterSolenoid1 = 12;
const byte WaterSolenoid2 = 14;
const byte FlowSensorInterrupt = 13;  // 0 = digital pin 2
byte pulseCount;


struct {
  unsigned long SavedTotal;
  int maxgallons;
  int AlertError;
  unsigned long EEPROMWriteCountTotal;
  float flowRate;
  float FlowSensorCalibrationFactor = 26;
  float flowMilliLitres;
  float totalMilliLitres;
  bool s1 = false;
  bool s2 = false;
  unsigned long runtime = 0;
  bool command = false;
} _packet;

struct {
  unsigned long SavedTotal;
  int maxgallons;
  unsigned long EEPROMWriteCountTotal;
} waterParams;

unsigned long now = 0;
unsigned long now2 = 0;

void sendStruct(IPAddress to, char delimiter[], char delimiter2[]) {
  _packet.SavedTotal = waterParams.SavedTotal;
  _packet.maxgallons = waterParams.maxgallons;
  _packet.EEPROMWriteCountTotal = waterParams.EEPROMWriteCountTotal;
  if (digitalRead(WaterSolenoid1) == LOW) {
    _packet.s1 = true;
  } else {
    _packet.s1 = false;
  }
  if (digitalRead(WaterSolenoid2) == LOW) {
    _packet.s2 = true;
  } else {
    _packet.s2 = false;
  }
  Udp.beginPacket(to, ServerPort);
  Udp.write(delimiter);
  Udp.write((uint8_t*)&_packet, sizeof(_packet)); //cast to bytes
  Udp.write(delimiter2);
  Udp.endPacket();
}

void _writeEEPROM () {
  waterParams.EEPROMWriteCountTotal++;  EEPROM.put(addr, waterParams);
  EEPROM.commit();    //Store data to EEPROM
  Serial.println("EEPROM WRITE");
}

void PwmPinISR() {
  pulseCount++;
}

void getPwmReading() {
  detachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt));
  _packet.flowRate = ((1000.0 / (millis() - now)) * pulseCount) / _packet.FlowSensorCalibrationFactor;
  _packet.flowMilliLitres = (_packet.flowRate / 60) * 1000;
  _packet.totalMilliLitres += _packet.flowMilliLitres;
  pulseCount = 0;
  attachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt), PwmPinISR, FALLING);

}

int TankNext = 0;
int  WaterSched = 0;
unsigned long WaterWaitComp = 0;
unsigned long WaterWaitFill = 32400000; //9hr //FILL MODE TIMER
unsigned long WaterWaitCustom = 0;
int CustomMaxGallons = 0;

void handleWater() {
  if (WaterSched == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid1, LOW); //off
      //Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid1, LOW); //off4
      // Serial.println(F("Tank 1 Done"));
      WaterWaitComp = millis();
      digitalWrite(WaterSolenoid2, HIGH); //ON
      WaterSched = 0;
      _packet.totalMilliLitres = 0;
      TankNext = 1;//
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _writeEEPROM();
    }
  }
  if (TankNext == 1) {
    if (_packet.totalMilliLitres / 3785 >= waterParams.maxgallons) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
    if (millis() - WaterWaitComp >= WaterWaitFill) {
      digitalWrite(WaterSolenoid2, LOW); //off
      TankNext = 0;
      WaterWaitCustom = 0;
      WaterWaitComp = millis();
      waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;
      _packet.totalMilliLitres = 0;
      _writeEEPROM();
    }
  }
}

void rec_packet() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(incomingPacket, 255);
    char verifyStart[7]; // char array to be null terminated
    char verifyEnd[7]; //char array to be null terminated
    int _data;
    strncpy (verifyStart, (char*)incomingPacket, 6);// copy fist 6 bytes of message into verifyStart
    strncpy (verifyEnd, (char *)incomingPacket + len - 6 , 6 );//copy last 6 bytes into verifyend
    verifyStart[6] = 0; //null terminate char array
    verifyEnd[6] = 0; //null terminate char array
    if (strcmp(verifyStart, "WCT1FA") == 0) {
      if (strcmp(verifyEnd, "AF1TCW") == 0) { //FILL BOTH TANKS command
        _packet.command = true;
        now4 = millis();
        _packet.totalMilliLitres = 0;
        digitalWrite(WaterSolenoid1, HIGH); //ON
        WaterWaitComp = millis();
        Serial.println(F("Both Tanks Will Fill For 9 Hours"));
        WaterSched = 1;
      }
    }
  }
}

void setup() {
  pinMode(WaterSolenoid1, OUTPUT);
  pinMode(WaterSolenoid2, OUTPUT);
  digitalWrite(WaterSolenoid1, LOW);
  digitalWrite(WaterSolenoid2, LOW);
  Serial.begin(115200);
  SPIFFS.begin();
  EEPROM.begin(256);  //Initialize EEPROM
  EEPROM.get(addr, waterParams);
  WiFi.persistent(0);
  WiFi.mode(WIFI_STA);
  WiFi.begin(sta_ssid, sta_password);
  WiFi.config(sta_local_IP, sta_subnet, sta_gateway);
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  attachInterrupt(digitalPinToInterrupt(FlowSensorInterrupt), PwmPinISR, FALLING);
  Udp.begin(localUdpPort);
}

void loop() {
  handleWater();
  rec_packet();
  if (millis() - now4 >= 1000) {
    _packet.command = false;
    now4 = millis();
  }
  if (millis() - now >= 1000) {
    getPwmReading();
    _packet.runtime++;
    sendStruct(sta_gateway, "NODWTR", "RTWODE");
    now = millis();
  }
}

for a little bit the whole system works fine. then after some time, 5 minutes-1 hour, then system will stop receiving udp packets it seems. the rest of the system works. the flow rate, the sendStruct() but Udp stops responding to send udp packets.

There are eight different messages in packetHelper.h. Some have EEprom writes, some have memcpy. Can you see any pattern to when the program fails, as to which was the last message received?

cattledog:
There are eight different messages in packetHelper.h. Some have EEprom writes, some have memcpy. Can you see any pattern to when the program fails, as to which was the last message received?

I have been testing that trying to narrow down to something. i mostly use "waterSched '8' so "WCT1FC" and the stop command. but hey seems to all function about the same until the freeze. they all stop responding

I would like to add, i use multiple different modules with about the exact same udp packet code. this is the only module that stops responding. this is also the only module that i use Interrupts.

below is a snippet from my other module that works fine

void recPacket() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(incomingPacket, 255);
    char verifyStart[7]; //NODEC1 plus null
    char verifyEnd[7]; //C1NODE plus null
    unsigned long _data;
    strncpy (verifyStart, (char*)incomingPacket, 6);//6 bytes
    strncpy (verifyEnd, (char *)incomingPacket + len - 6 , 6 );//6 bytes
    memcpy(&_data, incomingPacket + 6 , 4); //copy 4 bytes to _data
    verifyStart[6] = 0; //null terminate
    verifyEnd[6] = 0; //null terminate
    if (strcmp(verifyStart, "T1ONDE") == 0) {
      if (strcmp(verifyEnd, "UDT1ON") == 0) {
        _EEPROM.timer1OnTime = _data;
        Serial.println("update0");
        writeEEPROM = true;
        now4 = millis();
      }
    }
    if (strcmp(verifyStart, "T1OFFE") == 0) {
      if (strcmp(verifyEnd, "UT1OFF") == 0) {
        _EEPROM.timer1OffTime = _data;
        Serial.println("update1");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }


    if (strcmp(verifyStart, "T2ONDE") == 0) {
      if (strcmp(verifyEnd, "UDT2ON") == 0) {
        _EEPROM.timer2OnTime = _data;
        Serial.println("update2");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }
    if (strcmp(verifyStart, "T2OFFE") == 0) {
      if (strcmp(verifyEnd, "UT2OFF") == 0) {
        _EEPROM.timer2OffTime = _data;
        Serial.println("update3");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }
    if (strcmp(verifyStart, "T3ONDE") == 0) {
      if (strcmp(verifyEnd, "UDT3ON") == 0) {
        _EEPROM.timer3OnTime = _data;
        Serial.println("update4");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }
    if (strcmp(verifyStart, "T3OFFE") == 0) {
      if (strcmp(verifyEnd, "UT3OFF") == 0) {
        _EEPROM.timer3OffTime = _data;
        Serial.println("update5");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }
    if (strcmp(verifyStart, "T4ONDE") == 0) {
      if (strcmp(verifyEnd, "UDT4ON") == 0) {
        _EEPROM.timer4OnTime = _data;
        Serial.println("update6");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }
    if (strcmp(verifyStart, "T4OFFE") == 0) {
      if (strcmp(verifyEnd, "UT4OFF") == 0) {
        _EEPROM.timer4OffTime = _data;
        Serial.println("update7");
        writeEEPROM = true;
        now4 = millis();
        //Serial.println("struct recieved");
        //connected = true;
      }
    }

    if (strcmp(verifyStart, "NODDI1") == 0) {
      if (strcmp(verifyEnd, "ID1ODE") == 0) {
        _EEPROM.t1enabled = false;
        timer1State = 0;
        digitalWrite(relay[0], HIGH);
        writeEEPROM = true;
        Serial.println("1");
      }
    }
    if (strcmp(verifyStart, "NODEN1") == 0) {
      if (strcmp(verifyEnd, "1NEODE") == 0) {
        _EEPROM.t1enabled = true;
        timer1State = 0;
        writeEEPROM = true;
        Serial.println("1");
      }
    }


    if (strcmp(verifyStart, "NODDI2") == 0) {
      if (strcmp(verifyEnd, "ID2ODE") == 0) {
        _EEPROM.t2enabled = false;
        timer2State = 0;
        digitalWrite(relay[1], HIGH);
        writeEEPROM = true;
        Serial.println("3");
      }
    }
    if (strcmp(verifyStart, "NODEN2") == 0) {
      if (strcmp(verifyEnd, "2NEODE") == 0) {
        _EEPROM.t2enabled = true;
        timer2State = 0;
        writeEEPROM = true;
        Serial.println("4");
      }
    }

    if (strcmp(verifyStart, "NODDI3") == 0) {
      if (strcmp(verifyEnd, "ID3ODE") == 0) {
        _EEPROM.t3enabled = false;
        timer3State = 0;
        digitalWrite(relay[2], HIGH);
        writeEEPROM = true;
        Serial.println("5");
      }
    }
    if (strcmp(verifyStart, "NODEN3") == 0) {
      if (strcmp(verifyEnd, "3NEODE") == 0) {
        _EEPROM.t3enabled = true;
        timer3State = 0;
        writeEEPROM = true;
        Serial.println("6");
      }
    }

    if (strcmp(verifyStart, "NODDI4") == 0) {
      if (strcmp(verifyEnd, "ID4ODE") == 0) {
        _EEPROM.t4enabled = false;
        timer4State = 0;
        digitalWrite(relay[3], HIGH);
        writeEEPROM = true;
        Serial.println("76");
      }
    }
    if (strcmp(verifyStart, "NODEN4") == 0) {
      if (strcmp(verifyEnd, "4NEODE") == 0) {
        _EEPROM.t4enabled = true;
        timer4State = 0;
        writeEEPROM = true;
        Serial.println("8");
      }
    }
    if (strcmp(verifyStart, "NODENA") == 0) {
      if (strcmp(verifyEnd, "ANEODE") == 0) {
        _EEPROM.enabled = true;
        timer1State = 0;
        timer2State = 0;
        timer3State = 0;
        timer4State = 0;
        timerState = 1;
        Serial.println("9");
        writeEEPROM = true;
      }
    }
    if (strcmp(verifyStart, "NODDIA") == 0) {
      if (strcmp(verifyEnd, "IDEODE") == 0) {
        _EEPROM.enabled = false;
        digitalWrite(relay[0], HIGH);
        digitalWrite(relay[1], HIGH);
        digitalWrite(relay[2], HIGH);
        digitalWrite(relay[3], HIGH);
        timer1State = 0;
        timer2State = 0;
        timer3State = 0;
        timer4State = 0;
        timerState = 1;
        Serial.println("10");
        writeEEPROM = true;
      }
    }
  }
}

although in these lines,

waterParams.SavedTotal = waterParams.SavedTotal + _packet.totalMilliLitres;

im adding a float to an unsigned long. is this okay?

When i send command to that module from the master,

Udp.beginPacket(Client6, ServerPort);
Udp.write("WCTSTP");
Udp.write("PTSTCW");
Udp.endPacket();

I found a big problem in one of my other programs. apparently i had assigned another module with the same ip address as the problem module.

Possibly not related to your problem but variables that are used in both main code and ISR should be declared volatile.

sterretje:
Possibly not related to your problem but variables that are used in both main code and ISR should be declared volatile.

thanks. i used to have,

volatile byte pulseCount;

but i changed it not knowing what i was doing. Just to clarify, "any" variable defined in both areas should be volatile?

I ask because of all these variables,

  _packet.flowRate = ((1000.0 / (millis() - now)) * pulseCount) / _packet.FlowSensorCalibrationFactor;
  _packet.flowMilliLitres = (_packet.flowRate / 60) * 1000;
  _packet.totalMilliLitres += _packet.flowMilliLitres;
  pulseCount = 0;
  attachInterrupt(digita

I did not dig through your code, just noticed the pulseCount.

sterretje:
I did not dig through your code, just noticed the pulseCount.

you act like the code is hard to read. i literally shortened it to 200 lines of code.

"variables that are used in both main code and ISR should be declared volatile."

I dont know anything about ISR really. i cant tell if they of they all need to be volatile like i asked or not. I think if i fully understood i wouldn't have asked the question in the first place. so maybe cut me some slack.