Hi Arduino community, I'm building a project to read my pool temperature from inside.
The temperature Server is an M5Stamp reading a DS18B20 sensor that will be mounted into my Hayward sat cell control box for convenience.
I can connect to the ESP32 Server softAP with my Android phone, connect/disconnect and sent more that 10 commands a second with connect/disconnect in between, it's solid as a rock.
Issues begins when I try to connect the Client, the other ESP32 module.
I connects fine after a reset and can fetch de temperature JSON string fine but cannot reconnect at the second loop. client.connect(server, port, 2000) always return false from second connection.
Here is the part of the code related to Client loop().
This is unfinished test code as I need to test the system for stability and reliability before continue development.
I hope to have help to understand what's going on...
Thanks for your help.
#include <Arduino.h>
#include <stdio.h>
#include <strings.h>
#include <rtc_wdt.h>
#include <esp_system.h>
#include <M5StickCPlus.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
#define RTC_WDT_TIMEOUT 5000 //Watchdog timer delay in milliseconds
/* Global variable declaration */
//Set your softAP access point network credentials and IP
const char* ssid = "PoolTempServer"; //SSID constant with constant char pointer. WiFi.begin only accept const char*
const char* password = "0123456789"; //Password constant with constant char pointer. WiFi.begin only accept const char*
const unsigned int port = 80; //Port constant, server listening port
IPAddress server(192, 168, 1, 1); //PoolTempServer IP address
WiFiClient client;
float tempCelcius = 0;
float tempFahrenheit = 0;
const char answerOK[17] = "{\"answer\":\"ok\"}"; //Output a crafted compatible JSON string, answer OK string with NULL end (16+1)
const byte allowedMaxCommChars = 100; //Maximum number of chars allowed on the interface from an answer
bool reachedMaxWifiChars = false; //Set to true if we reached the maximum number of chars allowed from an answer
bool wifiStringComplete = false; //Whether the comamnd string is complete and available to be parsed
bool wifiTimeoutOccured = false; //Set to true if the wifiCommEvent function timed out by waiting data for too long
bool wifiTimeoutStarted = false; //Set to true if the wifiCommEvent function detected the start marker and started the verification of wifiCommEvent timeout
const word wifiTimeoutValue = 2000; //Set the wifiCommEvent timeout value in ms to stop waiting incomming data for too long after the start marker
unsigned long wifiTimerStart = 0; //Store the millis() timer first snapshot for commEvent timeout
unsigned long currentTime = 0; //Current milli() snapshot time, used in general timeout calculation
unsigned long previousTime = 0; //Previous milli() snapshot time, used in general timeout calculation
char wifiString[allowedMaxCommChars]; //wifiString array to store the received wifi data, destructed after been used
char answerString[allowedMaxCommChars]; //answerString is the received "serial" or "wifi" answer string
char answerToJSON[allowedMaxCommChars]; //answerToJSON is a copy of the answerString char array to be used by the answer functions and JSON error detection
/* Initialization function
* Code is excuted once at reset and power ON
*/
void setup()
{
/*rtc_wdt_protect_off(); //Disable RTC WDT write protection
//Set stage 0 to trigger a system reset after RTC_WDT_TIMEOUT delay
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
rtc_wdt_set_time(RTC_WDT_STAGE0, RTC_WDT_TIMEOUT);
rtc_wdt_enable(); //Start the RTC WDT timer
rtc_wdt_protect_on(); //Enable RTC WDT write protection*/
esp_sleep_enable_ext0_wakeup(GPIO_NUM_37, LOW); //Set button A (top M5 button - GPIO37) to be used to get M5Stick out of deep sleep when pressed
Serial.begin(115200); //Initialize serial communication at 115200 bits per second, 8 bits, no parity, 1 stop bit (SERIAL_8N1)
WiFi.mode(WIFI_STA); //Set WiFi mode to Station Mode
delay(1000); //Waiting a little for AP to start
WiFi.begin(ssid, password, 1, NULL, false); //Channel #1, no BSSID, no automatic connect (done in loop)
M5.begin();
M5.Lcd.setRotation(3); //Init LCD rotation horizontally, LCD at right of M5 button
//M5.Beep.tone(3300);
//delay(100);
//M5.Beep.mute();
}
/* Main loop function, code is executed repeatedly
*/
void loop()
{
if (WiFi.status() != WL_CONNECTED)
{
M5.Lcd.fillScreen(0x0000); //Fill LCD screen with black color
M5.Lcd.setCursor(0, 0, 2); //X-Y, font #2
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK); //White text on black background
M5.Lcd.setTextSize(1);
M5.Lcd.println("Connecting to PoolTempServer...");
Serial.println("Connecting to PoolTempServer..."); //DEBUG
M5.Lcd.print("SSID: ");
Serial.print("SSID: "); //DEBUG
M5.Lcd.println(ssid);
Serial.println(ssid); //DEBUG
while (WiFi.status() != WL_CONNECTED)
{
for (byte i = 0; i < 9; i++) //We wait for a server connection for 10 seconds max
{
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
WiFi.reconnect();
delay(1000);
M5.Lcd.print(".");
Serial.print("."); //DEBUG
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
if (WiFi.status() == WL_CONNECTED)
{
M5.Lcd.println("");
M5.Lcd.println("WiFi connected!");
M5.Lcd.print("IP address: ");
M5.Lcd.println(WiFi.localIP());
M5.Lcd.println("");
Serial.println(""); //DEBUG
Serial.println("WiFi connected!"); //DEBUG
Serial.print("IP address: "); //DEBUG
Serial.println(WiFi.localIP()); //DEBUG
Serial.println(""); //DEBUG
break;
}
}
if (WiFi.status() != WL_CONNECTED)
{
M5.Beep.tone(3300);
delay(100);
M5.Beep.mute();
M5.Lcd.println("");
M5.Lcd.println("Cannot connect to PoolTempServer");
Serial.println(""); //DEBUG
Serial.println("Cannot connect to PoolTempServer"); //DEBUG
delay(3000);
break;
}
}
}
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
if (WiFi.status() == WL_CONNECTED)
{
if (client.connect(server, port, 2000))
{
delay(500);
client.println("{\"get\":\"temp\"}");
Serial.println("get:temp command sent to server"); //DEBUG
delay(1000);
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
}
else
{
M5.Beep.tone(3300);
delay(100);
M5.Beep.mute();
M5.Lcd.println("Cannot connect on port 80");
Serial.println("Cannot connect on port 80"); //DEBUG
delay(3000); //We wait to display message if connection failed, 3 secs max to be below watchdog timeout
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
M5.Lcd.fillScreen(0x0000); //Fill LCD screen with black color
//ESP.restart();
}
}
server = client.available(); //If server sent data to client, we have something to read
if (server)
{
//Serial.println("WiFi server data available!");
while (client.connected())
{
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
if (wifiTimeoutStarted) // Verify if wifiCommEvent function started the timeout verification process
{
if (((unsigned long)millis() - wifiTimerStart) >= wifiTimeoutValue) //Differential timer to validate if wifiCommEvent command receiving delay is exeeding the determined value and branch if true
{
M5.Beep.tone(3300);
delay(100);
M5.Beep.mute();
wifiTimeoutOccured = true; //Set to true if we exceeded the determined wifi timeout value, wifiCommEvent() will take care of this
wifiCommEvent(); //We branch here as a wifi timeout has been detected and we need to reset the function logics
M5.Lcd.println("WiFi answer timeout!");
break;
}
}
if (client.available() > 0) //We verify if chars are available in the wifi interface buffer
{
wifiCommEvent(); //We branch here if data is available to be fetched from the wifi interface
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
}
if ((wifiStringComplete) && (reachedMaxWifiChars == false)) //Branch if wifi transmission has ended and MaxCommChars has not been exceeded
{
memcpy(answerString, wifiString, sizeof(wifiString)); //Keep a workable copy of the string when a closing JSON curly bracket has been detected
memset(wifiString, 0, sizeof(wifiString)); //Clear the wifi string to be reused
wifiStringComplete = false; //Reset the flag to be reused
answerParser(); //Parsing the received commandString string and execute the right command
memset(answerString, 0, sizeof(answerString)); //Clear the commandString string to be reused
memset(answerToJSON, 0, sizeof(answerToJSON)); //Clear the commandToJSON string to be reused
break;
}
if ((wifiStringComplete) && (reachedMaxWifiChars == true)) //Branch if wifi transmission has ended and MaxCommChars has been reached or exceeded, we are in error
{
M5.Beep.tone(3300);
delay(100);
M5.Beep.mute();
memset(wifiString, 0, sizeof(wifiString)); //Clear the wifi string to be reused
wifiStringComplete = false; //Reset the flag to be reused
reachedMaxWifiChars = false; //Reset the flag to be reused, we branched here so we know we are in error
M5.Lcd.println("WiFi answer overflow!");
break;
}
}
//while (client.read() != -1) { delay(10); } //We need be sure the buffer is empty to close the connection properly and avoid leaving an open socket on the server
client.flush();
client.stop();
//WiFi.disconnect();
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
delay(2500);
rtc_wdt_feed(); //When called, resets the RTC Watchdog timer
delay(2500);
M5.Lcd.fillScreen(0x0000); //Fill LCD screen with black color
//M5.Axp.DeepSleep();
//ESP.restart();
}
}