Websocket reconnect after sleep mode
Posted: 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
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
- // 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