Hopefully the last question I'll have on my Greenhouse monitor that I've had some help with lately. The monitor has a BME280 connected to a ESP32 Dev board, using an access point WiFi connection I send the values to a base station in the house. The base is also a ESP32 Dev board with a TFT display. The monitor is set as the server and the base the client. I know that this is backwards but it works and later I'll swap them around. I put the monitor to sleep every 2 minutes, that will be increased once I get this working. The base sends httpGETRequest() to read the values from the monitor. I test to make sure the WiFi is connected before sending the httpGETRequest(). The problem is when the monitor goes to sleep the base still thinks the WiFi is connected but the httpGETRequest() returns blanks. It only does it once, the next time it recognises that the WiFi is not connected. I don't think it's a timing thing that the base just happens to request just as the monitor is going to sleep, it's very consistent, happens every time. I've tried a few things but nothing obviously none of those worked.
here is the code for the monitor
// ESP32 with BME/BMP280
// Added Wifi to Thingspeak
// Added Nrfl24l01
// _2 added RTC
// _3 added NTP time
// _4 removed RTC
// Loaded into Weather Station 3.0
// Added Websocket Server
// removed Websockets changed to HTTP communications
#include <Wire.h>
#include <SPI.h>
#include <WiFi.h>
#include <ThingSpeak.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24Network.h>
#include <time.h>
#include <Mapf.h>
#include "ESPAsyncWebServer.h"
Adafruit_BME280 bme; // I2C
#define SEALEVELPRESSURE_HPA (1013.25)
float Temp = 0;
float Prss = 0;
float Humd = 0;
float c_Temp = 0;
struct dataStruct {
float H1_Temp;
float H1_Prss;
float H1_Humd;
int16_t H1_Hour;
int16_t H1_Min;
float Batt_Lvl;
}myDataStructure;
// long int start_delay = 0; // start of delay time
// int baseUpdate = 0; // base data has been updated
// long int write_time = 20000; // time between writes to base
long int lastTime = 0;
long int updateTime = 10000;
long int sleepDelay = 60000;
bool Reset = false;
#define BME280Pwr 25 // BME280 Power signal to GPIO25
//#define NRF24Pwr 33 // NRF24L01 power signal to GPIO33
// Set your access point network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String readTemp() {
return String((bme.readTemperature() * 9/5) + 32); // calculate F'
//return String(1.8 * bme.readTemperature() + 32);
}
String readHumi() {
return String(bme.readHumidity());
}
String readPres() {
return String(bme.readPressure() / 3389.39); // 100.0F
}
String readBatt() {
return String(myDataStructure.Batt_Lvl);
}
String readHour() {
return String(myDataStructure.H1_Hour);
}
String readMin() {
return String(myDataStructure.H1_Min);
}
// Wifi for ThinkSpeak and NTP
#define WIFI_NETWORK "my_ssid" // your network SSID (name)
#define WIFI_PASSWORD "my_password" // your network password (use for WPA, or use as key for WEP)
#define WIFI_TIMEOUT_MS 20000
WiFiClient client;
// ThingSpeak
unsigned long myChannelNumber = 1562213;
const char * myWriteAPIKey = "OTIKE0VFZJ122V2H";
// for NTP time
const char* NTP_SERVER = "ch.pool.ntp.org";
const char* TZ_INFO = "EST5EDT,M3.2.0,M11.1.0"; //
tm timeinfo;
time_t now;
long unsigned lastNTPtime;
unsigned long lastEntryTime;
// for deep sleep using ESP32's RTC
#include <Arduino.h>
#define LED_PIN 2
#define BTN_PIN 26 // Wakeup button
// Define a few time periods
// #define SECONDS_TO_HANG_ABOUT 10
#define SECONDS_TO_SLEEP 120 // duration of sleep
#define uS_TO_S_FACTOR 1000000
// Place all variables you want to retain across sleep periods in the
// RTC SRAM. 8kB SRAM on the RTC for all variables.
RTC_DATA_ATTR int bootCount = 0;
// for battery monitoring
#define Batt_In 33 //32
double value=333;// adc reading
uint8_t bit_resolution=10;// for example 10 bit adc
double output_min=0;// 0v
double output_max=5; //5v
//double Batt_Lvl;
float t; // holds the temperature value
float h;// holds the Humidity value
float p; // holds pressure value
float b; // holds battery value
int interval = 1000; // virtual delay
unsigned long previousMillis = 0; // Tracks the time since last event fired
void setup() {
Serial.begin(115200);
// Pin Modes
pinMode(Batt_In,INPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
// Why are we awake?
getWakeUpReason();
// Start BME280
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
//while (1);
//digitalWrite(LED_PIN, HIGH); // turn on LED
} // end if (!bmp.begin())
// Start Wifi
connectToWiFi();
ThingSpeak.begin(client);
// NTP time
Serial.println("\n\nNTP Time Test\n");
configTime(0, 0, NTP_SERVER);
// See https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv for Timezone codes for your region
setenv("TZ", TZ_INFO, 1);
if (getNTPtime(10)) { // wait up to 10sec to sync
} else {
Serial.println("Time not set");
//digitalWrite(LED_PIN, HIGH); // turn on LED
ESP.restart();
}
showTime(timeinfo);
lastNTPtime = time(&now);
lastEntryTime = millis();
lastTime = millis(); // for update of readings
// Setting the ESP as an access point
Serial.print("Setting AP (Access Point)…");
// Remove the password parameter, if you want the AP (Access Point) to be open
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readTemp().c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readHumi().c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readPres().c_str());
});
server.on("/battery", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readBatt().c_str());
});
server.on("/Gh1_Hour", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readHour().c_str());
});
server.on("/Gh1_Min", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readMin().c_str());
});
// Start server
server.begin();
} // end setup
void loop() {
// Read BME280
c_Temp = bme.readTemperature(); // read temp from BME280
myDataStructure.H1_Temp = (c_Temp * 9/5) + 32; // calculate F'
myDataStructure.H1_Prss = (bme.readPressure() / 3389.39);
myDataStructure.H1_Humd = bme.readHumidity();
// Update ThingSpeak data
ThingSpeak.setField(1,myDataStructure.H1_Temp);
ThingSpeak.setField(2,myDataStructure.H1_Humd);
ThingSpeak.setField(3,myDataStructure.H1_Prss);
ThingSpeak.setField(4,myDataStructure.Batt_Lvl);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
unsigned long currentMillis = millis(); // call millis and Get snapshot of time
if((millis() > (lastTime + updateTime)) && Reset == false){
Reset = true;
// Update NTP time
configTime(0, 0, NTP_SERVER);
setenv("TZ", TZ_INFO, 1);
if (getNTPtime(10)) { // wait up to 10sec to sync
} else {
Serial.println("Time not set");
ESP.restart();
}
showTime(timeinfo);
lastNTPtime = time(&now);
lastEntryTime = millis();
// Read Battery
myDataStructure.Batt_Lvl = mapf_ADC(analogRead(Batt_In),0,4.2,12); // example for 12 bit ADC 0 to 3.3 voltage
b = myDataStructure.Batt_Lvl;
readBatt();
// Read BME280
c_Temp = bme.readTemperature(); // read temp from BME280
myDataStructure.H1_Temp = (c_Temp * 9/5) + 32; // calculate F'
myDataStructure.H1_Prss = (bme.readPressure() / 3389.39);
myDataStructure.H1_Humd = bme.readHumidity();
// Update ThingSpeak data
ThingSpeak.setField(1,myDataStructure.H1_Temp);
ThingSpeak.setField(2,myDataStructure.H1_Humd);
ThingSpeak.setField(3,myDataStructure.H1_Prss);
ThingSpeak.setField(4,myDataStructure.Batt_Lvl);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
// Send to Serial Monitor
Serial.print("Temp = ");
Serial.print(myDataStructure.H1_Temp);
Serial.print("\t");
Serial.print("Pressure = ");
Serial.print(myDataStructure.H1_Prss);
Serial.print("\t");
Serial.print("Humdity = ");
Serial.println(myDataStructure.H1_Humd);
// Serial.print("\t");
Serial.print("Time = ");
Serial.print(myDataStructure.H1_Hour);
Serial.print(":");
Serial.print(myDataStructure.H1_Min);
Serial.print("\t");
Serial.print("Battery = ");
Serial.println(myDataStructure.Batt_Lvl);
Serial.println();
/*
// Update Webserver data
if ((unsigned long)(currentMillis - previousMillis) >= interval) { // How much time has passed, accounting for rollover with subtraction!
update_temp_hum(); // update temperature data.
update_webpage(); // Update Humidity Data
previousMillis = currentMillis; // Use the snapshot to set track time until next event
} // end if ((unsigned long)(currentMillis - previousMillis) >= interval)
//lastTime = millis(); // reset last time data updated
*/
} // end if(millis() > (lastTime + updateTime)
if(millis() > (lastTime + sleepDelay)){
// Put ESP to sleep
Reset = false;
lastTime = millis(); // reset last time data updated
gotoSleep();
} // end if(millis() > (lastTime + sleepDelay)
} // end loop
void connectToWiFi(){
//digitalWrite(LED_PIN, HIGH); // turn on LED
Serial.print("Connecting to Wifi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);
unsigned long startAttemptTime = millis();
while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){
Serial.print(".");
delay(100);
}
if(WiFi.status() != WL_CONNECTED){
Serial.println(" Failed ");
// take some action here because of failed connection
}else{
Serial.print(" Connected! ");
//digitalWrite(LED_PIN, HIGH); // turn on LED
Serial.println(WiFi.localIP());
}
//digitalWrite(LED_PIN, HIGH); // turn on LED
} // end void connectTo WiFi
bool getNTPtime(int sec) {
{
uint32_t start = millis();
do {
time(&now);
localtime_r(&now, &timeinfo);
Serial.print(".");
delay(10);
} while (((millis() - start) <= (1000 * sec)) && (timeinfo.tm_year < (2016 - 1900)));
if (timeinfo.tm_year <= (2016 - 1900)) return false; // the NTP call was not successful
Serial.print("now "); Serial.println(now);
char time_output[30];
strftime(time_output, 30, "%a %d-%m-%y %T", localtime(&now));
Serial.println(time_output);
Serial.println();
}
return true;
}
void showTime(tm localTime) {
Serial.print(localTime.tm_mday);
Serial.print('/');
Serial.print(localTime.tm_mon + 1);
Serial.print('/');
Serial.print(localTime.tm_year - 100);
Serial.print('-');
Serial.print(localTime.tm_hour);
Serial.print(':');
Serial.print(localTime.tm_min);
Serial.print(':');
Serial.print(localTime.tm_sec);
Serial.print(" Day of Week ");
myDataStructure.H1_Hour = localTime.tm_hour;
readHour();
myDataStructure.H1_Min = localTime.tm_min;
readMin();
if (localTime.tm_wday == 0) Serial.println(7);
else Serial.println(localTime.tm_wday);
}
/*
// Shorter way of displaying the time
void showTime(tm localTime) {
Serial.printf(
"%04d-%02d-%02d %02d:%02d:%02d, day %d, %s time\n",
localTime.tm_year + 1900,
localTime.tm_mon + 1,
localTime.tm_mday,
localTime.tm_hour,
localTime.tm_min,
localTime.tm_sec,
(localTime.tm_wday > 0 ? localTime.tm_wday : 7 ),
(localTime.tm_isdst == 1 ? "summer" : "standard")
);
}
*/
//Put the ESP32 device to sleep, woken by the RTC and/or external switch
void gotoSleep() {
Serial.println("Going to sleep");
// Allow wake up if Button Switch is pressed
esp_sleep_enable_ext0_wakeup((gpio_num_t)BTN_PIN, LOW); // could use: GPIO_NUM_26
// Allow RTC to wake up this device after X seconds
esp_sleep_enable_timer_wakeup(SECONDS_TO_SLEEP * uS_TO_S_FACTOR);
// Sleep starts
esp_deep_sleep_start();
}
void getWakeUpReason() {
Serial.print("This is reboot number ");
Serial.print("\t");
Serial.println(bootCount);
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal using RTC_IO");
break;
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wakeup caused by external signal using RTC_CNTL");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by RTC timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
Serial.println("Wakeup caused by ULP program");
break;
default:
Serial.println("Wakeup was not caused by deep sleep:");
}
}
Here is the base code
// Changed controller to ESP32
// Added websocket client
// Removed websocket changed to http communications
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
//Your IP address or domain name with URL path
const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";
const char* serverNameBatt = "http://192.168.4.1/battery";
const char* serverNameHour = "http://192.168.4.1/Gh1_Hour";
const char* serverNameMin = "http://192.168.4.1/Gh1_Min";
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_router = "my_ssid"; // Wifi SSID
const char* password_router = "my_password"; //Wi-FI Password
// http comm
String temperature;
String humidity;
String pressure;
String battery;
String Gh1_Hour;
String Gh1_Min;
unsigned long previousMillis = 0;
const long interval = 5000;
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 Access Point
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("@");
}
Serial.println("");
Serial.print("Connected to Server network with IP Address: ");
Serial.println(WiFi.localIP());
} // end void setup
void loop() {
// read http server
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
if(WiFi.status()== WL_CONNECTED ){
temperature = httpGETRequest(serverNameTemp);
humidity = httpGETRequest(serverNameHumi);
pressure = httpGETRequest(serverNamePres);
battery = httpGETRequest(serverNameBatt);
Gh1_Hour = httpGETRequest(serverNameHour);
Gh1_Min = httpGETRequest(serverNameMin);
Serial.println("Temperature: " + temperature + " *F - Pressure: " + pressure + " in - Humdity: " + humidity + " %");
Serial.println("Time: " + Gh1_Hour + ":" + Gh1_Min + "\t" + "Battery: " + battery);
Serial.println();
// save the last HTTP GET Request
previousMillis = currentMillis;
} // end if(WiFi.status()== WL_CONNECTED
else {
Serial.println("WiFi Disconnected");
}
} // if(currentMillis - previousMillis >= interval)
// 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
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "--";
if (httpResponseCode>0) {
// Serial.print("HTTP Response code: ");
// Serial.println(httpResponseCode);
payload = http.getString();
}
else {
// Serial.print("Error code: ");
// Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
Thanks for your help