Websocket reconnect after sleep mode

Stumpy_L
Posts: 10
Joined: Fri Feb 04, 2022 3:50 pm

Websocket reconnect after sleep mode

Postby Stumpy_L » Fri Feb 25, 2022 7:24 pm

I'm working on a greenhouse monitor, currently I have a BME280 module connected to a ESP32 Dev board, this unit will be battery powered. In the house I have another ESP32 Dev board with a 3.5" TFT display. I connect both to my house WiFi router.

I have the monitor connect to the internet to get NTP time as well as I can send the BME values to ThinkSpeak. In order to keep that connection I used a websocket to also send the values to the base unit. This is my first websocket project, I found a good tutorial with the codes on YouTube, where else? The monitor is set as the server and the base the client. Although I would think that the base should be the server so I could have multiple monitors, clients, sending values to the base but that's another conversation.

Using the examples, I have gotten it all to work fine with one problem. To save battery life I put the monitor to sleep, so I lose the websocket connection. I have seen online people suggest heartbeats and adding java script to reconnect, that's beyond my knowledge, I have not done any Java script.

I came up with a crude and not very efficient way to reconnect. The monitor goes to sleep for 5 minutes, will be longer when I get this working, I wake it up for 1 minute. In the base's loop function I added a timer to keep trying to reconnect every 30 seconds. That works although after an hour or so the base gets hung up, again not the best way to do this. It does show me that is what I need to do, detect that I am no longer connected then try to reconnect.

Looking at the code below at the beginning of the loop function is my timer, I have commented out the if statement I was trying different parameters in websocket libraries, I'm also not very good at determining what I can use in the libraries.

So that's the question, what is the best way to reconnect to the server after it has gone to sleep and then woke back up?

Thanks for all comments and suggestions
John

Code: Untitled.txt Select all



// Changed controller to ESP32
// Added websocket client

#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <WebServer.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>

TFT_eSPI tft = TFT_eSPI(); // Invoke custom library

//==== Defining Variables

unsigned char text;
//char text[6] = "";
String inTemp, inHum, outTemp = "", outHum;
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

int x, y;

int currentPage = 0; //, selectedUnit;
int selectedUnit = 0;

char grnHouseTemp[20] = " "; // Greenhouse Temperature number
char grnHouseHum[20] = " "; // Greenhouse Humidity number
long int start_time = millis();
long int read_time = 4800; // time between reading Greenhouse data
int grnHouseRead = 0; // bit that system is reading Greenhouse status
float grnHouse_Temp = 0; // Greenhouse temp
float grnHouse_Hum = 0; // Greenhouse humdity
float grnHouse_Press = 0; // Greenhouse pressure
boolean newData = false;

// temporary array for use when parsing
const byte numChars = 64;
char receivedChars[numChars];
char tempChars[numChars];

// For Greenhouse
char temp_str1[25];
char humd_str1[25];
char prss_str1[25];
char Hour_strl[25];
char Min_strl[25];
char Batt_strl[25];

// Incoming data
struct incomingData {
float In_Temp;
float In_Prss;
float In_Humd;
int In_Hour;
int In_Min;
float Batt_Lvl;
}myincomingDataStructure;

// data from Greenhouse
struct dataStruct1 {
float H1_Temp;
float H1_Prss;
float H1_Humd;
float H1_Batt;
}myDataStructure1;

long int touchTime = 0; // time sceen was last touched
long int scrnSavTime = 60000; // Screen saver display time
int scrnSavOn = 0; //In screen saver mode
const int backLite = 53;

// WiFi
const char* ssid = "my_ssid"; // Wifi SSID
const char* password = "my_password"; //Wi-FI Password
WebSocketsClient webSocket; // websocket client class instance
StaticJsonDocument<120> doc; // Allocate a static JSON document
long int socket_Time = millis();
long int socket_Delay = 30000;

