-
Notifications
You must be signed in to change notification settings - Fork 54
Description
I have a code in an ESP32-C3 in ARDUINO-IDE where I read humidity in a plant and then I send it to google sheets so that I can store it and analyze it there. However, I have a problem. If the span of time between messages to google sheets is araound 1 miniute, then there is no problem, but if I put 10 minutes or bigger then it will stop sending data to google sheets.
I read that it could be because the token is not renovating correctly but I do not know how to solve it.
Also, the code uses almost all the memory of the esp32, i do not know if it is related. I does not explain why it works with 1 min, but not 10 or longer.
Thank you.
ERROR:
Append spreadsheet values...
WARN.mRunUntil: Terminating because the ssl engine closed.
ERROR.mConnectSSL: Failed to initlalize the SSL layer.
ERROR.mConnectSSL: Validation time is unknown.
unknown error
CODE:
#include <Arduino.h>
#include "time.h"
#include <ESP_Google_Sheet_Client.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <ArduinoJson.h>
AsyncWebServer server(80);
#define WIFI_SSID ""
#define WIFI_PASSWORD ""
// ID del Proyecto de Google
#define PROJECT_ID "**"
// Correo electrónico del cliente de la Cuenta de Servicio
#define CLIENT_EMAIL "**"
// Clave privada de la Cuenta de Servicio
const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY-----**\n-----END PRIVATE KEY-----\n";
// El ID de la hoja de cálculo donde se publicarán los datos
const char spreadsheetId[] = "**";
int valorHumedad, humedad;
int referencia = 65;
int Amplitud = 10;
int referencia_superior = referencia + Amplitud;
int referencia_inferior = referencia - Amplitud;
int motorEstado = 0; // Variable para almacenar el estado de la bomba de agua
unsigned long lastTime = 0;
const unsigned long interval = 1000; // 1 segundo
unsigned long lastUpdate = 0;
const unsigned long updateInterval = 1800000; // 30 minutos
// Servidor NTP para solicitar la hora
const char* ntpServer = "pool.ntp.org";
// Función que obtiene la hora actual
String getTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "Fallo al obtener la hora";
}
char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%d %H:%M:%S", &timeinfo);
return String(timeStringBuff);
}
void handleRoot(AsyncWebServerRequest *request) {
String html = "";
html += "";
html += "<style>";
html += "body { font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 20px; }";
html += "h1 { font-size: 28px; margin-bottom: 20px; }";
html += "p { font-size: 22px; margin-bottom: 20px; }";
html += "form { margin: 20px 0; }";
html += "input[type='submit'] { font-size: 22px; padding: 15px 30px; margin: 5px; }";
html += "</style>";
html += "";
html += "
Control ESP32
";html += "
Referencia actual: " + String(referencia) + "
";html += "";
html += "";
html += "";
html += "";
html += "";
html += "";
html += "";
html += "";
html += "";
request->send(200, "text/html", html);
}
void handleSetReferencia(AsyncWebServerRequest *request) {
String html = "";
html += "";
html += "<style>";
html += "body { font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 20px; }";
html += "h1 { font-size: 28px; margin-bottom: 20px; }";
html += "a { font-size: 22px; text-decoration: none; color: #0000EE; }";
html += "</style>";
html += "";
if (request->hasParam("action", true)) {
String action = request->getParam("action", true)->value();
if (action == "increase") {
referencia += 10;
} else if (action == "decrease") {
referencia -= 10;
}
html += "
Referencia actualizada!
";} else {
html += "
Error: ¡Acción no proporcionada!
";}
html += "Volver";
html += "";
request->send(200, "text/html", html);
}
void enviarDatosGoogleSheets(int humedad, int motorEstado, int referencia_superior, int referencia_inferior, int referencia) {
FirebaseJson response;
Serial.println("\nAñadiendo valores a la hoja de cálculo...");
Serial.println("----------------------------");
FirebaseJson valueRange;
String currentTime = getTime();
valueRange.add("majorDimension", "COLUMNS");
valueRange.set("values/[0]/[0]", currentTime); // Enviar la fecha y hora combinadas
valueRange.set("values/[1]/[0]", humedad);
valueRange.set("values/[2]/[0]", motorEstado);
valueRange.set("values/[3]/[0]", referencia);
valueRange.set("values/[4]/[0]", referencia_inferior);
valueRange.set("values/[5]/[0]", referencia_superior);
// Añadir valores a la hoja de cálculo
bool success = GSheet.values.append(&response, spreadsheetId, "Hoja1!A1", &valueRange);
if (success) {
response.toString(Serial, true);
valueRange.clear();
} else {
Serial.println(GSheet.errorReason());
}
Serial.println();
Serial.println(ESP.getFreeHeap());
}
void reconnectWiFi() {
if (WiFi.status() != WL_CONNECTED) {
Serial.print("Reconectando a Wi-Fi");
WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.print("Reconectado con IP: ");
Serial.println(WiFi.localIP());
Serial.println();
}
}
void reconnectGoogleSheet() {
if (!GSheet.ready()) {
Serial.println("Reconectando a Google Sheets...");
ESP.restart();
}
}
void tokenStatusCallback(TokenInfo info) {
if (info.status == token_status_error) {
Serial.printf("Información del token: tipo = %s, estado = %s\n", GSheet.getTokenType(info).c_str(), GSheet.getTokenStatus(info).c_str());
Serial.printf("Error del token: %s\n", GSheet.getTokenError(info).c_str());
} else {
Serial.printf("Información del token: tipo = %s, estado = %s\n", GSheet.getTokenType(info).c_str(), GSheet.getTokenStatus(info).c_str());
}
}
void setup() {
Serial.begin(9600);
pinMode(7, OUTPUT); // Configurar el pin de salida para el motor
// Para UTC+2 (horario de verano en España):
configTime(7200, 0, ntpServer);
GSheet.printf("Cliente ESP Google Sheet v%s\n\n", ESP_GOOGLE_SHEET_CLIENT_VERSION);
// Conectar a Wi-Fi
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Conectando a Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.print("Conectado con IP: "); Serial.println(WiFi.localIP());
Serial.println();
// Configurar el callback para la generación del token de acceso de Google API
GSheet.setTokenCallback(tokenStatusCallback);
// Configurar el tiempo de refresco del token de acceso antes de expirar
GSheet.setPrerefreshSeconds(10 * 60);
// Iniciar la generación del token de acceso para la autenticación de Google API
GSheet.begin(CLIENT_EMAIL, PROJECT_ID, PRIVATE_KEY);
// Iniciar el servidor web
server.on("/", HTTP_GET, handleRoot);
server.on("/setReferencia", HTTP_POST, handleSetReferencia);
server.begin();
}
void loop() {
int referencia_superior = referencia + Amplitud;
int referencia_inferior = referencia - Amplitud;
// Llamar a ready() repetidamente en el bucle para verificar la autenticación y el procesamiento
bool ready = GSheet.ready();
reconnectWiFi();
reconnectGoogleSheet();
valorHumedad = analogRead(4); // Leer el valor del sensor de humedad
humedad = map(valorHumedad, 0, 4095, 0, 100); // Mapear el valor del sensor a un porcentaje
// Control por histéresis
if (humedad < referencia_inferior) {
while (humedad < referencia_superior) {
// Enviar datos a Google Sheets
enviarDatosGoogleSheets(humedad, motorEstado, referencia_superior, referencia_inferior, referencia);
digitalWrite(7, HIGH); // Encender el pin de salida
motorEstado = 1; // Actualizar el estado del motor
realizarDelayConHandleClient(1); // Tiempo de muestreo 1 seg si el motor está en ON
valorHumedad = analogRead(4); // Lectura de la humedad
humedad = map(valorHumedad, 0, 4095, 0, 100);
// Para depuración: imprimir valores
Serial.println("Ajustando humedad");
Serial.print("Humedad: "); Serial.println(humedad);
Serial.println("Encendiendo bomba de agua: humedad baja");
}
digitalWrite(7, LOW); // Apagar el pin de salida
motorEstado = 0; // Actualizar el estado del motor
Serial.println("Apagando salida: humedad alcanzada");
// Enviar datos a Google Sheets
enviarDatosGoogleSheets(humedad, motorEstado, referencia_superior, referencia_inferior, referencia);
realizarDelayConHandleClient(60); // 1800 segundos (media hora) de delay comprobando el servidor
} else {
digitalWrite(7, LOW); // Apagar el pin de salida
motorEstado = 0; // Actualizar el estado del motor
Serial.println("Humedad correcta");
Serial.print("Valor humedad = "); Serial.println(humedad); // Imprimir valor de humedad en el monitor serie
// Enviar datos a Google Sheets
enviarDatosGoogleSheets(humedad, motorEstado, referencia_superior, referencia_inferior, referencia);
realizarDelayConHandleClient(60); // 1800 segundos (media hora) de delay comprobando el servidor
}
}
void realizarDelayConHandleClient(int segundos) {
int contador = 0;
while (contador < segundos * 10) { // Multiplicamos por 10 para tener iteraciones de 0.1 segundos
delay(100); // Reducimos el delay a 100 ms
contador++;
yield(); // Permitir que el sistema haga sus tareas de mantenimiento
}
}