But it always had that problem of sometimes sendins only V0, and not the others, even before I write the sleep function.
Here is my code, it’s a bit messy but it’s working, the only problem is that, sometimes it only sends V0 to blynk, so basically what is does is there is a sequence of reading sensors, when that finishes sends the data to blynks and goes to sleep for 15 minutes, and then start over again
#define BLYNK_TEMPLATE_ID "TMPL6HKt-Gbrm"
#define BLYNK_TEMPLATE_NAME "Test"
#define BLYNK_AUTH_TOKEN "nA-QIT6CDdAIN-lAKT1IXZWU04TJN0Ee"
#define TINY_GSM_MODEM_SIM7000
#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>
#include <Arduino.h>
#include <Wire.h>
#include <MCP3XXX.h>
MCP3008 adc;
char auth[] = BLYNK_AUTH_TOKEN;
char apn[] = "telstra.internet";
char user[] = "";
char pass[] = "";
#define NUM_SAMPLES 32 // Número de muestras para promediar
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 900 /* ESP32 should sleep for 900 seconds (15 minutes) */
RTC_DATA_ATTR int bootCount = 0;
#define RES2 820.0
#define ECREF 200.0
#define GDIFF (30/1.8)
#define VR0 0.223
#define G0 2
#define I (1.24 / 10000)
#define SerialAT Serial1
#define UART_BAUD 115200
#define PIN_DTR 25
#define PIN_TX 27
#define PIN_RX 26
#define PWR_PIN 4
#define MODEM_RST 5
#define LED_PIN 12
#define PH_PIN 0
#define EC_PIN 21
#define TEMP_PIN 22
#define PH_CH_ADC 0
#define EC_CH_ADC 1
#define TEMP_CH_ADC 2
#define BATT_CH_ADC 3
#define STABILIZATION_TIME 90000 // Stabilization time in milliseconds
#define SENSOR_OFF_TIME 60000 // Time to turn off sensors before measurements
#define MEASUREMENT_DELAY 60000 // Delay between measurements
TinyGsm modem(SerialAT);
enum SensorState {
IDLE,
PREPARE_SENSOR,
READ_SENSOR,
DEACTIVATE_SENSORS,
WAIT_FOR_NEXT_MEASUREMENT
};
SensorState sensorState = IDLE;
uint8_t currentSensorPin = PH_PIN;
int currentChannel = PH_CH_ADC;
unsigned long lastActivationTime = 0;
unsigned long lastMeasurementTime = 0;
unsigned long lastSampleTime = 0;
unsigned long lastConnectionAttempt = 0;
float PH = 0, TEMP = 0, EC = 0;
int PH_count = 0, TEMP_count = 0, EC_count = 0;
float PH_sum = 0, TEMP_sum = 0, EC_sum = 0;
float voltage = 0;
int sampleCount = 0;
float voltageSum = 0;
bool sensorsRead = false; // Flag to indicate if all sensors have been read
void setup() {
Serial.begin(115200);
adc.begin();
pinMode(PH_PIN, OUTPUT);
pinMode(EC_PIN, OUTPUT);
pinMode(TEMP_PIN, OUTPUT);
digitalWrite(PH_PIN, LOW);
digitalWrite(EC_PIN, LOW);
digitalWrite(TEMP_PIN, LOW);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
modem_on();
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
if (!modem.restart()) {
Serial.println("Failed to restart modem, attempting to continue without restarting");
}
String name = modem.getModemName();
Serial.println("Modem Name: " + name);
modem.disableGPS();
modem.sendAT("+SGPIO=0,4,1,0");
if (modem.waitResponse(10000L) != 1) {
DBG(" SGPIO=0,4,1,0 false ");
}
Blynk.begin(auth, modem, apn, user, pass);
++bootCount;
Serial.println("Boot number: " + String(bootCount));
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
print_wakeup_reason();
}
void print_wakeup_reason() {
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 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.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
}
void deactivateAllSensors() {
digitalWrite(PH_PIN, LOW);
digitalWrite(EC_PIN, LOW);
digitalWrite(TEMP_PIN, LOW);
sensorState = DEACTIVATE_SENSORS;
lastActivationTime = millis();
}
void activateSensor(uint8_t pin) {
digitalWrite(pin, HIGH);
lastActivationTime = millis();
sensorState = PREPARE_SENSOR;
}
void deactivateSensor(uint8_t pin) {
digitalWrite(pin, LOW);
}
void startVoltageReading() {
sampleCount = 0;
voltageSum = 0;
lastSampleTime = millis();
}
bool readVoltage() {
if (sampleCount < NUM_SAMPLES) {
if (millis() - lastSampleTime >= 1000) {
voltageSum += (adc.analogRead(currentChannel) * 3300) / 1023.0;
sampleCount++;
lastSampleTime = millis();
}
return false;
} else {
voltage = voltageSum / NUM_SAMPLES;
return true;
}
}
void sendSensor() {
if (PH_count > 0) {
PH = PH_sum / PH_count;
PH_sum = 0;
PH_count = 0;
}
if (EC_count > 0) {
EC = EC_sum / EC_count;
EC_sum = 0;
EC_count = 0;
}
if (TEMP_count > 0) {
TEMP = TEMP_sum / TEMP_count;
TEMP_sum = 0;
TEMP_count = 0;
}
Blynk.virtualWrite(V0, PH);
Blynk.virtualWrite(V1, EC);
Blynk.virtualWrite(V2, TEMP);
int rssi = modem.getSignalQuality();
int signalPercentage = 0;
if (rssi == 99 || rssi < 0 || rssi > 31) rssi = 0; // Not known, not detectable, or invalid value
signalPercentage = map(rssi, 0, 31, 0, 100);
Blynk.virtualWrite(V3, signalPercentage);
int battV = (adc.analogRead(BATT_CH_ADC) * 3300) / 1023.0;
float battPercentage = map(battV, 1600, 2100, 0, 100);
Blynk.virtualWrite(V4, battPercentage);
Serial.print("Signal %: "); Serial.println(signalPercentage);
Serial.print(" PH : "); Serial.println(PH);
Serial.print(" Temp : "); Serial.println(TEMP);
Serial.print(" EC: "); Serial.println(EC);
}
void shutdown() {
modem_off();
delay(1000);
Serial.flush();
Serial.println("Going to sleep now");
esp_deep_sleep_start();
}
void modem_off() {
Serial.println("Turning modem off");
modem.poweroff();
}
void modem_on()
{
// Set-up modem power pin
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, HIGH);
delay(10);
digitalWrite(PWR_PIN, LOW);
delay(1010); //Ton 1sec
digitalWrite(PWR_PIN, HIGH);
//wait_till_ready();
Serial.println("Waiting till modem ready...");
delay(10000); //Ton uart 4.5sec but seems to need ~7sec after hard (button) reset
//On soft-reset serial replies immediately.
}
void loop() {
Blynk.run();
if (!Blynk.connected()) {
Serial.println("Attempting to reconnect to Blynk...");
if (millis() - lastConnectionAttempt >= 300000) { // Verifica si ha pasado más de cinco minutos
modem_reset();
lastConnectionAttempt = millis(); // Actualiza el tiempo del último intento de conexión
}
Blynk.connect();
} else {
lastConnectionAttempt = millis(); // Reinicia el contador si la conexión es exitosa
}
switch (sensorState) {
case IDLE:
deactivateAllSensors();
break;
case DEACTIVATE_SENSORS:
if (millis() - lastActivationTime >= SENSOR_OFF_TIME) {
activateSensor(currentSensorPin);
}
break;
case PREPARE_SENSOR:
if (millis() - lastActivationTime >= STABILIZATION_TIME) {
startVoltageReading();
sensorState = READ_SENSOR;
}
break;
case READ_SENSOR:
if (readVoltage()) {
// Process sensor reading based on the current sensor
switch (currentSensorPin) {
case PH_PIN:
PH = calculatePH(voltage);
PH_sum += PH;
PH_count++;
break;
case EC_PIN:
EC = calculateEC(voltage, TEMP); // Assume TEMP is known or previously measured
EC_sum += EC;
EC_count++;
break;
case TEMP_PIN:
TEMP = calculateTEMP(voltage);
TEMP_sum += TEMP;
TEMP_count++;
break;
}
deactivateSensor(currentSensorPin);
lastMeasurementTime = millis();
sensorState = WAIT_FOR_NEXT_MEASUREMENT;
}
break;
case WAIT_FOR_NEXT_MEASUREMENT:
if (millis() - lastMeasurementTime >= MEASUREMENT_DELAY) {
// Cycle to the next sensor
if (currentSensorPin == PH_PIN) {
currentSensorPin = EC_PIN;
currentChannel = EC_CH_ADC;
} else if (currentSensorPin == EC_PIN) {
currentSensorPin = TEMP_PIN;
currentChannel = TEMP_CH_ADC;
} else {
currentSensorPin = PH_PIN;
currentChannel = PH_CH_ADC;
sensorsRead = true; // All sensors have been read
}
sensorState = IDLE;
}
break;
}
// Update Blynk if all sensors have been read
if (sensorsRead) {
sendSensor();
sensorsRead = false;
delay(1000); // Ensure the data is sent before going to sleep
shutdown(); // Call shutdown to turn off the modem and put the ESP32 to sleep
}
}
float calculatePH(float voltage) {
float slope = (7.00 - 4.0) / ((1500 - 1500) / 3.0 - (2010 - 1500) / 3.0);
float intercept = 7.00 - slope * ((1500 - 1500) / 3.0);
return slope * (voltage - 1500) / 3.0 + intercept;
}
float calculateTEMP(float voltage) {
float Rpt1000 = ((voltage / 1000) / GDIFF + VR0) / I / G0;
return (Rpt1000 - 1000) / 3.1;
}
float calculateEC(float voltage, float temperature) {
float ecvalueRaw = 100000 * voltage / RES2 / ECREF * 1.3;
float tempCompensationFactor = (temperature == 25.0) ? 1.0 : (1.0 + 0.01 * (temperature - 25.0));
return ecvalueRaw * tempCompensationFactor;
}
void modem_reset() {
Serial.println("\nModem hardware reset\n");
pinMode(MODEM_RST, OUTPUT);
digitalWrite(MODEM_RST, LOW);
delay(260); // Treset 252ms
digitalWrite(MODEM_RST, HIGH);
delay(15000); // Modem takes longer to get ready and reply after this kind of reset vs power on
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
if (!modem.restart()) {
Serial.println("Failed to restart modem, attempting to continue without restarting");
}
String name = modem.getModemName();
Serial.println("Modem Name: " + name);
Blynk.begin(auth, modem, apn, user, pass);
}