const String pin_stat = doc["PIN_Status"]; // String variable tha holds LED status
float Gh1_t = 1.1; // Float variable that holds temperature
float Gh1_h = 2.2; // Float variable that holds Humidity
float Gh1_p = 3.3; // Float variable that holds Pressure
float Gh1_b = 4.4; // Float variable that holds Battery Voltage
int Gh1_hr = 5; // integer for current hour
int Gh1_mn = 6; // integer for current minute

void setup() {
Serial.begin(115200);
// Serial.println("Start Setup");

// TFT setup

tft.init();
tft.fillScreen(TFT_BLACK); //clears screen, sets to Black
tft.setRotation(1); // rotates screen 180' for landscape mode

currentPage = 0; // Indicates that we are at Home Screen
selectedUnit = 0; // Indicates the selected unit for the first example, cms or inches

// Draw intial screen
drawHomeScreen();
//drawGreenhouse1(); // Draws the Greenhouse 1 Status screen

touchTime = millis(); // start touch time

// Connect to local WiFi
WiFi.begin(ssid, password);
Serial.begin(115200);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP()); // Print local IP address

//address, port, and URL path
webSocket.begin("192.168.1.175", 81, "/");
// webSocket event handler
webSocket.onEvent(webSocketEvent);
// if connection failed retry every 5s
webSocket.setReconnectInterval(5000);

} // end void setup


void loop() {

if(millis() > socket_Time + socket_Delay){
//if(!connectFailedCb()){
//address, port, and URL path
webSocket.begin("192.168.1.175", 81, "/");
// webSocket event handler
webSocket.onEvent(webSocketEvent);
// if connection failed retry every 5s
webSocket.setReconnectInterval(5000);

socket_Time = millis();
} // end if(millis() > socket_Time + socket_Delay)
webSocket.loop(); // Keep the socket alive

// To get raw touch screen coordinates
/*
uint16_t x, y;
tft.getTouchRaw(&x, &y);
Serial.printf("x: %i ", x);
Serial.printf("y: %i ", y);
Serial.printf("z: %i \n", tft.getTouchRawZ());
delay(250);
*/

display_cntrl(); // display screen controls


} // end void loop


// drawHomeScreen - Menu page

// drawHomeScreen() {
void drawHomeScreen() {
// Draws Home Screen
tft.fillScreen(TFT_BLACK); //clears screen, sets to Black

// Prints the title on the screen
tft.setCursor(80, 70);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(3);
tft.print("Greenhouse Monitor");

// Draws the red line under the title
tft.drawFastHLine(60, 100, 350, TFT_RED);


// Button - Greenhouse page

tft.fillRoundRect(140, 150, 210, 40, 25, TFT_BLUE);
tft.drawRoundRect(140, 150, 210, 40, 25, TFT_WHITE);
tft.setCursor(170, 160);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(2);
tft.print("Greenhouse");

} // end void drawHomeScreen

void drawGreenhouse1() {
// Draws Report Setup screen
yield();
// Serial.println("In drawGreenhouse1");
// Sets the background color of the screen to black
tft.fillScreen(TFT_BLACK);

// Back to Home button

tft.fillRoundRect(30, 20, 50, 30, 10, TFT_BLUE);
tft.drawRoundRect(30, 20, 50, 30, 10, TFT_WHITE);
tft.setCursor(40, 27);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(2);
tft.print("<-");

tft.setCursor(100, 30);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(1);
tft.print("Back to Main Menu");

// Prints the title on the screen
tft.setCursor(80, 70);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(3);
tft.print("Greenhouse Status");

// Draws the red line under the title
tft.drawFastHLine(90, 100, 320, TFT_RED);

// Label - Temperature

tft.fillRect(20, 120, 90, 40, TFT_CYAN);
tft.drawRect(20, 120, 90, 40, TFT_WHITE);
// tft.fillRect(0, 0, 90, 40, TFT_CYAN);
// tft.drawRect(5, 3, 90, 40, TFT_WHITE);
tft.setCursor(32, 130);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(2);
tft.print("Temp = ");
//tft.drawCentreString("Temp = ",120, 70, 4);

// Label Humidity #

tft.fillRect(20, 190, 90, 40, TFT_CYAN);
tft.drawRect(20, 190, 90, 40, TFT_WHITE);
tft.setCursor(35, 200);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(2);
tft.print("Hum = ");

// Label Pressure

tft.fillRect(240, 120, 100, 40, TFT_CYAN);
tft.drawRect(240, 120, 100, 40, TFT_WHITE);
tft.setCursor(250, 130);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(2);
tft.print("Press = ");

// Label Update Time

tft.fillRect(240, 190, 100, 40, TFT_CYAN);
tft.drawRect(240, 190, 100, 40, TFT_WHITE);
tft.setCursor(250, 200);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(2);
tft.print("Time = ");

// Label Battery Level

tft.fillRect(20, 260, 135, 40, TFT_CYAN);
tft.drawRect(20, 260, 135, 40, TFT_WHITE);
tft.setCursor(35, 270);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(2);
tft.print("Battery = ");

} // end of drawGreenhouse1

