#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
#include <WiFiMulti.h>
#include <NewPing.h>
#include <DallasTemperature.h>
#include <OneWire.h>
//variables para libreria multiwifi
const uint32_t TiempoEsperaWifi = 5000;
WiFiMulti wifiMulti;
//definimmos cliente wifi
WiFiClient esp32Client;
PubSubClient mqttClient(esp32Client);
//direccion del servidor a conectarse
char *server = "192.168.0.50";
int port = 1883;
// Topicos de Entradas (suscripcion)
const char* mqtt_topic_start = "entrada/jheiser/start";
const char* mqtt_topic_stop = "entrada/jheiser/stop";
const char* mqtt_topic_PE = "entrada/jheiser/PE";
const char* mqtt_topic_vaciar = "entrada/jheiser/vaciar";
const char* mqtt_topic_bomba_on = "entrada/jheiser/bomba_on";
const char* mqtt_topic_modo_manual_mod = "entrada/jheiser/modo_manual_mod";
const char* mqtt_topic_bomba2_on = "entrada/jheiser/bomba2_on";
const char* mqtt_topic_bomba3_on = "entrada/jheiser/bomba3_on";
const char* mqtt_topic_valvula_llenado_on = "entrada/jheiser/valvula_llenado_on";
const char* mqtt_topic_valvula_llenado_on2 = "entrada/jheiser/valvula_llenado_on2";
const char* mqtt_topic_boton_servo = "entrada/jheiser/boton_servo";
const char* mqtt_topic_sp = "entrada/jheiser/sp";
const char* mqtt_topic_kp = "entrada/jheiser/kp";
const char* mqtt_topic_ki = "entrada/jheiser/ki";
const char* mqtt_topic_kd = "entrada/jheiser/kd";
const char* mqtt_topic_ts = "entrada/jheiser/ts";
const char* mqtt_topic_MD = "entrada/jheiser/MD";
const char* mqtt_topic_M_OFF = "entrada/jheiser/M_OFF";
const char* mqtt_topic_H_TOTAL = "entrada/jheiser/H_TOTAL";
const char* mqtt_topic_R_INFERIOR = "entrada/jheiser/R_INFERIOR";
const char* mqtt_topic_R_SUPERIOR = "entrada/jheiser/R_SUPERIOR";
const char* mqtt_topic_H_TOTAL_2 = "entrada/jheiser/H_TOTAL_2";
const char* mqtt_topic_R_INFERIOR_2 = "entrada/jheiser/R_INFERIOR_2";
const char* mqtt_topic_R_SUPERIOR_2 = "entrada/jheiser/R_SUPERIOR_2";
const char* mqtt_topic_reserva = "entrada/jheiser/reserva";
const char* mqtt_topic_OFFSET1 = "entrada/jheiser/OFFSET1";
const char* mqtt_topic_OFFSET2 = "entrada/jheiser/OFFSET2";
const char* mqtt_topic_OFFSET3 = "entrada/jheiser/OFFSET3";
// ServoMotor
Servo servo; // nombre variable de servomotor
int pinServo = 17; // pin del servomotor
// Variables para almacenar los datos de salida (publicacion)
char datos[40];
char datos2[40];
char datos3[40];
char datos4[40];
char datos5[40];
char datos6[40];
char datos7[40];
char datos8[40];
char datos9[40];
char datos10[40];
char datos11[40];
char datos12[40];
char datos13[40];
char datos14[40];
char datos15[40];
char datos16[40];
char datos17[40];
char datos18[40];
char datos19[40];
char datos20[40];
char datos21[40];
char datos22[40];
char datos23[40];
char datos24[40];
char datos25[40];
// estado inicial de salidas para topicos de publicacion
int estBomba=0;
int estBomba2=0;
int estBomba3=0;
int estValvula1=0;
int estValvula2=0;
int estSensorEnvase=0;
int estVaciado=0;
int estPilotoPE=0;
int estPilotollenando=0;
int estPilotosensor=0;
int estpilotoTermicoB1=0;
float estcv;
int estTermicoB1=0;
int estTermicoB2=0;
int estTermicoB3=0;
// variables para sensor ultrasonico 2
#define TRIGGER_PIN 4 // 19
#define ECHO_PIN 36 //18 // 2
#define MAX_DISTANCE 20
float H_TOTAL = 30.9; // Altura total del balde en cm
float R_INFERIOR = 13.1; // Radio inferior en cm
float R_SUPERIOR = 15.1; // Radio superior en cm
// variables para sensor ultrasonico 1
#define TRIGGER_PIN_2 25
#define ECHO_PIN_2 26
#define MAX_DISTANCE_2 20
float H_TOTAL_2 = 30.9; // Altura total del balde en cm
float R_INFERIOR_2 = 13.1; // Radio inferior en cm
float R_SUPERIOR_2 = 15.1; // Radio superior en cm
NewPing sensor1(TRIGGER_PIN , ECHO_PIN, MAX_DISTANCE);
NewPing sensor2(TRIGGER_PIN_2 , ECHO_PIN_2, MAX_DISTANCE_2);
// variables para almacenar los valores desde los topicos de suscripcion
float start_mod;
float stop_mod;
float vaciar_mod;
float PE_mod;
double sp_mod;
double kp_mod;
double ki_mod;
double kd_mod;
double ts_mod;
float H_TOTAL_mod;
float R_INFERIOR_mod;
float R_SUPERIOR_mod;
float H_TOTAL_2_mod;
float R_INFERIOR_2_mod;
float R_SUPERIOR_2_mod;
float reserva_mod;
float OFFSET1_mod;
float OFFSET2_mod;
float OFFSET3_mod;
//MODO MANUAL
float bomba_on_mod;
float modo_manual_mod;
float bomba2_on_mod;
float bomba3_on_mod;
float valvula_on_mod;
float valvula2_on_mod;
float boton_servo_mod;
//VARIABLES CONDICIONES INCIALES
float MD_mod;
float M_OFF_mod;
// variables de control
double SetP;
double SetP_nuevo; //Setpoint enviado desde tópico
int MV = 0; // variable indicadora de sistema vacío
double error = 0; // registra el error
double errorAnt = 0; // registra el error anterior
double errorAntAnt = 0; // registra el error anterior hace dos muestreos
double cv = 0; // accion de control original
double cv_map = 0; // accion de control en el mapeo final
double cvAnt = 0; // accion de control anterior original
double Kp=5; // Acción Proporcional
double Ki=10; // Acción Integral
double Kd=0; // Acción Derivativa
double Ts=0.1; // Tiempo de Muestreo
double valorPID = 0; // Variable donde se almacena el retorno de la funcion PID
double m1 = 0; // variable 1 de retencion de función PID
double m2 = 0; // variable 2 de retencion de función PID
int bomba = 27; // 23 //pin de bomba
int bomba2 = 22; //pin de bomba2
int bomba3 = 21; //pin de bomba3
int Mbomba3 = 0; //Variable para la activación de la bomba de retorno después de un fallo o un Paro de Emergencia
int valvula_1 = 14; //pin de valvula de llenado
int valvula_2 = 13; //pin de valvula de llenado
int pinSensorEnvase = 17; //pin de sensor de envase
int pilotoSistema = 16; // Piloto para indicar Sistema Encendido
int pilotoSensor = 0; // Piloto para indicar presencia de envase
int pilotoPE = 12; // Piloto para indicar PE Activado
int pilotoLlenando = 0; // Piloto para indicar llenado
int sensorEnvase = 0; //registro de sensor de envase
int estEnvase = 0; // condición de llenado de envase
// ETAPAS DEL SISTEMA (E#)
int E0 = 1;
int E1 = 0;
int E2 = 0;
int E3 = 0;
int E4 = 0;
int E_MANUAL = 0; // ETAPA MANUAL
int E5Int = 0; //Etapa interna de la etapa 1 para la confirmacion inicial de llenado del deposito
// MACRO ETAPAS DEL SISTEMA (ME#)
int ME30 = 0;
int ME31 = 0;
int ME32 = 0;
int ME40 = 0;
int ME50 = 0;
int MS = 0; // Variable confirmadora de llenado inicial del depósito principal
int M_OFF = 0; // Variable confirmadora de producción terminada
int selector_modo = 0; // Selector de modo
int MODOs = 0; // variable acondicionadora de modos para la activacion y desactivacion a causa de los selectores
//MODO MANUAL
int boton_bomba1 = 0; //boton para bomba de suministro en modo manual
int boton_bomba2 = 0; //boton para bomba de llenado en modo manual
int boton_bomba3 = 0; //boton para bomba de vaciado en modo manual
int boton_valvula = 0; //boton para valvula de llenado en modo manual
int boton_valvula2 = 0; //boton para valvula de VACIADO en modo manual
int boton_servo = 0; //boton para servovalvula en modo manual
//int trigPin1 = 19; //pin de trigger de sensor ultrasónico superior
//int echoPin1 = 18; //pin de echo de sensor ultrasónico superior
//int trigPin2 = 8; //pin de trigger de sensor ultrasónico inferior
//int echoPin2 = 7; //pin de echo de sensor ultrasónico inferior
float duracion; // duración de viaje de onda sensor superior
float distancia; // distancia leida por el sensor ultrasónico superior
float nivel; //nivel leido por el sensor ultrasónico superior (en centímetros)
//float nivel_metros; //nivel leido por el sensor ultrasónico superior (en metros)
//float volumen_tanque; // volumen del tanque sensor superior (metros cúbicos)
float nivel_litros; // nivel convertido a litros de sensor superior
float duracion_2; // duración de viaje de onda sensor inferior
float distancia_2; // distancia leida por el sensor ultrasónico inferior
float nivel_2; //nivel leido por el sensor ultrasónico inferior (en centímetros)
//float nivel_metros2; //nivel leido por el sensor ultrasónico inferior (en metros)
//float volumen_tanque2; // volumen del tanque sensor inferior (metros cúbicos)
float nivel_litros_2; // nivel convertido a litros de sensor inferior
int pinStart = 2; //4 //pin de inicio del sistema
int pinStop = 33; //2 //pin de paro del sistema
int pinPE = 13; //pin de paro de emergencia
int estSistema = 0; //variable de condicón del sistema (on/off)
//int pinVaciar= 27; //pin de vaciado del sistema
float datoLitros1Viejo = 0; //dato viejo de ultrasónico 1
float datoLitros1Actual; //dato actual de ultrasónico 1
float datoLitros2Viejo = 0; //dato viejo de ultrasónico 2
float datoLitros2Actual; //dato actual de ultrasónico 2
int datoBomba1Viejo = 1; //dato viejo de bomba 1
int datoBomba1Actual; //dato actual de bomba 1
int datoBomba2Viejo = 1; //dato viejo de bomba 2
int datoBomba2Actual; //dato actual de bomba 2
int datoBomba3Viejo = 1; //dato viejo de bomba 3
int datoBomba3Actual; //dato actual de bomba 3
int datoValvulaViejo = 1; //dato viejo de valvula de llenado
int datoValvulaActual; //dato actual de valvula de llenado
int datoValvula2Viejo = 1; //dato viejo de valvula de llenado
int datoValvula2Actual; //dato actual de valvula de llenado
int datoSistemaViejo = 1; //dato viejo de estado del Sistema
int datoSistemaActual; //dato actual de estado del Sistema
int datoSensorEnvaseViejo = 1; //dato viejo de Sensor para Envase
int datoSensorEnvaseActual; //dato actual de Sensor para Envase
float datoCvViejo = 1; //dato viejo de "estcv"
float datoCvActual; //dato actual de "estcv"
int datoPilotoPEViejo = 1; //dato viejo de Piloto de Emergencia
int datoPilotoPEActual; //dato actual de Piloto de Emergencia
int datoPilotoLlenandoViejo = 1; //dato viejo de "Piloto llenando"
int datoPilotoLlenandoActual; //dato actual de "Piloto llenando"
int datoCEViejo = 1; //dato viejo de CE
int datoCEActual; //dato actual de CE
int datoCSViejo = 1; //dato viejo de CS
int datoCSActual; //dato actual de CS
int datoMVViejo = 1; //dato viejo de MV
int datoMVActual; //dato actual de MV
int datoMSViejo = 1; //dato viejo de MV
int datoMSActual; //dato actual de MV
int datoPilotoTermicoViejo = 1; //dato viejo de Piloto de Termicos
int datoPilotoTermicoActual; //dato actual de Piloto de Termicos
int datoPilotoSensorViejo = 1; //dato viejo de Piloto del Sensor de Envase
int datoPilotoSensorActual; //dato actual de Piloto del Sensor de Envase
int datoTermicoB1Viejo = 0; //dato viejo de Termico Bomba 1
int datoTermicoB1Actual; //dato actual de Termico Bomba 1
int datoTermicoB2Viejo = 0; //dato viejo de Termico Bomba 2
int datoTermicoB2Actual; //dato actual de Termico Bomba 2
int datoTermicoB3Viejo = 0; //dato viejo de Termico Bomba 3
int datoTermicoB3Actual; //dato actual de Termico Bomba 3
int datoCMViejo = 1; //dato viejo de CM
int datoCMActual; //dato actual de CM
float datocorriente1Viejo = 0; //dato viejo de sensor corriente 1
float datocorriente1Actual; //dato actual de sensor corriente 1
float datocorriente2Viejo = 0; //dato viejo de sensor corriente 2
float datocorriente2Actual; //dato actual de sensor corriente 2
float datocorriente3Viejo = 0; //dato viejo de sensor corriente 3
float datocorriente3Actual; //dato actual de sensor corriente 3
float datoflujometroViejo = 0; //dato viejo de sensor corriente 3
float datoflujometroActual; //dato actual de sensor corriente 3
unsigned long i = 0; //variable de temporizador de llenado
unsigned long j = 0; //variable de temporizador de confirmación del envase
int v1 = 0; // variables activadora de "if" del tiempo inicial del temporizador
int tiempo = 0;
unsigned long tiempo_actual; // valor actual del millis
unsigned long temporizador; // valor del temporizador al activarse
unsigned long tiempo_inicial; // tiempo de inicio del temporizador desde el millis
unsigned long tiempo_objetivo; // tiempo de finalización del temporizador
unsigned long t_delay_confirmacion = 3000; // tiempo del delay de confirmacion de botella
unsigned long t_calculado = 4000; // tiempo de llenado del envase
const unsigned long temp = 20000UL;
unsigned long mem_temp; // memoria de temporizador para fallos al momento del llenado
int Z = 0; // variable confirmadora de fallos en el momento de llenado
int MF = 0;
int v2 = 0;
//VARIBLES PARA LOS DELAYS CON MILLIS
unsigned long tiempoPrevio = 0; //Variable temp1 almacenadora del ultimo temporizado
unsigned long tiempoPrevio2 = 0; //Variable temp2 almacenadora del ultimo temporizado
unsigned long tiempoPrevio3 = 0; //Variable temp3 almacenadora del ultimo temporizado
unsigned long tiempoPrevio4 = 0; //Variable temp4 almacenadora del ultimo temporizado
unsigned long tiempoPrevio5 = 0; //Variable temp5 almacenadora del ultimo temporizado
unsigned long tiempoPrevio6 = 0; //Variable temp6 (PID) almacenadora del ultimo temporizado
unsigned long tiempoPrevio7 = 0;
unsigned long tiempoPrevio8 = 0;
unsigned long tiempoPrevio9 = 0;
const long intervalo = 100; // variable que designa el tiempo de "delay" de cada temporizador
const long intervalo6 = 5000; // // variable que designa el tiempo de "delay" del temporizador de parámetros PID
int activador1 = 1; // variable para activar temporizador 1
int activador2 = 0; // variable para activar temporizador 2
int activador3 = 0; // variable para activar temporizador 3
int activador4 = 0; // variable para activar temporizador 4
int activador5 = 0; // variable para activar temporizador 5
int activador6 = 0;
int activador7 = 0;
int activador8 = 0;
int activador9 = 0;
//TÉRMICOS
int TermicoB1 = 16; //Pin térmico de bomba 1 (de prueba)
int TermicoB2 = 34; //Pin térmico de bomba 1 (de prueba)
int TermicoB3 = 19; //Pin térmico de bomba 1 (de prueba)
int pilotoTermicoB1 = 0;
// VARIABLES DE ESTADÍSTICA
int CE = 0; // ENVASE DE ENTRADA
int CS = 0; // ENVASE DE SALIDA (LLENO)
int CM = 0; // MERMA
int MD = 0; // VARIABLE DE CONFIRMACIÓN DE DATOS DE SP Y BOTELLAS ENVIADOS CORRECTAMENTE
//CODIGO PARA LEER LA SEÑAL DE CORRIENTE DE UN MODULO ACS712
float Sensibilidad_5A = 0.185; //sensibilidad en Voltios/Amperio para sensor de 5A Sale de la tabla
const int PIN_SENSOR_1 = 39; // Pin analógico donde está conectado el sensor ACS712 de bomba 1
const int PIN_SENSOR_2 = 33; // Pin analógico donde está conectado el sensor ACS712 de bomba 2
const int PIN_SENSOR_3 = 35; // Pin analógico donde está conectado el sensor ACS712 de bomba 3
#define NUM_LECTURAS 200 // Cantidad de mediciones para hacer el promedio
float corriente_1 = 0;
float corriente_2 = 0;
float corriente_3 = 0;
float offset1 = 1.66; // Offset del ACS712 (SENSOR 1) (1.66V para señales DC en esp32 al convertirlo)
float offset2 = 1.66; // Offset del ACS712 (SENSOR 2) (1.66V para señales DC en esp32 al convertirlo)
float offset3 = 1.66; // Offset del ACS712 (SENSOR 3)(1.66V para señales DC en esp32 al convertirlo)
//float offset = 1.66; // Offset del ACS712 (1.66V para señales DC en esp32 al convertirlo)
// Sensor de caudal--------------
volatile int flow_frequency;
float vol = 0.0, l_minute; // Esta es la variable que se debe configurar según el dato
unsigned char flowsensor = 32; // Señal de entrada
unsigned long currentTime;
unsigned long cloopTime;
//Sensor Caudalímetro para leer LITROS
volatile double waterFlow;
double volumenBotella = 1.0;
// Las variables que se tienen declaradas, son:
String c = "c"; // Sensor de caudal
// Sensor de Temperatura
OneWire ourWire(33); // Se establece el pin de entrada de señal de temperatura
DallasTemperature sensors(&ourWire); // Se crea una instancia para el sensor
//FUNCION PID
double funcionPID(){
error = SetP - nivel_litros;
if ((cv < 90 && cv >= 0)&& (m1 == 0 && m2 == 0)){
cv = cvAnt + (Kp+(Kd/Ts))*error + (-Kp +Ki*Ts - (2*Kd/Ts))*errorAnt + (Kd/Ts)*errorAntAnt;
}
if(nivel_litros >= SetP && cv >= 0){
m1=1;
m2=0;
cv = cvAnt + (Kp+(Kd/Ts))*error + (-Kp +Ki*Ts - (2*Kd/Ts))*errorAnt + (Kd/Ts)*errorAntAnt;
}
if((nivel_litros <=SetP - ((2*SetP)/100))&& cv < 90){
m1=0;
m2=1;
cv = cvAnt + (Kp+(Kd/Ts))*error + (-Kp +Ki*Ts - (2*Kd/Ts))*errorAnt + (Kd/Ts)*errorAntAnt;
}
cvAnt = cv;
errorAntAnt = errorAnt;
errorAnt = error;
if (cv >= 90){
cv = 90;
}
if (cv <= 0){
cv = -0.01;
}
if (nivel_litros >= SetP + 0.5){
cv = -0.01;
}
cv_map = map(cv,0,90,90,0);
return cv_map;
}
void bomba1 (){
if (nivel_litros <= SetP ){
digitalWrite(bomba, LOW); //bomba 1 encendida
}
if (nivel_litros >= SetP + 1){
digitalWrite(bomba, HIGH); //bomba 1 apagada
}
}
void bomba_3 (){
if (nivel_litros <= SetP){
digitalWrite(bomba3, HIGH); // bomba3 apagada
Mbomba3 = 0;
}
if (nivel_litros >= SetP + 1){
digitalWrite(bomba3, LOW); // bomba3 encendida
Mbomba3 = 1;
}
if ((nivel_litros < SetP + 1) && (Mbomba3 == 1)){
digitalWrite(bomba3, LOW); // bomba3 encendida
}
}
void sensor_corriente_1(){
float sumLecturas_1 = 0;
// Realizar múltiples lecturas y sumarlas para bomba 1
for (int i = 0; i < NUM_LECTURAS; i++)
{
int bits_1 = analogRead(PIN_SENSOR_1);
float voltage_1 = (bits_1 / 4095.0) * 3.3; // Convertir el valor analógico a voltaje (1.66-3.3V)
sumLecturas_1 += voltage_1;
}
// Calcular el promedio de voltaje
float voltaje_prom_1 = sumLecturas_1 / NUM_LECTURAS;
// Calcular el amperaje en base al voltaje promedio
corriente_1 = (voltaje_prom_1 - offset1) / Sensibilidad_5A;
// Mostrar el valor de corriente en el monitor serie
Serial.print("Corriente bomba 1: ");
Serial.print(corriente_1,3);
Serial.println(" A");
}
void sensor_corriente_2(){
float sumLecturas_2 = 0;
// Realizar múltiples lecturas y sumarlas para bomba 2
for (int i = 0; i < NUM_LECTURAS; i++)
{
int bits_2 = analogRead(PIN_SENSOR_2);
float voltage_2 = (bits_2 / 4095.0) * 3.3; // Convertir el valor analógico a voltaje (1.66-3.3V)
sumLecturas_2 += voltage_2;
}
// Calcular el promedio de voltaje
float voltaje_prom_2 = sumLecturas_2 / NUM_LECTURAS;
// Calcular el amperaje en base al voltaje promedio
corriente_2 = (voltaje_prom_2 - offset2) / Sensibilidad_5A;
// Mostrar el valor de corriente en el monitor serie
Serial.print("Corriente bomba 2: ");
Serial.print(corriente_2,3);
Serial.println(" A");
}
void sensor_corriente_3(){
float sumLecturas_3 = 0;
// Realizar múltiples lecturas y sumarlas para bomba 3
for (int i = 0; i < NUM_LECTURAS; i++)
{
int bits_3 = analogRead(PIN_SENSOR_3);
float voltage_3 = (bits_3 / 4095.0) * 3.3; // Convertir el valor analógico a voltaje (1.66-3.3V)
sumLecturas_3 += voltage_3;
}
// Calcular el promedio de voltaje
float voltaje_prom_3 = sumLecturas_3 / NUM_LECTURAS;
// Calcular el amperaje en base al voltaje promedio
corriente_3 = (voltaje_prom_3 - offset3) / Sensibilidad_5A;
// Mostrar el valor de corriente en el monitor serie
Serial.print("Corriente bomba 3: ");
Serial.print(corriente_3,3);
Serial.println(" A");
//delay(1); // Esperar un poco antes de la siguiente lectura
}
// Función para contar las pulsaciones del sensor de caudal
void flow() {
waterFlow += 1.0 / 450.0;
flow_frequency++;
}
void sensor_caudal(){
// Este código de programación se queda como está:
currentTime = millis();
if (currentTime >= (cloopTime + 1000)) {
cloopTime = currentTime;
if (flow_frequency != 0) {
l_minute = (flow_frequency / 60 * 10 - 0.26);
l_minute = l_minute / 60;
c = vol;
vol = vol + l_minute;
Serial.println(" Caudal:"); // Ls
Serial.print(vol); // Código a editar
flow_frequency = 0; // Reset Counter
Serial.println(" mililitros (mL)"); // Ls
}
}
Serial.println("CAUDAL CAUDAL CAUDAL");
//delay(1);
}
void sensor_temperatura (){
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
Serial.print(" Temperatura:"); // Ls
Serial.print(temp); // Código a editar
Serial.println(" °C"); // Ls
//delay(1);
}
//Configurar libreria multiWifi
void setup_wifi()
{
Serial.println("\nIniciando multi Wifi");
wifiMulti.addAP("Wokwi-GUEST", "");
wifiMulti.addAP("PCel", "pcel12345");
wifiMulti.addAP("Tenda", "24843275jhd");
WiFi.mode(WIFI_STA);
Serial.print("Conectando a Wifi ..");
while (wifiMulti.run(TiempoEsperaWifi) != WL_CONNECTED) {
Serial.print(".");
}
Serial.println(".. Conectado");
Serial.print("SSID:");
Serial.print(WiFi.SSID());
Serial.print(" ID:");
Serial.println(WiFi.localIP());
}
// Recibir datos de topicos desde NODE-RED
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print("Mensaje recibido en el tópico: ");
Serial.println(topic);
Serial.print("Contenido: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// --- Procesar el mensaje según el tópico y convertir a flotante ---
if (String(topic) == mqtt_topic_kp) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
kp_mod = atof(payload_str);
Serial.print("Valor de kp actualizado: ");
Serial.println(kp_mod, 2); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_ki) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
ki_mod = atof(payload_str);
Serial.print("Valor de ki actualizado: ");
Serial.println(ki_mod, 2); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_kd) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
kd_mod = atof(payload_str);
Serial.print("Valor de kd actualizado: ");
Serial.println(kd_mod, 2); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_sp) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
sp_mod = atof(payload_str);
Serial.print("Valor de sp actualizado: ");
Serial.println(sp_mod, 2); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_ts) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
ts_mod = atof(payload_str);
Serial.print("Valor de ts actualizado: ");
Serial.println(ts_mod, 2); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_start) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
start_mod = atof(payload_str);
Serial.print("Valor de start actualizado: ");
Serial.println(start_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_stop) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
stop_mod = atof(payload_str);
Serial.print("Valor de stop actualizado: ");
Serial.println(stop_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_vaciar) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
vaciar_mod = atof(payload_str);
Serial.print("Valor vaciar actualizado: ");
Serial.println(vaciar_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_bomba_on) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
bomba_on_mod = atof(payload_str);
Serial.print("Valor bomba actualizado: ");
Serial.println(bomba_on_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_bomba2_on) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
bomba2_on_mod = atof(payload_str);
Serial.print("Valor bomba2 actualizado: ");
Serial.println(bomba2_on_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_bomba3_on) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
bomba3_on_mod = atof(payload_str);
Serial.print("Valor bomba3 actualizado: ");
Serial.println(bomba3_on_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_valvula_llenado_on) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
valvula_on_mod = atof(payload_str);
Serial.print("Valor valvula actualizado: ");
Serial.println(valvula_on_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_valvula_llenado_on2) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
valvula2_on_mod = atof(payload_str);
Serial.print("Valor valvula actualizado: ");
Serial.println(valvula2_on_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_modo_manual_mod) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
modo_manual_mod = atof(payload_str);
Serial.print("Valor modo manual actualizado: ");
Serial.println(modo_manual_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_boton_servo) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
boton_servo_mod = atof(payload_str);
Serial.print("Valor PE actualizado: ");
Serial.println(boton_servo_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_PE) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
PE_mod = atof(payload_str);
Serial.print("Valor PE actualizado: ");
Serial.println(PE_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_MD) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
MD_mod = atof(payload_str);
Serial.print("Valor MD actualizado: ");
Serial.println(MD_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_M_OFF) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
M_OFF_mod = atof(payload_str);
Serial.print("Valor M_OFF actualizado: ");
Serial.println(M_OFF_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_H_TOTAL) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
H_TOTAL_mod = atof(payload_str);
Serial.print("Valor H_TOTAL actualizado: ");
Serial.println(H_TOTAL_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_R_INFERIOR) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
R_INFERIOR_mod = atof(payload_str);
Serial.print("Valor R_INFERIOR actualizado: ");
Serial.println(R_INFERIOR_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_R_SUPERIOR) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
R_SUPERIOR_mod = atof(payload_str);
Serial.print("Valor R_SUPERIOR_ actualizado: ");
Serial.println(R_SUPERIOR_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_H_TOTAL_2) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
H_TOTAL_2_mod = atof(payload_str);
Serial.print("Valor H_TOTAL_2 actualizado: ");
Serial.println(H_TOTAL_2_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_R_INFERIOR_2) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
R_INFERIOR_2_mod = atof(payload_str);
Serial.print("Valor R_INFERIOR_2 actualizado: ");
Serial.println(R_INFERIOR_2_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_R_SUPERIOR_2) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
R_SUPERIOR_2_mod = atof(payload_str);
Serial.print("Valor R_SUPERIOR_2 actualizado: ");
Serial.println(R_SUPERIOR_2_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_reserva) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
reserva_mod = atof(payload_str);
Serial.print("Valor reserva actualizado: ");
Serial.println(reserva_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_OFFSET1) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
OFFSET1_mod = atof(payload_str);
Serial.print("Valor reserva actualizado: ");
Serial.println(OFFSET1_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_OFFSET2) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
OFFSET2_mod = atof(payload_str);
Serial.print("Valor reserva actualizado: ");
Serial.println(OFFSET2_mod); // Imprimir con 2 decimales
}
}
else if (String(topic) == mqtt_topic_OFFSET3) {
if (length > 0) {
char payload_str[length + 1];
strncpy(payload_str, (char*)payload, length);
payload_str[length] = '\0';
OFFSET3_mod = atof(payload_str);
Serial.print("Valor reserva actualizado: ");
Serial.println(OFFSET3_mod); // Imprimir con 2 decimales
}
}
// agregar más condiciones 'else if' para otros tópicos
}
// conexión a MQTT (nombra los topicos a conectar)
void reconnect()
{
while (!mqttClient.connected())
{
Serial.print("Intentando conectarse MQTT...");
if (mqttClient.connect("esp32Client"))
{
Serial.println("Conectado");
digitalWrite(2,HIGH);
// Opcional: volver a asegurar el keep alive tras reconectar
mqttClient.setKeepAlive(120);
WiFi.setSleep(false);
mqttClient.subscribe(mqtt_topic_start);
mqttClient.subscribe(mqtt_topic_stop);
mqttClient.subscribe(mqtt_topic_PE);
mqttClient.subscribe(mqtt_topic_vaciar);
mqttClient.subscribe(mqtt_topic_bomba_on);
mqttClient.subscribe(mqtt_topic_bomba2_on);
mqttClient.subscribe(mqtt_topic_bomba3_on);
mqttClient.subscribe(mqtt_topic_valvula_llenado_on);
mqttClient.subscribe(mqtt_topic_valvula_llenado_on2);
mqttClient.subscribe(mqtt_topic_modo_manual_mod);
mqttClient.subscribe(mqtt_topic_boton_servo);
mqttClient.subscribe(mqtt_topic_kp);
mqttClient.subscribe(mqtt_topic_ki);
mqttClient.subscribe(mqtt_topic_kd);
mqttClient.subscribe(mqtt_topic_sp);
mqttClient.subscribe(mqtt_topic_ts);
mqttClient.subscribe(mqtt_topic_MD);
mqttClient.subscribe(mqtt_topic_M_OFF);
mqttClient.subscribe(mqtt_topic_H_TOTAL);
mqttClient.subscribe(mqtt_topic_R_INFERIOR);
mqttClient.subscribe(mqtt_topic_R_SUPERIOR);
mqttClient.subscribe(mqtt_topic_H_TOTAL_2);
mqttClient.subscribe(mqtt_topic_R_INFERIOR_2);
mqttClient.subscribe(mqtt_topic_R_SUPERIOR_2);
mqttClient.subscribe(mqtt_topic_reserva);
mqttClient.subscribe(mqtt_topic_OFFSET1);
mqttClient.subscribe(mqtt_topic_OFFSET2);
mqttClient.subscribe(mqtt_topic_OFFSET3);
} else
{
digitalWrite(2,LOW);
Serial.print("Fallo, rc=");
Serial.print(mqttClient.state());
Serial.println(" intentar de nuevo en 5 segundos");
// Wait 5 seconds before retrying
delay(1000);
}
}
}
// Enviar datos desde ESP32 hacia Node-red
void publishData() {
// Publicar los topicos
if (datocorriente1Actual >= (datocorriente1Viejo + 0.01) || datocorriente1Actual <= (datocorriente1Viejo - 0.01) ){
sprintf(datos22, "%3.22f", corriente_1);
mqttClient.publish("salida/jheiser/corriente_1",datos22);
datocorriente1Viejo = datocorriente1Actual;
}
if (datocorriente2Actual >= (datocorriente2Viejo + 0.01) || datocorriente2Actual <= (datocorriente2Viejo - 0.01) ){
sprintf(datos23, "%3.22f", corriente_2);
mqttClient.publish("salida/jheiser/corriente_2",datos23);
datocorriente2Viejo = datocorriente2Actual;
}
if (datocorriente3Actual >= (datocorriente3Viejo + 0.01) || datocorriente3Actual <= (datocorriente3Viejo - 0.01) ){
sprintf(datos24, "%3.22f", corriente_3);
mqttClient.publish("salida/jheiser/corriente_3",datos24);
datocorriente3Viejo = datocorriente3Actual;
}
if (datoflujometroActual >= (datoflujometroViejo + 0.1) || datoflujometroActual <= (datoflujometroViejo - 0.1) ){
sprintf(datos25, "%3.2f", flow_frequency);
mqttClient.publish("salida/jheiser/flujometro",datos25);
datoflujometroViejo = datoflujometroActual;
}
if (datoLitros1Actual >= (datoLitros1Viejo + 0.1) || datoLitros1Actual <= (datoLitros1Viejo - 0.1) ){
sprintf(datos, "%3.2f", nivel_litros);
mqttClient.publish("salida/jheiser/nivel_litros",datos);
datoLitros1Viejo = datoLitros1Actual;
}
if (datoLitros2Actual >= (datoLitros2Viejo + 0.1) || datoLitros2Actual <= (datoLitros2Viejo - 0.1) ){
sprintf(datos11, "%3.2f", nivel_litros_2);
mqttClient.publish("salida/jheiser/nivel_litros_2",datos11);
datoLitros2Viejo = datoLitros2Actual;
}
if( datoBomba1Actual != datoBomba1Viejo){
sprintf(datos2, "%d", estBomba);
mqttClient.publish("salida/jheiser/bomba",datos2);
datoBomba1Viejo = datoBomba1Actual;
}
if( datoBomba2Actual != datoBomba2Viejo){
sprintf(datos3, "%d", estBomba2);
mqttClient.publish("salida/jheiser/bomba2",datos3);
datoBomba2Viejo = datoBomba2Actual;
}
if( datoBomba3Actual != datoBomba3Viejo){
sprintf(datos4, "%d", estBomba3);
mqttClient.publish("salida/jheiser/bomba3",datos4);
datoBomba3Viejo = datoBomba3Actual;
}
if( datoValvulaActual != datoValvulaViejo){
sprintf(datos5, "%d", estValvula1);
mqttClient.publish("salida/jheiser/valvula_llenado",datos5);
datoValvulaViejo = datoValvulaActual;
}
if( datoValvula2Actual != datoValvula2Viejo){
sprintf(datos21, "%d", estValvula2);
mqttClient.publish("salida/jheiser/valvula_llenado2",datos21);
datoValvula2Viejo = datoValvula2Actual;
}
if( datoSistemaActual != datoSistemaViejo){
sprintf(datos6, "%d", estSistema);
mqttClient.publish("salida/jheiser/estSistema",datos6);
datoSistemaViejo = datoSistemaActual;
}
if( datoSensorEnvaseActual != datoSensorEnvaseViejo){
sprintf(datos7, "%d", estSensorEnvase);
mqttClient.publish("salida/jheiser/estEnvase",datos7);
datoSensorEnvaseViejo = datoSensorEnvaseActual;
}
if ((datoCvActual >= (datoCvViejo + 1)) || (datoCvActual <= (datoCvViejo - 1))){
sprintf(datos8, "%3.2f", estcv);
mqttClient.publish("salida/jheiser/estcv",datos8);
datoCvViejo = datoCvActual;
}
if( datoPilotoPEActual != datoPilotoPEViejo){
sprintf(datos9, "%d", estPilotoPE);
mqttClient.publish("salida/jheiser/estPilotoPE",datos9);
datoPilotoPEViejo = datoPilotoPEActual;
}
if( datoPilotoLlenandoActual != datoPilotoLlenandoViejo){
sprintf(datos10, "%d", estPilotollenando);
mqttClient.publish("salida/jheiser/estPilotollenando",datos10);
datoPilotoLlenandoViejo = datoPilotoLlenandoActual;
}
if( datoCEActual != datoCEViejo){
sprintf(datos12, "%d", CE);
mqttClient.publish("salida/jheiser/CE",datos12);
datoCEViejo = datoCEActual;
}
if( datoCSActual != datoCSViejo){
sprintf(datos13, "%d", CS);
mqttClient.publish("salida/jheiser/CS",datos13);
datoCSViejo = datoCSActual;
}
if( datoMVActual != datoMVViejo){
sprintf(datos14, "%d", MV);
mqttClient.publish("salida/jheiser/MV",datos14);
datoMVViejo = datoMVActual;
}
if( datoMSActual != datoMSViejo){
sprintf(datos15, "%d", MS);
mqttClient.publish("salida/jheiser/MS",datos15);
datoMSViejo = datoMSActual;
}
if( datoPilotoTermicoActual != datoPilotoTermicoViejo){
sprintf(datos16, "%d", estpilotoTermicoB1);
mqttClient.publish("salida/jheiser/estpilotoTermicoB1",datos16);
datoPilotoTermicoViejo = datoPilotoTermicoActual;
}
if( datoPilotoSensorActual != datoPilotoSensorViejo){
sprintf(datos17, "%d", estPilotosensor);
mqttClient.publish("salida/jheiser/estPilotosensor",datos17);
datoPilotoSensorViejo = datoPilotoSensorActual;
}
if( datoTermicoB1Actual != datoTermicoB1Viejo){
sprintf(datos18, "%d", estTermicoB1);
mqttClient.publish("salida/jheiser/TermicoB_1",datos18);
datoTermicoB1Viejo = datoTermicoB1Actual;
}
if( datoTermicoB2Actual != datoTermicoB2Viejo){
sprintf(datos19, "%d", estTermicoB2);
mqttClient.publish("salida/jheiser/TermicoB_2",datos19);
datoTermicoB2Viejo = datoTermicoB2Actual;
}
if( datoTermicoB3Actual != datoTermicoB3Viejo){
sprintf(datos20, "%d", estTermicoB3);
mqttClient.publish("salida/jheiser/TermicoB_3",datos20);
datoTermicoB3Viejo = datoTermicoB3Actual;
}
}
// actualizar salidas para publicar en topicos
void Estado_actuadores() {
// salidas a relés (logica inversa HIGH=0 y LOW=1)
if (digitalRead(bomba) == HIGH) {
estBomba=0;
} else {
estBomba=1;
}
if (digitalRead(bomba2) == HIGH) {
estBomba2=0;
} else {
estBomba2=1;
}
if (digitalRead(bomba3) == HIGH) {
estBomba3=0;
} else {
estBomba3=1;
}
if (digitalRead(valvula_1) == HIGH) {
estValvula1=0;
} else {
estValvula1=1;
}
if (digitalRead(valvula_2) == HIGH) {
estValvula2=0;
} else {
estValvula2=1;
}
// entradas
if (digitalRead(pinSensorEnvase) == LOW) {
estSensorEnvase=1;
} else {
estSensorEnvase=0;
}
if (digitalRead(pilotoSistema) == HIGH) {
estSistema=1;
} else {
estSistema=0;
}
if (digitalRead(pilotoPE) == HIGH) {
estPilotoPE=1;
} else {
estPilotoPE=0;
}
if (pilotoLlenando == 1) {
estPilotollenando=1;
} else {
estPilotollenando=0;
}
if (digitalRead(estpilotoTermicoB1) == HIGH) {
estpilotoTermicoB1=1;
} else {
estpilotoTermicoB1=0;
}
if (pilotoSensor == 1) {
estPilotosensor=1;
} else {
estPilotosensor=0;
}
if (digitalRead(TermicoB1) == HIGH) {
estTermicoB1=1;
} else {
estTermicoB1=0;
}
if (digitalRead(TermicoB2) == HIGH) {
estTermicoB2=1;
} else {
estTermicoB2=0;
}
if (digitalRead(TermicoB3) == HIGH) {
estTermicoB3=1;
} else {
estTermicoB3=0;
}
}
// Asigna y actualiza los valores enviados desde Node-red al Esp32
void asignar_valores() {
SetP_nuevo = sp_mod;
Kp = kp_mod;
Ki = ki_mod;
Kd = kd_mod;
Ts = ts_mod;
boton_bomba1 = bomba_on_mod;
boton_bomba2 = bomba2_on_mod;
boton_bomba3 = bomba3_on_mod;
boton_valvula = valvula_on_mod;
boton_valvula2 = valvula2_on_mod;
boton_servo = boton_servo_mod;
selector_modo = modo_manual_mod;
MD = MD_mod;
M_OFF = M_OFF_mod;
H_TOTAL = H_TOTAL_mod;
R_INFERIOR = R_INFERIOR_mod;
R_SUPERIOR = R_SUPERIOR_mod;
H_TOTAL_2 = H_TOTAL_2_mod;
R_INFERIOR_2 = R_INFERIOR_2_mod;
R_SUPERIOR_2 = R_SUPERIOR_2_mod;
offset1 = OFFSET1_mod;
offset2 = OFFSET2_mod;
offset3 = OFFSET3_mod;
if (tiempo_actual - tiempoPrevio6 >= intervalo6){
tiempoPrevio6 = tiempo_actual;
// los valores actuales
Serial.print("Valor actual de kp: ");
Serial.println(Kp, 2); // Imprimir con 2 decimales
Serial.print("Valor actual de ki: ");
Serial.println(Ki, 2); // Imprimir con 2 decimales
Serial.print("Valor actual de kd: ");
Serial.println(Kd, 2); // Imprimir con 2 decimales
Serial.print("Valor actual de sp: ");
Serial.println(SetP, 2); // Imprimir con 2 decimales
Serial.print("Valor actual de ts: ");
Serial.println(Ts, 2); // Imprimir con 2 decimales
}
estcv = map(cv_map, 0, 90, 0, 100);
if (estcv < 0) {
estcv = 0; // Asegurar que no sea negativo
}
// Variables para eliminar la saturación de publicaciones
datoflujometroActual = flow_frequency;
datocorriente1Actual = corriente_1;
datocorriente2Actual = corriente_2;
datocorriente3Actual = corriente_3;
datoLitros1Actual = nivel_litros;
datoLitros2Actual = nivel_litros_2;
datoBomba1Actual = estBomba;
datoBomba2Actual = estBomba2;
datoBomba3Actual = estBomba3;
datoValvulaActual = estValvula1;
datoValvula2Actual = estValvula2;
datoSistemaActual = estSistema;
datoSensorEnvaseActual = estSensorEnvase;
datoCvActual = estcv;
datoPilotoPEActual = estPilotoPE;
datoPilotoLlenandoActual = estPilotollenando;
datoCEActual = CE;
datoCSActual = CS;
datoMVActual = MV;
datoMSActual = MS;
datoPilotoTermicoActual = estpilotoTermicoB1;
datoPilotoSensorActual = estPilotosensor;
datoTermicoB1Actual = estTermicoB1;
datoTermicoB2Actual = estTermicoB2;
datoTermicoB3Actual = estTermicoB3;
}
void lectura_ultrasonico1() {
//sensor ultrasonico
// Realiza una lectura con el filtro de mediana
duracion = sensor1.ping_median();
// Convierte la duración a centímetros
distancia = sensor1.convert_cm(duracion);
if (distancia == 0) { // Si no se detecta nada, asumir que está vacío
Serial.println("Volumen: 0.00 L");
} else {
// 1. Calcular la altura del líquido
float altura_liquido = H_TOTAL - distancia;
if (altura_liquido < 0) {
altura_liquido = 0; // Asegurar que no sea negativo
}
// 2. Calcular el radio de la superficie del líquido (usando la ecuación lineal)
float radio_superficie = (R_SUPERIOR - R_INFERIOR) / H_TOTAL * altura_liquido + R_INFERIOR;
// 3. Calcular el volumen del tronco de cono en cm^3
float volumen_cm3 = (1.0 / 3.0) * PI * altura_liquido * (R_INFERIOR*R_INFERIOR + radio_superficie*radio_superficie + R_INFERIOR*radio_superficie);
// 4. Convertir a litros
float volumen_litros = volumen_cm3 / 1000.0;
nivel= altura_liquido;
nivel_litros= volumen_litros;
Serial.print("NIVEL 1 (Litros): ");
Serial.println(nivel_litros);
}
}
void lectura_ultrasonico2() {
//sensor ultrasonico
// Realiza una lectura con el filtro de mediana
duracion_2 = sensor2.ping_median();
// Convierte la duración a centímetros
distancia_2 = sensor2.convert_cm(duracion_2);
if (distancia_2 == 0) { // Si no se detecta nada, asumir que está vacío
Serial.println("Volumen: 0.00 L");
} else {
// 1. Calcular la altura del líquido
float altura_liquido_2 = H_TOTAL_2 - distancia_2;
if (altura_liquido_2 < 0) {
altura_liquido_2 = 0; // Asegurar que no sea negativo
}
// 2. Calcular el radio de la superficie del líquido (usando la ecuación lineal)
float radio_superficie_2 = (R_SUPERIOR_2 - R_INFERIOR_2) / H_TOTAL_2 * altura_liquido_2 + R_INFERIOR_2;
// 3. Calcular el volumen del tronco de cono en cm^3
float volumen_cm3_2 = (1.0 / 3.0) * PI * altura_liquido_2 * (R_INFERIOR_2*R_INFERIOR_2 + radio_superficie_2*radio_superficie_2 + R_INFERIOR_2*radio_superficie_2);
// 4. Convertir a litros
float volumen_litros_2 = volumen_cm3_2 / 1000.0;
nivel_2= altura_liquido_2;
nivel_litros_2= volumen_litros_2;
Serial.print("NIVEL 2 (Litros): ");
Serial.println(nivel_litros_2);
}
}
void setup() {
servo.attach(pinServo,500,2500);
Serial.begin(115200);
waterFlow = 0;
pinMode(bomba, OUTPUT); // pin de salida para la bomba1
digitalWrite(bomba,HIGH); // bomba1 apagada
pinMode(bomba3, OUTPUT); // pin de salida para la bomba2
digitalWrite(bomba3, HIGH); // bomba3 apagada
pinMode(bomba2, OUTPUT); // pin de salida para la bomba2
digitalWrite(bomba2, HIGH); // bomba2 apagada
pinMode(valvula_1, OUTPUT); // pin de salida para la valvula de llenado
digitalWrite(valvula_1, HIGH); // valvula apagada
pinMode(valvula_2, OUTPUT); // pin de salida para la valvula de llenado
digitalWrite(valvula_2, HIGH); // valvula apagada
//pinMode(pinStart, INPUT_PULLDOWN); // pin de entrada para el Start
//pinMode(pinStop, INPUT_PULLDOWN); // pin de entrada para el Stop
//pinMode(pinPE, INPUT_PULLDOWN); // pin de entrada para el PE
//pinMode(pinSensorEnvase, INPUT_PULLUP); // pin de entrada para el Sensor de envase
//pinMode (trigPin1, OUTPUT); // pin de salida para el trigger sensor superior
//pinMode(echoPin1, INPUT); // pin de entrada para el echo sensor superior
//pinMode (trigPin2, OUTPUT); // pin de salida para el trigger sensor inferior
// pinMode(echoPin2, INPUT); // pin de entrada para el echo sensor inferior
//pinMode(pilotoSistema, OUTPUT); // Piloto para indicar Sistema Encendido
//digitalWrite(pilotoSistema, LOW);
//pinMode(pinVaciar,INPUT_PULLDOWN); // pin de entrada para el VACIADO
//pinMode(pilotoPE, OUTPUT); // Piloto para indicar PE Activado
//digitalWrite(pilotoPE, LOW);
pinMode (TermicoB1, INPUT_PULLDOWN); //Pin térmico de bomba 1 (de prueba)
pinMode (TermicoB2, INPUT_PULLDOWN); //Pin térmico de bomba 2 (de prueba)
pinMode (TermicoB3, INPUT_PULLDOWN); //Pin térmico de bomba 3 (de prueba)
//pinMode (pilotoTermicoB1, OUTPUT); // Piloto para indicar Térmico de Bomba 1 Activado
pinMode(2,OUTPUT);
Estado_actuadores();
asignar_valores();
// Código para el sensor de caudal----------
pinMode(flowsensor, INPUT);
digitalWrite(flowsensor, HIGH); // Optional Internal Pull-Up
attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING); // Configurar la interrupción
Serial.print("Water Flow Meter");
Serial.print("Circuit Digest");
sensors.begin(); // se inicia el sensor
currentTime = millis();
cloopTime = currentTime;
//--------------------------------------------
bool status = c.begin(); // Inicialización del sensor de caudal
if (!status) {
Serial.println("¡No se pudo encontrar un sensor de HUMEDAD válido, verifique el cableado o cambie la dirección I2C!");
while (1);
}
// Establecer conexion Wifi y mqqt
setup_wifi();
mqttClient.setServer(server, port);
mqttClient.setCallback(callback);
mqttClient.setKeepAlive(120); // Establece el margen a 2 minutos
}
void loop() {
// Lectura de datos para enviar al broker
if (!mqttClient.connected())
{
digitalWrite(2,LOW);
reconnect();
}
mqttClient.loop();
//Asegura que el valor del % de la valvula no sea negativo
if (estcv > 0) {
estcv = 0; // Asegurar que no sea negativo
}
tiempo_actual = millis();
Serial.print("Valor de M_OFF: ");
Serial.println(M_OFF);
if ((activador1 == 1) && (tiempo_actual - tiempoPrevio >= intervalo)){
lectura_ultrasonico1();
activador1 = 0;
activador2 = 1;
tiempoPrevio2 = tiempo_actual;
}
if ((activador2 == 1) && (tiempo_actual - tiempoPrevio2 >= intervalo)){
lectura_ultrasonico2();
activador2 = 0;
activador3 = 1;
tiempoPrevio3 = tiempo_actual;
}
if ((activador3 == 1) && (tiempo_actual - tiempoPrevio3 >= intervalo)){
if (digitalRead(bomba) == LOW){
sensor_corriente_1();
}
else if (digitalRead(bomba) == HIGH){
Serial.println("NO SENSANDO CORRIENTE BOMBA 1");
corriente_1 = 0;
}
//Asegura que el valor de la corriente no sea negativo
if (corriente_1 < 0) {
corriente_1 = 0; // Asegurar que no sea negativo
}
activador3 = 0;
activador4 = 1;
tiempoPrevio4 = tiempo_actual;
}
if ((activador4 == 1) && (tiempo_actual - tiempoPrevio4 >= intervalo)){
if (digitalRead(bomba2) == LOW){
sensor_corriente_2();
}
else if (digitalRead(bomba2) == HIGH){
Serial.println("NO SENSANDO CORRIENTE BOMBA 2");
corriente_2 = 0;
}
//Asegura que el valor de la corriente no sea negativo
if (corriente_2 < 0) {
corriente_2 = 0; // Asegurar que no sea negativo
}
activador4 = 0;
activador5 = 1;
tiempoPrevio5 = tiempo_actual;
}
if ((activador5 == 1) && (tiempo_actual - tiempoPrevio5 >= intervalo)){
if (digitalRead(bomba3) == LOW){
sensor_corriente_3();
}
else if (digitalRead(bomba3) == HIGH){
Serial.println("NO SENSANDO CORRIENTE BOMBA 3");
corriente_3 = 0;
}
//Asegura que el valor de la corriente no sea negativo
if (corriente_3 < 0) {
corriente_3 = 0; // Asegurar que no sea negativo
}
activador5 = 0;
activador6 = 1;
tiempoPrevio6 = tiempo_actual;
}
if ((activador6 == 1) && (tiempo_actual - tiempoPrevio6 >= intervalo)){
sensor_temperatura ();
activador6 = 0;
activador7 = 1;
tiempoPrevio7 = tiempo_actual;
}
if ((activador7 == 1) && (tiempo_actual - tiempoPrevio7 >= intervalo)){
Serial.println(flow_frequency);
activador7 = 0;
activador1 = 1;
tiempoPrevio = tiempo_actual;
}
asignar_valores();
publishData();
Estado_actuadores();
// CONDICIÓN DE ACTIVACION DE ETAPA DE MODO MANUAL
if ( (selector_modo == 1) && (MODOs == 0)){
E_MANUAL = 1;
}
//ETAPA DE MODO MANUAL
if (E_MANUAL == 1){
E0 = 0;
E1 = 0;
E2 = 0;
E3 = 0;
E4 = 0;
Serial.println("ETAPA MANUAL ");
// CONDICIÓN DEL ON/OFF DE LA BOMBA DE SUMINISTRO
if (boton_bomba1 == 1){
digitalWrite(bomba, LOW); //bomba 1 encendida
} else if (boton_bomba1 == 0){
digitalWrite(bomba, HIGH); //bomba 1 apagada
}
// CONDICIÓN DEL ON/OFF DE LA BOMBA DE LLENADO CON VALVULA DE LLENADO
if (boton_bomba2 == 1){
digitalWrite(valvula_1, LOW); //valvula encendida
digitalWrite(bomba2, LOW); //bomba 2 encendida
} else if (boton_bomba2 == 0){
digitalWrite(valvula_1, HIGH); //valvula apagada
digitalWrite(bomba2, HIGH); //bomba 2 apagada
}
// CONDICIÓN DEL ON/OFF DE LA BOMBA DE VACIADO
if (boton_bomba3 == 1){
digitalWrite(valvula_2, LOW); //valvula encendida
digitalWrite(bomba3, LOW); //bomba 3 encendida
} else if (boton_bomba3 == 0){
digitalWrite(valvula_2, HIGH); //valvula encendida
digitalWrite(bomba3, HIGH); //bomba 3 apagada
}
// CONDICIÓN DEL ON/OFF DE LA VALVULA DE LLENADO
if (boton_valvula == 1){
digitalWrite(valvula_1, LOW); //valvula encendida
} else if (boton_valvula == 0){
digitalWrite(valvula_1, HIGH); //valvula apagada
}
// CONDICIÓN DEL ON/OFF DE LA VALVULA DE LLENADO
if (boton_valvula2 == 1){
digitalWrite(valvula_2, LOW); //valvula encendida
} else if (boton_valvula2 == 0){
digitalWrite(valvula_2, HIGH); //valvula apagada
}
// CONDICIÓN DEL ON/OFF DE LA SERVOVÁLVULA
if (boton_servo == 1){
servo.write(90);
} else if (boton_servo == 0){
servo.write(0);
}
// CONDICIÓN DE ACTIVACION DE ETAPA DE MODO AUTOMÁTICO
if ((selector_modo == 0) || (digitalRead(TermicoB1) == HIGH) || (digitalRead(TermicoB2) == HIGH) || (digitalRead(TermicoB3) == HIGH)){
E0 = 1;
E_MANUAL = 0;
digitalWrite(bomba, HIGH); //bomba 1 apagada
digitalWrite(bomba2, HIGH); //bomba 2 apagada
digitalWrite(bomba3, HIGH); //bomba 3 apagada
digitalWrite(valvula_1, HIGH); //valvula apagada
digitalWrite(valvula_2, HIGH); //valvula apagada
servo.write(0);
}
}
//ETAPA 0
if (E_MANUAL == 0){
ME50 = 0;
ME40 = 0;
ME30 = 0;
ME32 = 0;
E1 = 0;
E2 = 0;
E3 = 0;
E4 = 0;
MODOs = 0;
v1 = 0;
temporizador = 0;
Serial.println("ETAPA 0 ");
digitalWrite(bomba, HIGH); //bomba 1 apagada
digitalWrite(valvula_1, HIGH); // valvula de llenado apagada inicialmente
digitalWrite(valvula_2, HIGH); // valvula de llenado apagada inicialmente
digitalWrite(bomba3, HIGH); // bomba3 apagada
digitalWrite(bomba2, HIGH); // bomba2 apagada
//digitalWrite(pilotoSistema,LOW); // piloto del sistema apagado
// condición inicial del servomotor
servo.write(90);
cv = 0;
cv_map = 0;
Serial.print("Acción de Control (Grados): ");
Serial.println(cv_map);
// CONDICIÓN DE ACTIVACION DE ETAPA 1 ESTANDO EN ETAPA 0 (START DEL SISTEMA)
if ( (start_mod == 1) ){
E1 = 1;
}
// CONDICIÓN DE ACTIVACION DE ETAPA 4 ESTANDO EN ETAPA 0 (VACIADO)
if ( (/*digitalRead(pinVaciar) == HIGH ||*/ vaciar_mod == 1) && nivel_litros > 0.5){
E4 = 1;
}
}
//ETAPA 1
if (E1 == 1){
ME30 = 0;
ME32 = 0;
E0 = 0;
E2 = 0;
E3 = 0;
E4 = 0;
MODOs = 1;
CS = 0;
CM = 0;
CE = 0;
//AQUÍ SE IMPRIME LA VARIABLE CS
Serial.println("ETAPA 1 ");
digitalWrite(bomba2, HIGH); // bomba2 apagada
digitalWrite(valvula_1, HIGH); // valvula de llenado apagada
bomba_3 ();
if (nivel_litros_2 > reserva_mod){
bomba1 ();
}
if (nivel_litros_2 <= reserva_mod){
digitalWrite(bomba, HIGH); // bomba1 apagada
}
if (nivel_litros_2 > reserva_mod){
// acción de control
valorPID = funcionPID();
// control en servomotor
servo.write(int(valorPID));
}
if (nivel_litros_2 <= reserva_mod){
// condición de desactivación del PID
servo.write(90);
cv = 0;
}
Serial.print("Acción de Control (Grados): ");
Serial.println(cv_map);
if ( digitalRead(pinSensorEnvase) == HIGH){
MF = 0;
}
// CONDICIÓN DE ACTIVACION DE ETAPA 2 ESTANDO EN ETAPA 1 (PRESENCIA DE ENVASE)
if ((digitalRead(pinSensorEnvase) == LOW) && (MF == 0) && (nivel_litros > reserva_mod )){
E2 = 1;
CE = 1;
//AQUÍ SE IMPRIME LA VARIABLE CE
}
/* ETAPA INTERNA (E5Int) de la etapa 1 que se encarga de confirmar
que el deposito está lleno para activar la macroetapa de vacio
y los actuadores de los demas módulos por medio de la variable "MS"*/
}
// ETAPA 2
if ( E2 == 1){
E0 = 0;
E1 = 0;
E3 = 0;
E4 = 0;
//AQUÍ SE IMPRIME LA VARIABLE CE
Serial.println("ETAPA 2 ");
bomba_3 ();
if (nivel_litros_2 > reserva_mod){
bomba1 ();
}
if (nivel_litros_2 <= reserva_mod){
digitalWrite(bomba, HIGH); // bomba1 apagada
}
//INICIO TEMPORIZADOR
if (v1 == 0){
tiempo_inicial = millis();
tiempo_actual = millis();
temporizador = 0;
// TIEMPO DEL TEMPORIZADOR
tiempo_objetivo = tiempo_inicial + t_delay_confirmacion;
v1 = 1;
}
temporizador = (tiempo_actual - tiempo_inicial)*0.001;
Serial.print("temporizador 1 (Seg): ");
Serial.println(temporizador);
digitalWrite(bomba2, HIGH); // bomba2 apagada
digitalWrite(valvula_1, HIGH); // valvula de llenado apagada
if (nivel_litros_2 > reserva_mod){
// acción de control
valorPID = funcionPID();
// control en servomotor
servo.write(int(valorPID));
}
if (nivel_litros_2 <= reserva_mod){
// condición de desactivación del PID
servo.write(90);
cv = 0;
}
Serial.print("Acción de Control (Grados): ");
Serial.println(cv_map);
// CONDICIÓN DE ACTIVACION DE ETAPA 3 ESTANDO EN ETAPA 2 (FINAL DE TEMPORIZACIÓN)
if ( tiempo_actual >= tiempo_objetivo){
E3 = 1;
v1 = 0;
temporizador = 0;
}
// CONDICIÓN DE ACTIVACION DE ETAPA 1 ESTANDO EN ETAPA 2 (AUSENCIA DE ENVASE)
if ( digitalRead(pinSensorEnvase) == HIGH){
E1 = 1;
v1 = 0;
waterFlow = 0;
}
// CONDICIÓN DE ACTIVACION DE ETAPA 1 ESTANDO EN ETAPA 2 (SISTEMA VACÍO)
if ( nivel_litros <= reserva_mod){
E1 = 1;
v1 = 0;
}
}
// ETAPA 3
if ( E3 == 1){
E0 = 0;
E1 = 0;
E2 = 0;
E4 = 0;
Serial.println("ETAPA 3 ");
bomba_3 ();
if (nivel_litros_2 > reserva_mod){
bomba1 ();
}
if (nivel_litros_2 <= reserva_mod){
digitalWrite(bomba, HIGH); // bomba1 apagada
}
/*//PRUEBA CON POTENCIÓMETRO
flow_pot = analogRead(flowsensor);
waterFlow = flow_pot/3069.0;
*/
// INICIO DE LLENADO
Serial.print("LLENANDO BOTELLA: ");
Serial.print(waterFlow);
Serial.println("L");
digitalWrite(valvula_1, LOW); // valvula de llenado encendida
digitalWrite(bomba2, LOW); // bomba2 encendida
if (nivel_litros_2 > reserva_mod){
// acción de control
valorPID = funcionPID();
// control en servomotor
servo.write(int(valorPID));
}
if (nivel_litros_2 <= reserva_mod){
// condición de desactivación del PID
servo.write(90);
cv = 0;
}
Serial.print("Acción de Control (Grados): ");
Serial.println(cv_map);
// CONDICIÓN DE ACTIVACION DE ETAPA 1 ESTANDO EN ETAPA 3 (FINAL DE LLENADO DE BOTELLA)
if ( waterFlow >= volumenBotella){
E1 = 1;
v1 = 0;
MF = 1;
CS = 1;
waterFlow = 0;
//AQUÍ SE IMPRIME LA VARIABLE CS
}
// CONDICIÓN DE ACTIVACION DE ETAPA 1 ESTANDO EN ETAPA 3 (AUSENCIA DE ENVASE)
if ( digitalRead(pinSensorEnvase) == HIGH){
E1 = 1;
v1 = 0;
CM = 1;
waterFlow = 0;
}
}
//ETAPA 4
if ( E4 == 1 ){
E0 = 0;
E1 = 0;
E2 = 0;
E3 = 0;
Serial.println("ETAPA 4 ");
digitalWrite(valvula_2, LOW); //valvula encendida
digitalWrite(bomba3, LOW); // bomba3 encendida
// CONDICIÓN DE ACTIVACION DE ETAPA 0 ESTANDO EN ETAPA 4 (TANQUE VACÍO)
if (nivel_litros <= reserva_mod/2){
E0 = 1;
}
}
}