//2ºME - Sistema de control de caldera con ESP32 + ThingSpeak + cliente Wifi
#include <WiFi.h> //Librería para poder configurar el WiFi de la ESP32
#include "DHT.h" // Librería del sensor de temperatura y humedad
#include "ThingSpeak.h" //Librería con las funciones para acceder a ThingSpeak
#include <Wire.h> //Incluimos la librería para utilizar el modulo interno I2C de Arduino (pin 21 (SDA) de ESP32 a pin SDA del LCD. Pin 22 (SCL) de ESP32 a pin SCL del LCD)
#include <LiquidCrystal_I2C.h> //Incluimos la librería del LCD I2C
const int DHT_PIN = 2; // Número del pin al que está conectado el sensor DHT22
const int LEDverde = 13; // pin del LED verde (encendido de caldera)
const int LEDrojo = 5; // pin del LED rojo (encendido del sistema)
const int rele1 = 4; // pin de activación de caldera (LED azul) a traves del rele
const char* WIFI_NAME = "Wokwi-GUEST"; // Nombre de la red WiFi
const char* WIFI_PASSWORD = ""; // Contraseña de la red WiFi
const int myChannelNumber = 2433168; // Número de canal de ThingSpeak
const char* myWriteApiKey = "73G5RE03USSOYN1V"; // Clave de API de escritura en ThingSpeak
//Creamos las variables donde guardaremos los datos que recojamos para hacer las condiciones
String TmaxString;
float Tmax = 21.0; //Temperatura máxima por defecto.
float temperatura;
bool estadosistema = false; // Control de estado del sistema (ON/OFF) enviado desde la APP (switch ON/0FF), inicialmente OFF.
//Instanciamos objetos
DHT sensorTemp1(DHT_PIN, DHT22); // Crear una instancia sensor DHT22
LiquidCrystal_I2C lcd1(0x27, 16, 2); // Instanciamos el objeto lcd1 de la clase LCD16x2 con direccion I2C 0x27 (por defecto).
WiFiClient client; // Crear un objeto cliente WiFi
void setup()
{
Serial.begin(9600); // Inicializar la comunicación serial
sensorTemp1.begin(); // Inicializar el sensor DHT22
lcd1.init();
lcd1.setCursor(0, 0);
lcd1.println("SETUP");
pinMode(LEDverde, OUTPUT);
pinMode(LEDrojo, OUTPUT);
pinMode(rele1, OUTPUT);
digitalWrite(rele1, LOW); // rele apagado de inicio, caldera OFF.
digitalWrite(LEDrojo, LOW);
digitalWrite(LEDverde, LOW);
//Nos conectamos a la red Wifi y Creamos el acceso al ThingSpeak
WiFi.begin(WIFI_NAME, WIFI_PASSWORD); // Conectarse a la red WiFi
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("WiFi no conectado"); // Imprimir un mensaje si no se ha conectado al WiFi
}
Serial.println("¡WiFi conectado!"); // Imprimir un mensaje si se ha conectado al WiFi
Serial.print("IP local: "); // Imprimir la dirección IP local
Serial.println(WiFi.localIP());
lcd1.setCursor(0, 0);
lcd1.println("WIFI CONECTADO");
lcd1.setCursor(0, 1);
lcd1.println(WiFi.localIP());
WiFi.mode(WIFI_STA); // Establecer el modo WiFi en modo estación
ThingSpeak.begin(client); // Inicializar la biblioteca ThingSpeak
ThingSpeak.setField(1, Tmax); // Iniciamos Tmax a 21ºC, por defecto
//La linea anterior deberia evitarse, ya que es un campo de lectura
//por parte de ESP32. La solucion es que App inventor envie Tmax=21
//al iniciarse la aplicacion
}
void loop()
{
//Leemos los datos del campo 3 de ThingSpeak (Estado del sistema)
estadosistema = ThingSpeak.readFloatField(myChannelNumber, 3); //Leemos el valor del campo 1 en el canal de ThingSpeak, que corresponde al estado del sistema
int CodigoLectura = ThingSpeak.getLastReadStatus();
if(CodigoLectura == 200) // Si recibe mensaje "http 200"
{
Serial.println("Datos ON/OFF recibidos correctamente"); // Imprimir un mensaje si los datos se recibieron correctamente desde ThingSpeak
}
else
{
Serial.println("Error al recibir los datos ON/OFF" + String(CodigoLectura)); // Imprimir un mensaje de error con el código de estado HTTP si hubo un error al recibir los datos
}
//Leemos los datos del campo 1 de ThingSpeak (Tmax)
Tmax = ThingSpeak.readFloatField(myChannelNumber, 1); //Leemos el valor del campo 1 en el canal de ThingSpeak, que corresponde al Tmax
CodigoLectura = ThingSpeak.getLastReadStatus();
if(CodigoLectura == 200) // Si recibe mensaje "http 200"
{
Serial.println("Datos Tmax recibidos correctamente"); // Imprimir un mensaje si los datos se recibieron correctamente desde ThingSpeak
}
else
{
Serial.println("Error al recibir los datos Tmax" + String(CodigoLectura)); // Imprimir un mensaje de error con el código de estado HTTP si hubo un error al recibir los datos
}
delay(15000); // Retardo para que ThingSpeak pueda enviar Tmax + estadosistema y no esté saturado recogiendo los valores de temperatura
temperatura = sensorTemp1.readTemperature(); // Leer la temperatura del sensor DHT22
ImprimeTemperatura(temperatura);
ThingSpeak.setField(2, temperatura); // Establecer el valor del campo 2 en el canal de ThingSpeak como la temperatura
int CodigoEscritura = ThingSpeak.writeFields(myChannelNumber, myWriteApiKey); // Escribir los datos en el canal de ThingSpeak
if(CodigoEscritura == 200) // Si recibe mensaje "http 200"
{
Serial.println("Temperatura enviada correctamente"); // Imprimir un mensaje si los datos se enviaron correctamente a ThingSpeak
}
else
{
Serial.println("Error al enviar la temperatura" + String(CodigoEscritura)); // Imprimir un mensaje de error con el código de estado HTTP si hubo un error al enviar los datos
}
//Programamos la caldera para que se encienda cuando el sistema esté en ON y La temperatura sea menor que la Tmax
if (estadosistema == true) //Si sistema ON
{
digitalWrite(LEDrojo, HIGH); //Aviso de sistema encendido
digitalWrite(LEDverde, LOW); //Aviso de caldera (relé) apagada
digitalWrite(rele1, LOW); //Apagamos el rele (la caldera)
if (temperatura <= Tmax)
{
digitalWrite(LEDverde, HIGH); //Aviso de caldera encendida
digitalWrite(rele1, HIGH); //Encendemos el rele (la caldera)
}
else
{
digitalWrite(LEDverde, LOW); //Aviso de caldera apagada
digitalWrite(rele1, LOW); //Apagamos el rele (la caldera)
}
}
else //Si sistema OFF
{
digitalWrite(LEDrojo, LOW); //Aviso de sistema apagado
digitalWrite(LEDverde, LOW); //Aviso de caldera apagada
digitalWrite(rele1, LOW); //Apagamos el rele (la caldera
}
Serial.println();
Serial.println("----------------------- ESPERAMOS 15 SEGUNDOS -----------------------------");
Serial.println();
delay(15000); // Retardo para que ThingSpeak pueda recoger la temperatura y no esté saturado enviando Tmax + estadosistema
}
// FUNCIONES
void ImprimeTemperatura(float temp)
{
if (isnan(temp)) //¿hay errores en las lecturas?
{
Serial.println("Error DHT11");
escribirTemperaturaLCD(-1, Tmax);
}
else
{
Serial.print("Temperatura ");
Serial.print(temp);
Serial.println(" ºC");
Serial.print("Temperatura Max ");
Serial.print(Tmax);
Serial.println(" ºC");
escribirTemperaturaLCD(temp, Tmax);
}
}
void escribirTemperaturaLCD(float temp, float tempMax)
{
lcd1.backlight();
lcd1.clear();
if (temp == -1) //Error en la medida del sensor
{
lcd1.setCursor(0, 0); //columna, fila
lcd1.print("Error sensor ");
}
else
{
lcd1.setCursor(0, 0); //columna, fila
lcd1.print("Temp: ");
lcd1.setCursor(6, 0);
lcd1.print(temp);
lcd1.setCursor(11, 0);
lcd1.print((char)223); //simbolo º
lcd1.setCursor(12, 1);
lcd1.print("C");
}
lcd1.setCursor(0, 1);
lcd1.print("Tmax: ");
lcd1.setCursor(6, 1);
lcd1.print(tempMax);
lcd1.setCursor(11, 1);
lcd1.print((char)223); //simbolo º
lcd1.setCursor(12, 1);
lcd1.print("C");
}