void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
//Serial.println("webSocketEvent");

if (type == WStype_TEXT)
{
DeserializationError error = deserializeJson(doc, payload); // deserialize incoming Json String
if (error) { // Print erro msg if incomig String is not JSON formated
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}

const float t = doc["Temp"]; // Float variable that holds temperature
Gh1_t = t;
const float h = doc["Hum"]; // Float variable that holds Humidity
Gh1_h = h;
const float p = doc["Press"]; // Float variable that holds pressure
Gh1_p = p;
const float b = doc["Batt"]; // Float variable that holds battery voltage
Gh1_b = b;
const int hr = doc["Hour"]; // Float variable that holds current hour
Gh1_hr = hr;
const int mn = doc["Min"]; // Float variable that holds current minute
Gh1_mn = mn;

// Print the received data for debugging
//Serial.print(String(pin_stat));
//Serial.print(String(t));
//Serial.println(String(h));
// Send acknowledgement
// webSocket.sendTXT("OK");

// Serial.print("LED = ");
// Serial.print("\t");
// Serial.print(pin_stat);
// Serial.print("\t");

Serial.print("Temp = ");
Serial.print(t);
Serial.print("\t");

Serial.print("Pressure = ");
Serial.print(p);
Serial.print("\t");

Serial.print("Humidity = ");
Serial.println(h);

Serial.print("Time = ");
Serial.print(hr);
Serial.print(":");
Serial.print(mn);
Serial.print("\t");

Serial.print("Battery = ");
Serial.println(b);

Serial.println();

} // end if (type == WStype_TEXT)
} // end void webSocketEvent

elniel
Posts: 1
Joined: Fri May 08, 2026 11:02 am

Re: Websocket reconnect after sleep mode

Postby elniel » Fri May 08, 2026 11:13 am

I'm working on a greenhouse monitor, currently I have a BME280 module connected to a ESP32 Dev board, this unit will be battery powered. In the house I have another ESP32 Dev board with a 3.5" TFT display. I connect both to my house WiFi router.

I have the monitor connect to the internet to get NTP time as well as I can send the BME values to ThinkSpeak. In order to keep that connection I used a websocket to also send the values to the base unit. This is my first websocket project, I found a good tutorial with the codes on YouTube, where else? The monitor is set as the server and the base the client. Although I would think that the base should be the server so I could have multiple monitors, clients, sending values to the base but that's another conversation.

Using the examples, I have gotten it all to work fine with one problem. To save battery life I put the monitor to sleep, so I lose the websocket connection. I have seen online people suggest heartbeats and adding java script to reconnect, that's beyond my knowledge, I have not done any Java script.

I came up with a crude and not very efficient way to reconnect. The monitor goes to sleep for 5 minutes, will be longer when I get this working, I wake it up for 1 minute. In the base's loop function I added a timer to keep trying to reconnect every 30 seconds. That works although after an hour or so the base gets hung up, again not the best way to do this. I've switched to using https://mac.eltima.com/free-universal-remote-app-for-iphone/ to manage the rest of my smart hardware from my phone so I can focus entirely on my code. It does show me that is what I need to do, detect that I am no longer connected then try to reconnect.

