Hi Everybody,
I have a real strange phenomen with a ESP32 running ESPUI and sending UDP-messages.
After some time the website build with the ESPUI-library is no longer reachable.
Browser says "website did not answer"
using ping results in
C:\Users\choic>ping 192.168.1.234
Ping wird ausgeführt für 192.168.1.234 mit 32 Bytes Daten:
Zeitüberschreitung der Anforderung.
Antwort von 192.168.1.73: Zielhost nicht erreichbar.
Zeitüberschreitung der Anforderung.
Zeitüberschreitung der Anforderung.
Ping-Statistik für 192.168.1.234:
Pakete: Gesendet = 4, Empfangen = 1, Verloren = 3
(75% Verlust),
C:\Users\choic>
but sending UDP-messags from this ESP32 still works ! ?? Hu???
I am very sure that sending the UDP-messages works because I have a computer running a python-script that receives the UDP-messages
2024.03.31; 22: 43: 24 ; 192.168.1.234 ; 2024.03.31; 22: 43: 24 ; reconnectCnt: 0 ; UDP_Msg - Cnt: 616 ; BoardType: ESP32-OLD-CP210x_COM3
2024.03.31; 22: 43: 29 ; 192.168.1.234 ; 2024.03.31; 22: 43: 29 ; reconnectCnt: 0 ; UDP_Msg - Cnt: 617 ; BoardType: ESP32-OLD-CP210x_COM3
If I lookup the WiFi-router the router shows ESP32 is present with IP-Adress 192.168.1.234
full signal-strength (ESPs are 1 m away from the router)
Now what could make an ESP32 sending UDP-messages but beeing unreachable for pings and website-requests?
What keeps the ESP32 connected is if I use auto-refresh of the website once every two minutes
I have another ESP32-S3 connected to the same router which shows the same phenomen:
refreshing the website every two minutes connecting stays
no refreshing connection gets lost
Then there is another ESP8266 running ESP-DASH which stays connected all the time without doing anything.
and ping-time of this ESP8266 is a single millisecond
C:\Users\choic>ping 192.168.1.81
Ping wird ausgeführt für 192.168.1.81 mit 32 Bytes Daten:
Antwort von 192.168.1.81: Bytes=32 Zeit=1ms TTL=255
Antwort von 192.168.1.81: Bytes=32 Zeit=1ms TTL=255
Antwort von 192.168.1.81: Bytes=32 Zeit=1ms TTL=255
Antwort von 192.168.1.81: Bytes=32 Zeit=1ms TTL=255
Ping-Statistik für 192.168.1.81:
Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0
(0% Verlust),
Ca. Zeitangaben in Millisek.:
Minimum = 1ms, Maximum = 1ms, Mittelwert = 1ms
while ping of the ESP32-S3 is aound 200 milliseconds for a local network with microcontroller with full signal-strength and 72 MBit speed
C:\Users\choic>ping 192.168.1.91
Ping wird ausgeführt für 192.168.1.91 mit 32 Bytes Daten:
Antwort von 192.168.1.91: Bytes=32 Zeit=189ms TTL=255
Antwort von 192.168.1.91: Bytes=32 Zeit=206ms TTL=255
Antwort von 192.168.1.91: Bytes=32 Zeit=208ms TTL=255
Antwort von 192.168.1.91: Bytes=32 Zeit=205ms TTL=255
Ping-Statistik für 192.168.1.91:
Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0
(0% Verlust),
Ca. Zeitangaben in Millisek.:
Minimum = 189ms, Maximum = 208ms, Mittelwert = 202ms
Oh oops and with code a much more detailed analysis is possible
#define BOARD_ID "ESP32-OLD-CP210x_COM3"
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
#define dbgi(myFixedText, variableName,timeInterval) \
{ \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
}
#define dbgc(myFixedText, variableName) \
{ \
static long lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
#define dbgcf(myFixedText, variableName) \
{ \
static float lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *
#include <Preferences.h> // see https://github.com/espressif/arduino-esp32/tree/master/libraries/Preferences
Preferences myPrefInstance; // create an instance of the object
#include <DNSServer.h>
DNSServer dnsServer;
#include <SafeString.h> // https://github.com/PowerBroker2/SafeString
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <AsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#include <ESPUI.h> // see https://github.com/s00500/ESPUI
#include <time.h> // time() ctime()
#define MaxMsgLength 1024
createSafeString(UDP_Msg_SS, MaxMsgLength);
#define MaxHeaderLength 32
createSafeString(UdpHeader_SS, MaxHeaderLength);
createSafeString(Msg1_SS, 128);
createSafeString(Msg2_SS, 128);
createSafeString(Msg3_SS, 128);
createSafeString(Msg4_SS, 128);
createSafeString(Msg5_SS, 128);
createSafeString(MultiPurp_SS, 128);
#define MaxTimeStampLength 64
createSafeString(TimeStamp_SS, MaxTimeStampLength);
cSF(Date_SS, 32);
cSF(multiPurp_SS, 1024);
cSF(text1_SS, 128);
cSF(text2_SS, 128);
cSF(text3_SS, 128);
cSF(BoardType_SS, 128);
const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);
time_t now; // this is the epoch
tm myTimeInfo; // the structure tm holds time information in a more convient way
const char* ntpServer = "2.de.pool.ntp.org";
const long gmtOffset_sec = 7200;
const int daylightOffset_sec = 0;
IPAddress remoteIP(192, 168, 1, 255); // receiver-IP
IPAddress broadCastIP(192, 168, 1, 255); // receiver-IP
IPAddress remoteAPIP(192, 168, 4, 255); // receiver-IP
IPAddress broadCastAPIP(192, 168, 4, 255); // receiver-IP
int remotePort = 4210; // receiver port to listen on must match the portnumber the receiver is listening to
IPAddress local_IP;
WiFiUDP Udp;
#define UDP_RcvBufLen 256
char UDP_RcvBuffer[UDP_RcvBufLen];
unsigned long reconnectCnt = 0;
unsigned long OnlineStart;
unsigned long UDP_SendTimer;
unsigned long WiFiDisCDetected;
unsigned long WiFiDisConnectedDone;
unsigned long WiFiReconnectDone;
unsigned long WiFiISreconected;
int myCounter = 0;
char HeaderDelimiter = '$'; // must match the delimiter defined in the python-code
unsigned long MyTestTimer = 0; // Timer-variables MUST be of type unsigned long
const byte OnBoard_LED = 2;
unsigned long SwitchStateTimer = 0;
int myWiFiStatus;
int myLastWiFiStatus;
const char *home_ssid = "SSID"; // your network SSID (name)
const char *home_password = "password"; // your network key
char ap_ssid[25];
const char* AP_password = "espui";
const char* AP_hostname = "espui";
uint16_t myTab1_ID;
uint16_t myTab2_ID;
uint16_t statusLabel_ID;
uint16_t text1_ID;
uint16_t text2_ID;
uint16_t text3_ID;
uint16_t buttonSave_ID;
uint16_t buttonSetDefault_ID;
#define myNameSpace "Texte"
const boolean ReadOnly = true;
const boolean ReadWrite = !ReadOnly; // not-operator inverts the value
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__) );
Serial.print( F(" compiled ") );
Serial.print( F(__DATE__) );
Serial.print( F(" ") );
Serial.println( F(__TIME__) );
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
void text1Callback(Control *sender, int eventType) {
Serial.print("ID: ");
Serial.print(sender->id);
Serial.print(" ");
Serial.println(sender->label);
Serial.print("eventType:");
Serial.println(eventType);
if (eventType == T_VALUE) {
multiPurp_SS = "";
multiPurp_SS += String(sender->label).c_str();
multiPurp_SS += " changed to #";
multiPurp_SS += String(sender->value).c_str();
multiPurp_SS += "#";
Serial.println(multiPurp_SS);
if (sender->id == text1_ID) {
text1_SS = "";
text1_SS += String(sender->value).c_str();
}
if (sender->id == text2_ID) {
text2_SS = "";
text2_SS += String(sender->value).c_str();
}
if (sender->id == text3_ID) {
text3_SS = "";
text3_SS += String(sender->value).c_str();
}
}
Serial.println();
ESPUI.updateLabel(statusLabel_ID, multiPurp_SS.c_str() ); //String(rndString1));
}
void buttonSetDefaultCallback(Control* sender, int eventType) {
Serial.print("ID: ");
Serial.print(sender->id);
Serial.print(" ");
Serial.println(sender->label);
if (eventType == B_UP) {
Serial.println("Set default values");
}
}
void buttonSaveCallback(Control* sender, int eventType) {
Serial.print("ID: ");
Serial.print(sender->id);
Serial.print(" ");
Serial.println(sender->label);
if (eventType == B_UP) {
SafePreferences();
}
}
void ConnectToWiFi() {
int myCount = 0;
#if defined(ESP32)
WiFi.setHostname(AP_hostname);
#else
WiFi.hostname(AP_hostname);
#endif
// try to connect to existing network
WiFi.begin(home_ssid, home_password);
Serial.print("\n\nTry to connect to existing network");
Serial.print(" named #");
Serial.print(home_ssid);
Serial.println("#");
// Wait for connection
while (WiFi.status() != WL_CONNECTED && myCount < 31) {
yield(); // very important to execute yield to make it work
BlinkHeartBeatLED(OnBoard_LED, 50); // blink LED fast during attempt to connect
if ( TimePeriodIsOver(MyTestTimer, 500) ) { // once every 500 miliseconds
Serial.print("."); // print a dot
myCount++;
if (myCount > 120) { // after 120 dots = 60 seconds
Serial.println();
Serial.print("not connected ");
}
}
}
if (WiFi.status() == WL_CONNECTED ) {
Serial.println("");
Serial.print("Connected to #");
Serial.print(home_ssid);
Serial.print("# IP address: ");
Serial.println(WiFi.localIP());
}
}
void printWiFiModeAndIP() {
if (WiFi.getMode() == WIFI_AP) {
Serial.print("ESP is its OWN accesspoint with SSID ");
Serial.println(ap_ssid);
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP() );
}
else {
Serial.print("ESP connected to existing WLAN named ");
Serial.println(home_ssid);
Serial.print("IPAdress: ");
Serial.println(WiFi.localIP() );
}
}
void setup() {
BoardType_SS = BOARD_ID;
Serial.begin(115200);
PrintFileNameDateTime();
Serial.print("Board-type:");
Serial.println(BoardType_SS);
#if defined(ESP32)
WiFi.setHostname(AP_hostname);
#else
WiFi.hostname(AP_hostname);
#endif
ConnectToWiFi();
synchroniseWith_NTP_Time();
if (WiFi.status() != WL_CONNECTED) {
Serial.println("not connected to WiFi");
}
printWiFiModeAndIP();
dnsServer.start(DNS_PORT, "*", apIP);
defineUI();
ESPUI.begin(BOARD_ID);
// LoadPreferences() must be called AFTER ESPUI.begin() because it uses ESPUI-variables
LoadPreferences();
}
void loop() {
dnsServer.processNextRequest();
BlinkHeartBeatLED(OnBoard_LED, 500);
myWiFiStatus = WiFi.status();
if (myLastWiFiStatus != myWiFiStatus) {
Serial.print("WiFiStatus changed from ");
printWiFiStatus(myLastWiFiStatus);
Serial.print(" to ");
printWiFiStatus(myWiFiStatus);
myLastWiFiStatus = myWiFiStatus;
}
if ( TimePeriodIsOver(MyTestTimer, 5000) ) {
multiPurp_SS = BOARD_ID;
time(&now); // read the current time
localtime_r(&now, &myTimeInfo); // update the structure tm with the current time
StoreTimeStampIntoSS(TimeStamp_SS, myTimeInfo);
multiPurp_SS += " ";
multiPurp_SS += TimeStamp_SS;
ESPUI.updateLabel(statusLabel_ID, multiPurp_SS.c_str() ); //String(rndString1));
}
if (TimePeriodIsOver(UDP_SendTimer, 5000)) {
myWiFiStatus = WiFi.status();
printWiFiStatus(myWiFiStatus );
if (myWiFiStatus != WL_CONNECTED) {
WiFiDisCDetected = micros();
Serial.println("WiFi.status() != WL_CONNECTED");
printWiFiStatus(myWiFiStatus );
WiFi.disconnect();
WiFiDisConnectedDone = micros();
Serial.println("WiFi.disconnect() done");
printWiFiStatus(WiFi.status());
WiFi.reconnect();
WiFiReconnectDone = micros();
Serial.println("WiFi.reconnect() done ");
printWiFiStatus(WiFi.status() );
reconnectCnt++;
OnlineStart = millis();
unsigned long myWaitTimer = millis();
while ( (millis() - myWaitTimer < 5000) ) {
yield();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("early reconnected");
break;
}
}
WiFiISreconected = micros();
Serial.println("waiting done");
Serial.print("DISC detected to WiFi.disconnect() done:");
Serial.println( WiFiDisConnectedDone - WiFiDisCDetected);
Serial.print("DISC detected to WiFi.reconnect() done:");
Serial.println( WiFiReconnectDone - WiFiDisCDetected);
Serial.print("DISC detected to reconnected:");
Serial.println(WiFiISreconected - WiFiDisCDetected );
printWiFiStatus(WiFi.status() );
//dbgc("WiFi", WiFi.status() );
}
if (WiFi.status() == WL_CONNECTED) {
SendUDP_Msg();
}
else {
printWiFiStatus(WiFi.status() );
Serial.println("no UDP - Message send");
OnlineStart = millis();
}
Serial.println();
Serial.println();
}
}
void defineUI() {
// shown above all tabs
statusLabel_ID = ESPUI.addControl(ControlType::Label, "last action", "Last Action: none", ControlColor::Turquoise);
dbg("dUI", statusLabel_ID);
/*
text1_ID = ESPUI.addControl(ControlType::Text, "Text 1", "", ControlColor::Alizarin,0, &text1Callback);
text2_ID = ESPUI.addControl(ControlType::Text, "Text 2", "", ControlColor::Alizarin,0, &text1Callback);
text3_ID = ESPUI.addControl(ControlType::Text, "Text 3", "", ControlColor::Alizarin,0, &text1Callback);
*/
text1_ID = ESPUI.text("Text-Input 1", &text1Callback, ControlColor::Alizarin, "Text 1");
text2_ID = ESPUI.text("Text-Input 2", &text1Callback, ControlColor::Alizarin, "Text 2");
text3_ID = ESPUI.text("Text-Input 3", &text1Callback, ControlColor::Alizarin, "Text 3");
dbg("dUI", text1_ID);
dbg("dUI", text2_ID);
dbg("dUI", text3_ID);
// ESPUI.button("Push Button", &buttonCallback, ControlColor::Peterriver, "Press");
buttonSave_ID = ESPUI.button("Save to Flash ", &buttonSaveCallback, ControlColor::Peterriver, "Save ");
buttonSetDefault_ID = ESPUI.button("Set Default ", &buttonSetDefaultCallback, ControlColor::Peterriver, "Default ");
dbg("dUI", buttonSave_ID);
dbg("dUI", buttonSetDefault_ID);
}
void LoadPreferences() {
Serial.println("LoadPreferences");
myPrefInstance.begin(myNameSpace, ReadOnly);
// ID default value
text1_SS = myPrefInstance.getString ("Text_1", "Text 1").c_str();
text2_SS = myPrefInstance.getString ("Text_2", "Text 2").c_str();
text3_SS = myPrefInstance.getString ("Text_3", "Text 3").c_str();
dbg("LP", text1_SS);
dbg("LP", text2_SS);
dbg("LP", text3_SS);
myPrefInstance.end();
ESPUI.updateControlValue(text1_ID, text1_SS.c_str() );
ESPUI.updateControlValue(text2_ID, text2_SS.c_str() );
ESPUI.updateControlValue(text3_ID, text3_SS.c_str() );
}
void SafePreferences() {
Serial.println("SafePreferences");
myPrefInstance.begin(myNameSpace, ReadWrite);
//myPrefInstance.clear();
myPrefInstance.putString ("Text_1" , text1_SS.c_str() );
myPrefInstance.putString ("Text_2" , text2_SS.c_str() );
myPrefInstance.putString ("Text_3" , text3_SS.c_str() );
LoadPreferences();
}
void SendUDP_Msg() {
Serial.print(F("Send Message to #"));
Serial.print(remoteIP);
Serial.print(F(": "));
Serial.println(remotePort);
Serial.print("reconnectCnt: ");
Serial.println(reconnectCnt);
UDP_Msg_SS = "";
UdpHeader_SS = BOARD_ID;
UDP_Msg_SS = UdpHeader_SS;
UDP_Msg_SS += HeaderDelimiter;
StoreTimeStampIntoSS(TimeStamp_SS, myTimeInfo);
UDP_Msg_SS += TimeStamp_SS;
ipToSafeString(MultiPurp_SS, WiFi.localIP() );
UDP_Msg_SS += " ; ";
UDP_Msg_SS += MultiPurp_SS;
time(&now); // read the current time
localtime_r(&now, &myTimeInfo); // update the structure tm with the current time
StoreTimeStampIntoSS(TimeStamp_SS, myTimeInfo);
UDP_Msg_SS += " ; ";
UDP_Msg_SS += TimeStamp_SS;
UDP_Msg_SS += " ; ";
UDP_Msg_SS += "reconnectCnt: ";
UDP_Msg_SS += reconnectCnt;
UDP_Msg_SS += " ; UDP_Msg - Cnt: ";
UDP_Msg_SS += myCounter++;
UDP_Msg_SS += " ; BoardType: ";
UDP_Msg_SS += BoardType_SS;
//Serial.print("WiFi.status() = ");
//Serial.println(WiFi.status() );
Serial.print(F("Send UDP_Msg #"));
Serial.print(UDP_Msg_SS);
Serial.println("#");
remoteIP = broadCastIP;
Udp.beginPacket(remoteIP, remotePort);
Udp.write((const uint8_t*)UDP_Msg_SS.c_str(), UDP_Msg_SS.length());
Udp.endPacket();
}
// Message callback of WebSerial
/*
void recvMsg(uint8_t *data, size_t len) {
WebSerial.println("Received Data...");
multiPurp_SS = "";
for (int i = 0; i < len; i++) {
multiPurp_SS += char(data[i]);
}
WebSerial.println(multiPurp_SS);
Serial.print("Webserial receievd #");
Serial.print(multiPurp_SS);
Serial.println("#");
}
*/
void ipToSafeString(SafeString & p_RefToSS, IPAddress ip) {
p_RefToSS = ip[0];
p_RefToSS += ".";
p_RefToSS += ip[1];
p_RefToSS += ".";
p_RefToSS += ip[2];
p_RefToSS += ".";
p_RefToSS += ip[3];
}
void SetDateStr() {
time(&now); // read the current time
localtime_r(&now, &myTimeInfo); // update the structure tm with the current time
//if (myTimeInfo.tm_hour == 0 && myTimeInfo.tm_min == 0 && myTimeInfo.tm_sec <= 0) {
Date_SS = " - ";
Date_SS += myTimeInfo.tm_year + 1900;
Date_SS += " - ";
Date_SS += myTimeInfo.tm_mon + 1;
Date_SS += " - ";
Date_SS += myTimeInfo.tm_mday;
}
void StoreTimeStampIntoSS(SafeString & p_RefToSS, tm p_myTimeInfo) {
time(&now); // read the current time
localtime_r(&now, &myTimeInfo); // update the structure tm with the current time
//p_RefToSS = " ";
p_RefToSS = myTimeInfo.tm_year + 1900;
p_RefToSS += ".";
// month
if (myTimeInfo.tm_mon + 1 < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_mon + 1;
p_RefToSS += ".";
// day
if (myTimeInfo.tm_mday + 1 < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_mday;
p_RefToSS += "; ";
// hour
if (myTimeInfo.tm_hour < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_hour;
p_RefToSS += ": ";
// minute
if (myTimeInfo.tm_min < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_min;
p_RefToSS += ": ";
// second
if (myTimeInfo.tm_sec < 10) {
p_RefToSS += "0";
}
p_RefToSS += myTimeInfo.tm_sec;
//p_RefToSS += ", ";
}
void synchroniseWith_NTP_Time() {
Serial.print("configTime uses ntpServer ");
Serial.println(ntpServer);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.print("synchronising time");
int myCnt = 0;
while (myTimeInfo.tm_year + 1900 < 2000 ) {
time(&now); // read the current time
localtime_r(&now, &myTimeInfo);
BlinkHeartBeatLED(OnBoard_LED, 100);
delay(100);
Serial.print(".");
myCnt++;
if (myCnt > 600) {
break;
}
}
if (myCnt > 600) {
Serial.println("not synchronised with NTP - server");
}
else {
Serial.print("\n time synchronsized \n");
}
}
void printWiFiStatus(uint8_t p_WiFiStatus) {
Serial.print("WiFi - Status: ");
switch (p_WiFiStatus) {
case WL_IDLE_STATUS: // 0
Serial.println("WL_IDLE_STATUS temporary status assigned when WiFi.begin() is called");
break;
case WL_NO_SSID_AVAIL: // 1
Serial.println("WL_NO_SSID_AVAIL when no SSID are available");
break;
case WL_SCAN_COMPLETED: // 2
Serial.println("WL_SCAN_COMPLETED scan networks is completed");
break;
case WL_CONNECTED: // 3
Serial.println("WL_CONNECTED");
break;
case WL_CONNECT_FAILED: // 4
Serial.println("WL_CONNECT_FAILED");
break;
case WL_CONNECTION_LOST: // 5
Serial.println("WL_CONNECTION_LOST");
break;
case WL_DISCONNECTED: // 6
Serial.println("WL_DISCONNECTED");
break;
}
}
