Buen día gente. Como andan? Quería compartirles mi código y si alguien está dispuesto a hacerme sugerencias, correcciones o comentarios se lo agradecería y es bienvenido.
Es un codigo para un riego, el cual consta de 3 electrovalvulas y una bomba (activada por un contactor y este por un relay). Además le incorporé modos de depuracion remota, crea un AP donde el cliente se conecta a la ip y al puerto predeterminado y puede conocer el estado del programa, testear cada electrovalvula y tambien setear la hora y fecha del modulo rtc el cual sirve de referencia para iniciar el riego.
/* CAMBIOS
1) MEJORA EN EL MANEJO DE ESTACIONES
2) REORGANIZACION DEL CODIGO EN GENERAL
3) ESCRIBIR Y LEER EEPROM
*/
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <RTClib.h>
#include <EEPROM.h>
RTC_DS1307 rtc;
//WIFI Y SERVER
const char *ssid = "ESP8266";
const char *password = "juan1234";
IPAddress ip(192, 168, 4, 1);
WiFiServer server1(80);
ESP8266WebServer server(90);
WiFiClient client;
WiFiClient client_web;
//PINES
int contactor = 16;
int sensor_a = A0;
int led = 15;
int trafo = 14;
int valvL = 12;
int valvC = 13;
int valvR = 0;
//AJUSTE RELES
const int RON = 0;
const int ROFF = 1;
//VARIABLES DE VALVULAS
const int grupoValv[] = {0, 12, 13, 14};
const int numValves = 3;
int valvePins[numValves] = {12, 13, 0};
int activeValve = -1;
//MODOS
bool modoControl = false;
bool modoTesteo = false;
bool salida = false;
bool exit_control = false;
//PRINTS Y VARIABLES DE MENSAJES
String printHistory[100];
int printIndex = 0;
String command = "";
String message;
String mensajeCliente = "";
//LED
unsigned long tiempoInicioLED = 0;
bool estadoLED = LOW;
//VARIABLES USADAS CON MILLIS
unsigned long tiempoInicio;
unsigned long tiempoActual;
//CONTADORES RIEGO
static int paso = 0;
static unsigned long tiempoInicioPaso = 0;
int ciclos = 0;
int riegos_diarios = 0;
unsigned long tiempo_riego;
//TIEMPOS DE REINICIO
unsigned long tiempoUltimoReinicio = 0;
const unsigned long periodoReinicio = 2592000000UL;
//CONFIGURACION DE ESTACIONES
int estacion = 0;
void setup() {
Serial.begin(115200);
pinMode(trafo, OUTPUT);
pinMode(valvL, OUTPUT);
pinMode(valvC, OUTPUT);
pinMode(valvR, OUTPUT);
pinMode(contactor, OUTPUT);
pinMode(led, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(contactor, LOW);
digitalWrite(trafo, ROFF);
digitalWrite(valvL, ROFF);
digitalWrite(valvC, ROFF);
digitalWrite(valvR, ROFF);
digitalWrite(led, HIGH);
digitalWrite(LED_BUILTIN, LOW);
tiempoUltimoReinicio = millis();
EEPROM.begin(sizeof(tiempo_riego));
EEPROM.get(0, tiempo_riego);
Wire.begin(D4, D1); //D4 (SDA) y D1 (SCL)
rtc.begin();
if (! rtc.begin()) {
Serial.println("Modulo RTC no detectado -X-");
Serial.flush();
while (1) delay(10);
}
for (int i = 0; i < 5; i++) {
digitalWrite(led, HIGH);
delay(250);
digitalWrite(led, LOW);
delay(1000);
}
digitalWrite(led, HIGH);
for (int i = 0; i < numValves; i++) {
pinMode(valvePins[i], OUTPUT);
digitalWrite(valvePins[i], ROFF);
}
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
server.begin();
server1.begin();
delay(4000);
server.on("/history", HTTP_GET, handleHistory);
Serial.println("Servidor web iniciado");
Serial.print("IP Address: ");
Serial.println(IP);
delay(10000);
Serial.println("Esperando instrucciones...");
tiempoInicio = millis();
while (millis() - tiempoInicio < 10000) {
if (Serial.available() > 0) {
String mensaje = Serial.readStringUntil('\n');
if (mensaje.equals("inicio testeo")) {
ejecutarModoTesteo();
break;
}
}
}
ciclos = 0;
riegos_diarios = 0;
exit_control = false;
salida = false;
}
void loop() {
DateTime now = rtc.now();
int month = now.month();
int day = now.day();
digitalWrite(LED_BUILTIN, LOW);
server.handleClient();
//----------------REINICIO PROGRAMADO----------------
unsigned long tiempoActual = millis();
if (tiempoActual - tiempoUltimoReinicio >= periodoReinicio) {
ESP.restart();
}
//----------------REINICIO PROGRAMADO----------------
//----------------DEFINIR TIEMPO RIEGO---------------
if (ciclos <1){
if ((month == 12 && day >=21) || (month == 1) || (month == 2) || (month ==3 && day <=20)){
if (estacion !=1){
tiempo_riego = 20*60*1000;
escribir_EEPROM(tiempo_riego);
message = "╔════════════════════════════════════╗";
print(message);
message = "║ INICIO VERANO ║";
print(message);
message = "╚════════════════════════════════════╝";
print(message);
}
estacion = 1;
}else if ((month == 3 && day >= 21) || (month == 4) || (month == 5 && day <= 20)){
if(estacion !=2){
tiempo_riego = 15*60*1000;
escribir_EEPROM(tiempo_riego);
message = "╔════════════════════════════════════╗";
print(message);
message = "║ INICIO OTOÑO ║";
print(message);
message = "╚════════════════════════════════════╝";
print(message);
}
estacion = 2;
}else if ((month == 5 && day >= 21) || (month == 6) || (month == 7) || (month == 8) || (month == 9 && day <= 20)){
if(estacion !=3){
tiempo_riego = 10*60*1000;
escribir_EEPROM(tiempo_riego);
message = "╔════════════════════════════════════╗";
print(message);
message = "║ INICIO INVIERNO ║";
print(message);
message = "╚════════════════════════════════════╝";
print(message);
}
estacion = 3;
}else if ((month == 9 && day >= 21) || (month == 10) || (month == 11) || (month == 12 && day <=20)){
if(estacion !=4){
tiempo_riego = 15*60*1000;
escribir_EEPROM(tiempo_riego);
message = "╔════════════════════════════════════╗";
print(message);
message = "║ INICIO PRIMAVERA ║";
print(message);
message = "╚════════════════════════════════════╝";
print(message);
}
estacion =4;
}
}
//----------------DEFINIR TIEMPO RIEGO---------------
//-------------------LOOP PRINCIPAL------------------
if (!client.connected()) {
client = server1.available();
}
if (client.connected() && client.available() > 0) {
String command = client.readStringUntil('\n');
command.trim();
/*message = "Loop principal-Comando Recibido: " + String(command);
print(message); */
if (command.equals("Control")) {
modoControl = true;
interacc_client();
modoControl = false;
paso = 0;
tiempoInicioPaso = 0;
goto salida1;
}
enviarMensajesCliente();
}
while (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
if (input.equals("inicio testeo")) {
modoTesteo = true;
ejecutarModoTesteo();
modoTesteo = false;
paso = 0;
tiempoInicioPaso = 0;
}
}
salida1:
if (ciclos < 1 && now.hour() != 18) {
message = "╔════════════════════════════════════╗";
print(message);
message = "║ ESPERANDO HASTA 18HS ║";
print(message);
message = "╚════════════════════════════════════╝";
print(message);
printRTC();
}
if (now.hour() >= 18 && riegos_diarios <1 && now.hour() < 20) {
ejecutarSecuenciaReles();
}
if (now.hour() == 0 && now.minute() == 0 && riegos_diarios != 0){
riegos_diarios = 0;
}
ciclos++;
}
//-------------------LOOP PRINCIPAL------------------
void interacc_client(){
message = "╔══════════════ CONTROL ══════════════";
print(message);
message = "╠══> Inicio Testeo";
print(message);
message = "╠══> Continuar Riego";
print(message);
message = "╠══> Hora RTC";
print(message);
message = "╠══> set_time";
print(message);
message = "║ ╚═>Ejemplo de comando: set_time 15:30:00";
print(message);
message = "╠══> set_date";
print(message);
message = "║ ╚═>Ejemplo de comando: set_date 10/03/2024";
print(message);
message = "╠══> Estado";
print(message);
digitalWrite(contactor, LOW);
delay(700);
desact_grupo();
while (client.connected()) {
if (client.available()) {
String command = client.readStringUntil('\n');
command.trim();
//message = "Control-Comando Recibido: " + String(command);
//print(message);
if (command.equals("verano")) {
tiempo_riego = 20 * 60 * 1000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
message = "Verano";
print(message);
} else if (command.equals("otoño")) {
tiempo_riego = 15 * 60 * 1000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
message = "Otoño";
print(message);
} else if (command.equals("invierno")) {
tiempo_riego = 10 * 60 * 1000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
message = "Invierno";
print(message);
} else if (command.equals("primavera")) {
tiempo_riego = 15 * 60 * 1000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
message = "Primavera";
print(message);
} else if (command.equals("5s")) {
tiempo_riego = 5000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
} else if (command.equals("tiempo_riego")) {
EEPROM.get(0, tiempo_riego);
message = "Valor de tiempo_riego: " + String(tiempo_riego);
print(message);
}
if (command.equals("5s")){
tiempo_riego = 5000;
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
Serial.println("Valor de tiempo_riego guardado correctamente en la EEPROM");
} else {
Serial.println("Error al guardar el valor de tiempo_riego en la EEPROM");
}
}
if (command.startsWith("set_time")) {
message = "╠══════════════<SET TIME>══════════════";
print(message);
DateTime now = rtc.now();
String timeString = command.substring(9);
int hour = timeString.substring(0, 2).toInt();
int minute = timeString.substring(3, 5).toInt();
int second = timeString.substring(6, 8).toInt();
if (hour >= 0 && hour<= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59) {
rtc.adjust(DateTime(now.year(), now.month(), now.day(), hour, minute, second));
message = "║ ╚═> " + String(now.hour()) + ':' + String(now.minute()) + ':' + String(now.second());
print(message);
printRTC();
} else {
message = "║ ╚═>Error: Formato de hora inválido.";
print(message);
}
}
if (command.startsWith("set_date")) {
DateTime now = rtc.now();
message = "╠═════════════<SET DATE>══════════════";
print(message);
//Ejemplo de comando: set_date 10/03/2024
String timeString = command.substring(9);
int day = timeString.substring(0, 2).toInt();
int month = timeString.substring(3, 5).toInt();
int year = timeString.substring(6, 10).toInt();
if (year > 2010 && month > 0 && month <= 12 && day > 0 && day <= 31) {
rtc.adjust(DateTime(year, month, day, now.hour(), now.minute(), now.second()));
/*message = "║ ╚═> " + String(now.year()) + '/' + String(now.month()) + '/' + String(now.day());;
print(message);*/
printRTC();
} else {
message = "║ ╚═>Error: Formato de fecha inválido.";
print(message);
}
}
if (command.equals("Hora RTC")){
printRTC();
}
if (command.equals("inicio testeo")) {
ejecutarModoTesteo();
exit_control = true;
}
if (command.equals("continuar riego")) {
salida = true;
modoTesteo = false;
exit_control = true;
}
if (command.equals("estado")) {
message = "╠══════════════<ESTADO>═══════════════";
print(message);
printRTC();
if (riegos_diarios == 1){
message = "║ ╚══>Riego Diario Realizado";
print(message);
}
else {
message = "║ ╚══>Riego Diario Pendiente";
print(message);
message = "║ ╚══>ESPERANDO HASTA 18HS";
print(message);
}
}
if (salida == true){
static int paso = 0;
static int tiempoInicioPaso = 0;
message = "╚═════════ FIN CONTROL MODE ══════════";
print(message);
exit_control = true;
}
if (exit_control == true){
exit_control = false;
salida = false;
return;
}
}
}
}
void ejecutarModoTesteo() {
message = "╠═════════════<TEST MODE>═════════════";
print(message);
modoTesteo = true;
digitalWrite(contactor, LOW);
desact_grupo();
digitalWrite(trafo, RON);
message = "╠══> Válvula L = 1";
print(message);
message = "╠══> Válvula C = 2";
print(message);
message = "╠══> Válvula R = 3";
print(message);
message = "╠══> Continuar Riego";
print(message);
message = "╠══>Fin Testeo";
print(message);
tiempoInicio = millis();
unsigned long tiempoInicioLED = millis();
bool estadoLED = LOW;
while (modoTesteo) {
if (tiempoActual - tiempoInicioLED >= 500) {
estadoLED = !estadoLED;
digitalWrite(15, estadoLED);
tiempoInicioLED = tiempoActual;
}
if (client.available()) {
String valveNumberStr = client.readStringUntil('\n');
int valveNumber = valveNumberStr.toInt();
valveNumberStr.trim();
if (valveNumberStr.equals("continuar riego")) {
modoTesteo = false;
salida = true;
message = "╠══════════<END TEST MODE>════════════";
print(message);
return;
}
if (valveNumber >= 1 && valveNumber <= numValves) {
digitalWrite(trafo, RON);
tiempoInicio = millis();
message = "║ ╠══>Válvula " + String(valveNumber) + " ON";
print(message);
activateValve(valveNumber);
tiempoInicio = millis();
digitalWrite(contactor, HIGH);
}
if (valveNumberStr.equals("fin testeo")) {
message = "╠══════════<END TEST MODE>════════════";
print(message);
secuencia_FnTst();
break;
}
}
if (Serial.available() > 0) {
String valveNumberStr = Serial.readStringUntil('\n');
int valveNumber = valveNumberStr.toInt();
if (valveNumber >= 1 && valveNumber <= numValves) {
digitalWrite(trafo, RON);
tiempoInicio = millis();
activateValve(valveNumber);
message = "║ ╠══>Válvula " + String(valveNumber) + " ON";
print(message);
digitalWrite(contactor, HIGH);
}
if (valveNumberStr.equals("fin testeo")) {
message = "╠══════════<END TEST MODE>════════════";
print(message);
secuencia_FnTst();
break;
}
}
}
}
void ejecutarSecuenciaReles() {
if (modoControl || modoTesteo) {
paso = 0;
tiempoInicioPaso = 0;
return;
}
static unsigned long tiempoInicioPaso = 0;
unsigned long tiemposEspera[] = {1000, 1000, 0, 1000, 0, 1000, 0, 1000};
tiemposEspera[2] = tiempo_riego;
tiemposEspera[4] = tiempo_riego;
tiemposEspera[6] = tiempo_riego;
unsigned long tiempoActual = millis();
if (tiempoActual < tiempoInicioPaso) {
paso = 0;
}
if (tiempoActual - tiempoInicioPaso >= tiemposEspera[paso]) {
switch (paso) {
case 0:
message = "╔══════════ INICIANDO RIEGO ══════════";
print(message);
desact_grupo();
digitalWrite(trafo, RON);
digitalWrite(valvL, RON);
break;
case 1:
digitalWrite(contactor, HIGH);
message = "╠══> Trafo ON // Válv. L ON // Bombas ON";
print(message);
break;
case 2:
message = "╠══> Válv. C ON";
print(message);
digitalWrite(valvC, RON);
break;
case 3:
digitalWrite(valvL, ROFF);
break;
case 4:
message = "╠══> Válv. R ON";
print(message);
digitalWrite(valvR, RON);
break;
case 5:
digitalWrite(valvC, ROFF);
break;
case 6:
message = "╠══> Bombas OFF";
print(message);
digitalWrite(contactor, LOW);
break;
case 7:
desact_grupo();
message = "╚══════════ RIEGO FINALIZADO ═════════";
print(message);
ciclos = 0;
digitalWrite(led, LOW);
riegos_diarios++;
break;
}
paso++;
tiempoInicioPaso = tiempoActual;
if (paso > 7) {
paso = 0;
}
}
}
void secuencia_FnTst() {
message = "║ ╠══>Apagando Bombas...";
print(message);
digitalWrite(contactor, LOW);
message = "║ ╠══>Apagando Electrovalvulas...";
print(message);
desact_grupo();
message = "║ ╚══>Aguarde 10s para reiniciar...";
print(message);
message = "╚═════════════<REBOOTING>═════════════";
print(message);
delay(10000);
ESP.restart();
}
void config_grupo() {
for (int i = 0; i < sizeof(grupoValv) / sizeof(grupoValv[0]); i++) {
pinMode(grupoValv[i], OUTPUT);
}
}
void activar_grupo() {
for (int i = 0; i < sizeof(grupoValv) / sizeof(grupoValv[0]); i++) {
digitalWrite(grupoValv[i], RON);
}
}
void desact_grupo() {
for (int i = 0; i < sizeof(grupoValv) / sizeof(grupoValv[0]); i++) {
digitalWrite(grupoValv[i], ROFF);
}
}
void print(String message) {
Serial.println(message);
agregarMensajeCliente(message);
enviarMensajesCliente();
addToPrintHistory(message);
message = "";
}
void addToPrintHistory(String message) {
DateTime now = rtc.now();
String dateTimeString = "";
if (now.day() < 10) {
dateTimeString += "0" + String(now.day()) + "/";
} else {
dateTimeString += String(now.day()) + "/";
}
if (now.month() < 10) {
dateTimeString += "0" + String(now.month()) + "/";
} else {
dateTimeString += String(now.month()) + "/";
}
dateTimeString += String(now.year()) + " - ";
if (now.hour() < 10) {
dateTimeString += "0" + String(now.hour()) + ":";
} else {
dateTimeString += String(now.hour()) + ":";
}
if (now.minute() < 10) {
dateTimeString += "0" + String(now.minute()) + ":";
} else {
dateTimeString += String(now.minute()) + ":";
}
if (now.second() < 10) {
dateTimeString += "0" + String(now.second());
} else {
dateTimeString += String(now.second());
}
message = "║" + dateTimeString + " - " + message;
printHistory[printIndex] = message;
printIndex = (printIndex + 1) % 100;
}
void handleHistory() {
EEPROM.get(0, tiempo_riego);
String historyResponse = "Tiempo_riego = " + String(tiempo_riego);
for (int i = 0; i < 100; i++) {
if (printHistory[i] != "") {
historyResponse += printHistory[i] + "\n";
}
}
server.sendHeader("Content-Type", "text/plain; charset=UTF-8");
server.send(200, "text/plain", historyResponse);
}
void agregarMensajeCliente(String mensaje) {
mensajeCliente += mensaje + "\n";
}
void enviarMensajesCliente() {
if (!mensajeCliente.isEmpty()) {
client.print(mensajeCliente);
mensajeCliente = "";
}
}
void activateValve(int valveNumber) {
if (valveNumber != activeValve) {
if (activeValve != -1) {
digitalWrite(valvePins[valveNumber - 1], RON);
message = "║ ╠══>Cambiando Válv.";
print(message);
delay(500);
digitalWrite(valvePins[activeValve - 1], ROFF);
delay(500);
message = "║ ╠══>Válvula " + String(activeValve) + " OFF";
print(message);
digitalWrite(valvePins[valveNumber - 1], RON);
activeValve = valveNumber;
}
}
}
void printRTC() {
DateTime now = rtc.now();
Serial.print("╠══════> ");
if (now.day() < 10){
Serial.print("0");
}
Serial.print(now.day());
Serial.print('/');
if (now.month() < 10){
Serial.print("0");
}
Serial.print(now.month());
Serial.print('/');
Serial.print(now.year());
Serial.print(" - ");
if (now.hour() < 10){
Serial.print("0");
}
Serial.print(now.hour());
Serial.print(':');
if (now.minute() < 10){
Serial.print("0");
}
Serial.print(now.minute());
Serial.print(':');
if (now.second() < 10){
Serial.print("0");
}
Serial.print(now.second());
Serial.println();
client.print("╠══════> ");
if (now.day() < 10){
client.print("0");
}
client.print(now.day());
client.print('/');
if (now.month() < 10){
client.print("0");
}
client.print(now.month());
client.print('/');
client.print(now.year());
client.print(" - ");
if (now.hour() < 10){
client.print("0");
}
client.print(now.hour());
client.print(':');
if (now.minute() < 10){
client.print("0");
}
client.print(now.minute());
client.print(':');
if (now.second() < 10){
client.print("0");
}
client.print(now.second());
client.println();
}
void escribir_EEPROM(unsigned long tiempo_riego){
EEPROM.put(0, tiempo_riego);
if (EEPROM.commit()) {
message = "Valor de tiempo_riego guardado correctamente en la EEPROM";
print(message);
} else {
message = "Error al guardar el valor de tiempo_riego en la EEPROM";
print(message);
}
}```