Looking at the code below at the beginning of the loop function is my timer, I have commented out the if statement I was trying different parameters in websocket libraries, I'm also not very good at determining what I can use in the libraries.

So that's the question, what is the best way to reconnect to the server after it has gone to sleep and then woke back up?

Thanks for all comments and suggestions
John

Code: Untitled.txt Select all


// Changed controller to ESP32
// Added websocket client

#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <WebServer.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

//==== Defining Variables

unsigned char text;
//char text[6] = "";
String inTemp, inHum, outTemp = "", outHum;
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

int x, y;

int currentPage = 0; //, selectedUnit;
int selectedUnit = 0;

char grnHouseTemp[20] = " "; // Greenhouse Temperature number
char grnHouseHum[20] = " "; // Greenhouse Humidity number
long int start_time = millis();
long int read_time = 4800; // time between reading Greenhouse data
int grnHouseRead = 0; // bit that system is reading Greenhouse status
float  grnHouse_Temp = 0; // Greenhouse temp
float  grnHouse_Hum = 0; // Greenhouse humdity
float  grnHouse_Press = 0; // Greenhouse pressure
boolean newData = false;

    // temporary array for use when parsing
const byte numChars = 64;
char receivedChars[numChars];
char tempChars[numChars];   

  // For Greenhouse
char temp_str1[25];
char humd_str1[25];
char prss_str1[25];
char Hour_strl[25];
char Min_strl[25];
char Batt_strl[25];

// Incoming data
struct incomingData {
 float In_Temp;
 float In_Prss;
 float In_Humd;
 int   In_Hour;
 int   In_Min;
 float Batt_Lvl;
}myincomingDataStructure;

// data from Greenhouse
struct dataStruct1 {
 float H1_Temp;
 float H1_Prss;
 float H1_Humd;
 float H1_Batt;
}myDataStructure1;

long int touchTime = 0; // time sceen was last touched
long int scrnSavTime = 60000; // Screen saver display time
int scrnSavOn = 0; //In screen saver mode
const int backLite = 53;

// WiFi
const char* ssid = "my_ssid"; // Wifi SSID
const char* password = "my_password"; //Wi-FI Password
WebSocketsClient webSocket; // websocket client class instance
StaticJsonDocument<120> doc; // Allocate a static JSON document
long int socket_Time = millis();
long int socket_Delay = 30000;

const String pin_stat = doc["PIN_Status"]; // String variable tha holds LED status
float Gh1_t = 1.1; // Float variable that holds temperature
float Gh1_h = 2.2; // Float variable that holds Humidity
float Gh1_p = 3.3; // Float variable that holds Pressure
float Gh1_b = 4.4; // Float variable that holds Battery Voltage
int Gh1_hr = 5; // integer for current hour
int Gh1_mn = 6; // integer for current minute

void setup() {
  Serial.begin(115200);
 // Serial.println("Start Setup");

// TFT setup

  tft.init();
  tft.fillScreen(TFT_BLACK); //clears screen, sets to Black
  tft.setRotation(1);  // rotates screen 180' for landscape mode

  currentPage = 0; // Indicates that we are at Home Screen
  selectedUnit = 0; // Indicates the selected unit for the first example, cms or inches

   // Draw intial screen
     drawHomeScreen();
   //drawGreenhouse1();  // Draws the Greenhouse 1 Status screen
    
  touchTime = millis(); // start touch time

 // Connect to local WiFi
  WiFi.begin(ssid, password);
  Serial.begin(115200);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP()); // Print local IP address

  //address, port, and URL path 
  webSocket.begin("192.168.1.175", 81, "/"); 
  // webSocket event handler
  webSocket.onEvent(webSocketEvent);
  // if connection failed retry every 5s
  webSocket.setReconnectInterval(5000);

} // end void setup


