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 but something I obviously need to learn.
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
Here's the code
// 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 = "mySSID"; // Wifi SSID
const char* password = "MyPassword"; //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