I am using an ESP32 Dev Module with the code below, which worked absolutely fine until the last week (beginning of September 2023).
I am using the four virtual PINS V0, V2, V1 and V9. The device stopped reading the V0 and V2 values, but it can still read V1 and V9.
#include <HardwareSerial.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <esp_bt.h>
#include <esp_wifi.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <MAX44009.h>
#include <TimeLib.h> /* Program code related to Real Time Clock (RTC). */
#include <WidgetRTC.h> /* Communication code with Blynk Real Time Clock Widget */
#include <SPI.h>
#include "driver/adc.h"
#define DHT_I_PIN 27
#define PIN_I_VOLTAGE 34
#define PIN_I_RELAY 33
#define POWER_O_PIN1 32
#define POWER_O_PIN2 14
#define SOIL_I_PIN 35
#define V_PIN_I_LIGHT V1
#define V_PIN_O_WATER V2 //This is input data from Blynk for the watering modes: 0 is no watering, 1 is auto mode, 2 always water
#define V_PIN_O_SOIL_DRY V0 //This is to define the level at which to start watering automatically: 50 to 70, recommended is 60.
#define V_PIN_I_TEMP V3
#define V_PIN_I_HUMID V4
#define V_PIN_I_SOIL V5
#define V_PIN_I_VOLTAGE V6
#define V_PIN_I_RELAY V7
#define V_PIN_IO_TERMINAL V8
#define V_PIN_O_WAKE_TIME V9
#define DRY_O_PIN 26 //DRY means the soil is dry and needs watering
#define WET_O_PIN 25 //WET means the soil is wet and does not need watering
#define LED_PIN 22
#define SERIAL_BAUD 9600
#define AIR_VALUE 3500 //DF ROBOT cool sensor last calibrated on 29.10.2021 this is a value from a dry soil top
#define WATER_VALUE 370 //this is value of water, but equal to soil from our garden watered well
#define DELAY 20 //Delay of timer in sec per hour
#define DHTTYPE DHT22
#define I2C_SDA 23
#define I2C_SCL 19
#define LOW_VOLTAGE 2750
#define SLEEP_INT 1800
#define SOIL_DRY_VAL 60
#define BLYNK_PRINT Serial
BlynkTimer timer; /* Define parameter for Blynk Timer */
WidgetRTC rtc; /* Define parameter for RTC Widget */
DHT dht(DHT_I_PIN, DHTTYPE); /* Define the DHT, MAX and Blynk terminal environment */
MAX44009 Lux(0x4A);
WidgetTerminal terminal(V_PIN_IO_TERMINAL);
RTC_DATA_ATTR int wake_count = 0; /* Initialise wake count in the slow memory */
uint8_t water_on = 1, soil_dry = SOIL_DRY_VAL; /* The water_on is parameter set up in Blynk manually, 0 - no watering, 1 - auto watering, 2 - always on;
soil_dry is at what default value watering starts: default is 60*/
uint16_t checkst = 0; /* This parameter and CheckTime used to check if the sent value is correctly reflected in Blynk, if not communcation repeated*/
String CheckTime;
class SoilMoist{
struct SensorsInput{
uint16_t s_moist, voltage, relay, error_dht;
float t = 0, h = 0, lux = 0;
} Sensors;
public:
SoilMoist();
void Sensors_Read(void);
void Blynk_IO(void);
void Switch_Relay(void);
int SleepPause(void);
int get_Relay(void);
};
SoilMoist::SoilMoist(){
Sensors.s_moist = 0;
Sensors.voltage = 0;
Sensors.relay = 0;
Sensors.error_dht = 0;
Sensors.t = 0;
Sensors.h = 0;
Sensors.lux = 0;
}
int SoilMoist::get_Relay(void){
return(Sensors.relay);
}
void callback(){
}
void setup() {
int SleepInterval = SLEEP_INT;
static SoilMoist SoilM;
btStop();
esp_bt_controller_disable();
adc_power_on();
Serial.begin(SERIAL_BAUD);
pinMode(DHT_I_PIN, INPUT);
pinMode(SOIL_I_PIN, INPUT);
pinMode(PIN_I_VOLTAGE, INPUT);
pinMode(PIN_I_RELAY, INPUT);
pinMode(DRY_O_PIN, OUTPUT);
pinMode(WET_O_PIN, OUTPUT);
pinMode(POWER_O_PIN1, OUTPUT);
pinMode(POWER_O_PIN2, OUTPUT);
pinMode(V_PIN_I_LIGHT, INPUT);
pinMode(V_PIN_I_TEMP, INPUT);
pinMode(V_PIN_I_HUMID, INPUT);
pinMode(V_PIN_I_SOIL, INPUT);
pinMode(LED_PIN, OUTPUT);
Wire.begin(I2C_SDA, I2C_SCL);
//Activate LED, power pins, light sensor and the DHT sensor (temperature and humidity)
digitalWrite(LED_PIN, LOW); //Strangely LOW means light up the LED
digitalWrite(POWER_O_PIN1, HIGH); //Power on sensors DHT and Soil
digitalWrite(POWER_O_PIN2, HIGH);
Lux.Begin(0, 188000);
dht.begin();
//Wait 200 milisconds until sensors are activated
delay(200);
SoilM.Sensors_Read();
digitalWrite(POWER_O_PIN1, LOW); //Power off sensors
digitalWrite(POWER_O_PIN2, LOW);
Connect_Blynk();
if(Blynk.connected()){
SoilM.Blynk_IO(); //If connected transfer data to Blynk and read the 'Watering override' option
}
else{
water_on = 1; //If not connected just rely on automatic watering
soil_dry = SOIL_DRY_VAL; //If not connected use this default level of soil dryness
}
SoilM.Switch_Relay(); //Switch relay according to sensor data and Blynk 'Watering override' option
if(Blynk.connected()){
SleepInterval = SoilM.SleepPause();
//Serial.println("\nNext time wake up in"+ (String)(SleepInterval/60) + " min");
terminal.flush();
if(SoilM.get_Relay() < 1000) {
Blynk.virtualWrite(V_PIN_I_RELAY, 0); //Write the state of relay, relay => 1000 means the water is ON
}
else {
Blynk.virtualWrite(V_PIN_I_RELAY, 1);
}
delay(250); //This delay is to let the terminal to flush
}
wake_count++; //increment wake counter
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
adc_power_off();
esp_wifi_stop();
digitalWrite(LED_PIN, HIGH);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_12,1);
esp_sleep_enable_timer_wakeup(1000000ULL * SleepInterval);
esp_sleep_pd_config(ESP_PD_DOMAIN_MAX, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_AUTO);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
esp_deep_sleep_start();
}
void SoilMoist::Sensors_Read() {
int loops = 1;
int soil_moisture = 0, voltage = 0, relay = 0, read_att = 0, error_dht = 0;
float temp = 0, humidity = 0, lux = 0;
for (loops = 1; loops <= 2; loops++){
soil_moisture = constrain(map(analogRead(SOIL_I_PIN), AIR_VALUE, WATER_VALUE, 0, 100), 0, 100);
temp = dht.readTemperature();
humidity = dht.readHumidity();
voltage = analogRead(PIN_I_VOLTAGE);
relay = analogRead(PIN_I_RELAY);
lux = Lux.GetLux();
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
read_att = 0;
while(isnan(temp)){
error_dht = 1;
if((read_att++) > 10) {
temp = 20;
break;
}
temp = dht.readTemperature();
delay(200);
}
read_att = 0;
while(isnan(humidity)){
error_dht = 1;
if((read_att++) > 10) {
humidity = 50;
break;
}
humidity = dht.readHumidity();
delay(200);
}
Sensors.s_moist += soil_moisture;
Sensors.t += temp;
Sensors.h += humidity;
Sensors.voltage += voltage;
Sensors.lux += lux;
Sensors.error_dht += error_dht;
}
Sensors.s_moist = Sensors.s_moist/(loops - 1);
Sensors.t = Sensors.t/(loops - 1);
Sensors.h = Sensors.h/(loops - 1);
Sensors.voltage = Sensors.voltage/(loops - 1);
Sensors.relay = relay;
Sensors.lux = Sensors.lux/(loops - 1);
}
void SoilMoist::Switch_Relay() {
if(Sensors.s_moist > soil_dry && Sensors.relay >= 1000 && water_on == 1){
dacWrite(WET_O_PIN, 255);
delay(200);
dacWrite(WET_O_PIN, 0);
}
else if(Sensors.s_moist <= soil_dry && Sensors.relay < 1000 && water_on == 1){
dacWrite(DRY_O_PIN, 255);
delay(200);
dacWrite(DRY_O_PIN, 0);
}
else if(water_on == 0 && Sensors.relay >= 1000){
dacWrite(WET_O_PIN, 255);
delay(200);
dacWrite(WET_O_PIN, 0);
}
else if(water_on == 2 && Sensors.relay < 1000){
dacWrite(DRY_O_PIN, 255);
delay(200);
dacWrite(DRY_O_PIN, 0);
}
Sensors.relay = analogRead(PIN_I_RELAY);
}
void Connect_Blynk() {
int connect_at = 0;
char ssid[] = "xxxxx";
char pass[] = "xxxxx";
//Initialisation of WiFi and connection to Blynk
WiFi.mode(WIFI_AP_STA);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
while (!Blynk.connected()) {
delay(500);
if(connect_at++ > 15){ // try for less than 16 attempts to connect to Blynk
break;
}}
if(Blynk.connected()){
rtc.begin();
}
else{Serial.println("Was not able to connect to Blynk");}
}
void SoilMoist::Blynk_IO() {
int att_num = 0;
unsigned long TimerStart = 0;
if(wake_count % 10 == 0) {terminal.clear();} //clearing terminal if the cycle is a multiple of 10
//transferring the data to the terminal
terminal.print("\nWake count = "+ (String)wake_count);
terminal.print("\nTemp = "+ (String)Sensors.t + "C");
terminal.print("\nHumidity = "+ (String)Sensors.h + "%");
if(Sensors.error_dht) terminal.print("\n!!WARNING!! There were " + (String)Sensors.error_dht + " error(s) reading DHT sensor!");
terminal.print("\nSoil moisture: " + (String)Sensors.s_moist + "%");
terminal.print("\nLux = "+ (String)Sensors.lux + "L");
terminal.print("\nVoltage = "+ (String)Sensors.voltage);
terminal.print("\nRelay = "+ (String)Sensors.relay);
//the loop tries to send data to Blynk 20 times with interval of 200 ms
while(floor(Sensors.lux) != checkst){
if((att_num++)>20) {break;}
Blynk.syncVirtual(V_PIN_O_WATER);
Blynk.syncVirtual(V_PIN_O_SOIL_DRY);
Blynk.virtualWrite(V_PIN_I_LIGHT, Sensors.lux);
Blynk.virtualWrite(V_PIN_I_VOLTAGE, Sensors.voltage);
Blynk.virtualWrite(V_PIN_I_SOIL, Sensors.s_moist);
Blynk.virtualWrite(V_PIN_I_TEMP, Sensors.t);
Blynk.virtualWrite(V_PIN_I_HUMID, Sensors.h);
Blynk.syncVirtual(V_PIN_I_LIGHT);
TimerStart = millis();
while(millis() - TimerStart < 200) {Blynk.run();}
}
if(att_num > 1) terminal.print("\n!!WARNING!! There were " + (String)att_num + " attempts to send data to Blynk!");
}
int SoilMoist::SleepPause() {
int att_num = 0;
int SleepAdd = 0, WakeUp = 0;
unsigned long TimerStart = 0;
char WakeUpTime[60], LastLogin[9];
/* Define "currentTime" by combining hour, minute and second */
float GetHour = hour() + (float)minute()/60 + (float)second()/3600;
if ((GetHour >= 21 && GetHour < 24)||(GetHour >=0 && GetHour <4.75)) {
SleepAdd = 3 * 3600;}
else if(GetHour >=4.75 && GetHour < 7.63) {
SleepAdd = (7.75 - GetHour) * 2 * SLEEP_INT;
}
else if(GetHour >=7.63 && GetHour < 9) {
SleepAdd = SLEEP_INT;
}
else if(GetHour >=9 && GetHour < 17.75) {
SleepAdd = 4 * SLEEP_INT;
}
else if(GetHour >=17.75 && GetHour < 19.63) {
SleepAdd = (19.75 - GetHour) * 2 * SLEEP_INT;
}
else if(GetHour >=19.63 && GetHour < 21) {
SleepAdd = SLEEP_INT;
}
if ((GetHour + SleepAdd/3600) >= 24) {GetHour -= 24;}
WakeUp = GetHour * 3600 + SleepAdd;
sprintf(WakeUpTime, "Wake %02d:%02d:%02d T=%.1fC H=%.0f%% S=%d%% L=%.1fL", WakeUp / 3600, WakeUp / 60 - (WakeUp / 3600) * 60, WakeUp % 60, Sensors.t, Sensors.h, Sensors.s_moist, Sensors.lux);
sprintf(LastLogin, "%02d:%02d:%02d\0", hour(), minute(), second());
WakeUp += DELAY * SleepAdd / 3600;
while(CheckTime!=(String)WakeUpTime){
if((att_num++)>20) {break;}
Blynk.virtualWrite(V_PIN_O_WAKE_TIME, WakeUpTime);
Blynk.syncVirtual(V_PIN_O_WAKE_TIME);
TimerStart = millis();
while(millis() - TimerStart < 100) {Blynk.run();}
}
if(att_num > 1) terminal.print("\n!!WARNING!! There were " + (String)att_num + " attempts to send timestamp to Blynk!");
terminal.print("\nWatering starts at = " + (String)soil_dry);
terminal.print("\nTimestamp " + (String)LastLogin);
return(SleepAdd);
}
BLYNK_WRITE(V_PIN_O_WATER)
{
water_on = param.asInt(); // Get value as integer
}
BLYNK_WRITE(V_PIN_O_SOIL_DRY)
{
soil_dry = param.asInt(); // Get value as integer
}
BLYNK_WRITE(V_PIN_I_LIGHT)
{
checkst = param.asInt(); // Get value as integer
}
BLYNK_WRITE(V_PIN_O_WAKE_TIME)
{
CheckTime = param.asStr(); // Get value as integer
}
BLYNK_CONNECTED()
{
}
void loop() {
while (Blynk.connected())
{
Blynk.run();
timer.run();
}