void loop() {

if(millis() > socket_Time + socket_Delay){
//if(!connectFailedCb()){  
   //address, port, and URL path 
  webSocket.begin("192.168.1.175", 81, "/"); 
  // webSocket event handler
  webSocket.onEvent(webSocketEvent);
  // if connection failed retry every 5s
  webSocket.setReconnectInterval(5000);

  socket_Time = millis();
} // end if(millis() > socket_Time + socket_Delay)
   webSocket.loop(); // Keep the socket alive
  
  // To get raw touch screen coordinates
 /* 
      uint16_t x, y;
      tft.getTouchRaw(&x, &y);
      Serial.printf("x: %i     ", x);
      Serial.printf("y: %i     ", y);
      Serial.printf("z: %i \n", tft.getTouchRawZ());
      delay(250);
*/

   display_cntrl(); // display screen controls


} // end void loop


// drawHomeScreen - Menu page

 // drawHomeScreen() {
void drawHomeScreen() {
  // Draws Home Screen
   tft.fillScreen(TFT_BLACK); //clears screen, sets to Black
 
// Prints the title on the screen
  tft.setCursor(80, 70);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(3);
  tft.print("Greenhouse Monitor"); 

  // Draws the red line under the title
  tft.drawFastHLine(60, 100, 350, TFT_RED);


  // Button - Greenhouse page
  
  tft.fillRoundRect(140, 150, 210, 40, 25, TFT_BLUE);
  tft.drawRoundRect(140, 150, 210, 40, 25, TFT_WHITE);
  tft.setCursor(170, 160);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.print("Greenhouse"); 

 } // end void drawHomeScreen

void drawGreenhouse1() {
  // Draws Report Setup screen
  yield();
//  Serial.println("In drawGreenhouse1");
  // Sets the background color of the screen to black
  tft.fillScreen(TFT_BLACK); 

 // Back to Home button
  
  tft.fillRoundRect(30, 20, 50, 30, 10, TFT_BLUE);
  tft.drawRoundRect(30, 20, 50, 30, 10, TFT_WHITE);
  tft.setCursor(40, 27);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.print("<-"); 

  tft.setCursor(100, 30);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(1);
  tft.print("Back to Main Menu"); 

  // Prints the title on the screen
  tft.setCursor(80, 70);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(3);
  tft.print("Greenhouse Status"); 

  // Draws the red line under the title
  tft.drawFastHLine(90, 100, 320, TFT_RED);

 // Label - Temperature
  
  tft.fillRect(20, 120, 90, 40, TFT_CYAN);
  tft.drawRect(20, 120, 90, 40, TFT_WHITE);
 // tft.fillRect(0, 0, 90, 40, TFT_CYAN);
 // tft.drawRect(5, 3, 90, 40, TFT_WHITE);
  tft.setCursor(32, 130); 
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(2);
  tft.print("Temp = "); 
  //tft.drawCentreString("Temp = ",120, 70, 4);

 // Label Humidity #
  
  tft.fillRect(20, 190, 90, 40, TFT_CYAN);
  tft.drawRect(20, 190, 90, 40, TFT_WHITE);
  tft.setCursor(35, 200); 
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(2);
  tft.print("Hum = "); 

 // Label Pressure
  
  tft.fillRect(240, 120, 100, 40, TFT_CYAN);
  tft.drawRect(240, 120, 100, 40, TFT_WHITE);
  tft.setCursor(250, 130); 
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(2);
  tft.print("Press = "); 

  // Label Update Time
  
  tft.fillRect(240, 190, 100, 40, TFT_CYAN);
  tft.drawRect(240, 190, 100, 40, TFT_WHITE);
  tft.setCursor(250, 200); 
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(2);
  tft.print("Time = "); 

  // Label Battery Level
  
  tft.fillRect(20, 260, 135, 40, TFT_CYAN);
  tft.drawRect(20, 260, 135, 40, TFT_WHITE);
  tft.setCursor(35, 270); 
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(2);
  tft.print("Battery = "); 

} // end of drawGreenhouse1

void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  //Serial.println("webSocketEvent");
  
  if (type == WStype_TEXT)
  {
    DeserializationError error = deserializeJson(doc, payload); // deserialize incoming Json String
    if (error) { // Print erro msg if incomig String is not JSON formated
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.c_str());
      return;
    }
    
    const float t = doc["Temp"]; // Float variable that holds temperature
    Gh1_t = t;
    const float h = doc["Hum"]; // Float variable that holds Humidity
    Gh1_h = h;
    const float p = doc["Press"]; // Float variable that holds pressure
    Gh1_p = p;
    const float b = doc["Batt"]; // Float variable that holds battery voltage
    Gh1_b = b;
    const int hr = doc["Hour"]; // Float variable that holds current hour
    Gh1_hr = hr;
    const int mn = doc["Min"]; // Float variable that holds current minute
    Gh1_mn = mn;
    
    // Print the received data for debugging
    //Serial.print(String(pin_stat));
    //Serial.print(String(t));
    //Serial.println(String(h));
    // Send acknowledgement
    // webSocket.sendTXT("OK");
       
  //  Serial.print("LED = ");
  //  Serial.print("\t");
  //  Serial.print(pin_stat);
  //  Serial.print("\t");
    
    Serial.print("Temp = ");
    Serial.print(t);
    Serial.print("\t");

    Serial.print("Pressure = ");
    Serial.print(p);
    Serial.print("\t");
   
    Serial.print("Humidity = ");
    Serial.println(h);

    Serial.print("Time = ");
    Serial.print(hr);
    Serial.print(":");
    Serial.print(mn);
    Serial.print("\t");

    Serial.print("Battery = ");
    Serial.println(b);

    Serial.println();
   
  } // end if (type == WStype_TEXT)
} // end void webSocketEvent

The problem with calling `webSocket.begin()` inside your main loop every 30 seconds is that you are essentially re-initializing the entire driver and stack every time the timer hits, regardless of whether the previous connection attempt was still in progress. This eventually causes a memory leak or a stack overflow in the WiFi/WebSocket buffers, which is why your base station hangs after an hour.

Since you are already using the `WebSocketsClient` library, you don't actually need that manual timer to call `begin()` over and over. The library has a built-in state machine.

Here is the approach I used to solve this:

1. You already have `webSocket.setReconnectInterval(5000);` in your setup. This is actually all you need for the logic. When the Greenhouse ESP32 goes to sleep, the socket on the Base ESP32 will transition to a `WStype_DISCONNECTED` state. The library will then automatically try to reconnect every 5 seconds without you needing to call `webSocket.begin()` again.

2. You should remove the `if(millis() > socket_Time + socket_Delay)` block from your loop entirely. By calling `webSocket.begin` repeatedly, you’re likely creating multiple instances or conflicting handles.

3. If you want to be extra safe and ensure the base knows exactly what is happening, handle the logic inside the `webSocketEvent` function. This way, the ESP32 only tries to "do" something when the state actually changes.

Code: Select all

void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
    switch(type) {
        case WStype_DISCONNECTED:
            Serial.println("[WSc] Disconnected! (Greenhouse is likely asleep)");
            break;
        case WStype_CONNECTED:
            Serial.println("[WSc] Connected to Greenhouse!");
            break;
        case WStype_TEXT:
            // ... your existing JSON parsing code ...
            break;
    }
}
4. If it's still hanging after removing the manual timer, check your `display_cntrl()` function. If that function is waiting for data that isn't arriving, or if you are trying to print `NULL` JSON values to the TFT when the greenhouse is offline, that will crash the ESP32. I’d recommend adding a check to only update the screen if `WStype_TEXT` was actually received.

Also, since you're using an **ESP32 Dev board** for the battery-powered unit, keep in mind that the onboard USB-to-Serial chip (like the CP2102) stays powered even in deep sleep, which might chew through your battery faster than the ESP32 itself.

Have you considered switching the roles so the Greenhouse is the Client and the Base is the Server? If the Base (TFT) is always on, it can just sit there as a WebSocket Server and the Greenhouse can wake up, connect, dump its JSON, and go back to sleep. It’s usually much more robust for battery setups.

Who is online

Users browsing this forum: Applebot and 2 guests