#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
// Credenciales WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Configuración MQTT
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
// Sin ID de cliente fijo
// Tópicos MQTT
const char* topicVoltaje = "medicion/voltaje";
const char* topicCorriente = "medicion/corriente";
const char* topicFrecuencia = "medicion/frecuencia";
const char* topicPotencia = "medicion/potencia";
const char* topicEstado = "medicion/estado";
const char* topicControlReset = "control/reset";
// Definición de pines
const int voltagePin = 1;
const int currentPin = 2;
const int controlPin = 7;
const int statusLedPin = 8;
const int buttonOnOffPin = 4;
const int buttonResetPin = 5;
// Variables de estado de los botones
bool lastButtonState = HIGH;
bool lastResetState = HIGH;
// Límites de seguridad
float minVoltage = 108.5;
float maxVoltage = 110.5;
float maxCurrent = 25.0;
// Variables de medición
float VAC = 0.0, lastVAC = -1;
float AmpAC = 0.0, lastAmpAC = -1;
float Power = 0.0, lastPower = -1;
float Frequency = 50.0, lastFrequency = -1;
bool systemEnabled = true, lastSystemState = true;
// Tiempos de actualización
unsigned long lastVoltageReadTime = 0;
unsigned long lastCurrentReadTime = 0;
unsigned long lastControlTime = 0;
unsigned long lastMqttPublishTime = 0;
// Objetos para WiFi y MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// Función para generar ID de cliente aleatorio
String generateRandomClientId() {
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
return clientId;
}
// Lectura de voltaje simulada
float readVoltageFromADC() {
int adcValue = analogRead(voltagePin);
return map(adcValue, 0, 4095, 0, 1300) / 10.0;
}
// Lectura de corriente simulada
float readCurrentFromADC() {
int adcValue = analogRead(currentPin);
return map(adcValue, 0, 4095, 0, 250) / 10.0;
}
// Cálculo de potencia
float calculatePower(float voltage, float current) {
return voltage * current;
}
// Configuración de la conexión WiFi
void setupWiFi() {
delay(10);
Serial.println();
Serial.print("Conectando a WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectado");
Serial.print("Dirección IP: ");
Serial.println(WiFi.localIP());
}
// Reconexión al servidor MQTT
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Conectando al servidor MQTT...");
// Generar un ID de cliente aleatorio
String clientId = generateRandomClientId();
Serial.print("ID de cliente: ");
Serial.print(clientId);
if (client.connect(clientId.c_str())) {
Serial.println(" - conectado");
// Suscribirse al tópico de control
client.subscribe(topicControlReset);
Serial.println("Suscrito al tópico de control/reset");
} else {
Serial.print(" - falló, rc=");
Serial.print(client.state());
Serial.println(" intentando de nuevo en 5 segundos");
delay(5000);
}
}
}
// Callback para procesar mensajes MQTT entrantes
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Mensaje recibido en tópico: ");
Serial.println(topic);
// Convertir payload a string para comparar
char mensaje[length + 1];
for (unsigned int i = 0; i < length; i++) {
mensaje[i] = (char)payload[i];
}
mensaje[length] = '\0';
Serial.print("Mensaje: ");
Serial.println(mensaje);
// Procesar comando de reset
if (strcmp(topic, topicControlReset) == 0) {
if (strcmp(mensaje, "reset") == 0) {
Serial.println("🔄 Reiniciando sistema por comando MQTT...");
resetSystem();
}
}
}
// Función para reiniciar el sistema
void resetSystem() {
Serial.println("🔄 Reiniciando sistema...");
delay(500);
// Apagar el sistema antes de reiniciar
systemEnabled = false;
digitalWrite(controlPin, LOW);
digitalWrite(statusLedPin, LOW);
Serial.println("⚠️ Sistema APAGADO durante reinicio");
// Publicar estado en MQTT
client.publish(topicEstado, "REINICIANDO");
// Encender el sistema nuevamente
delay(5000); // Un pequeño retraso para simular apagado/encendido
systemEnabled = true;
digitalWrite(controlPin, HIGH);
digitalWrite(statusLedPin, HIGH);
Serial.println("🔵 Sistema ENCENDIDO después del reinicio");
// Verificar si los datos de los sensores son válidos
float tempVAC = readVoltageFromADC();
float tempAmpAC = readCurrentFromADC();
if (tempVAC > 0 && tempAmpAC >= 0) {
VAC = tempVAC;
AmpAC = tempAmpAC;
Power = calculatePower(VAC, AmpAC);
Serial.println("✅ Datos válidos. Sistema listo para operar");
client.publish(topicEstado, "ACTIVO");
} else {
Serial.println("❌ Error en medición. Verifique sensores");
systemEnabled = false;
digitalWrite(controlPin, LOW);
digitalWrite(statusLedPin, LOW);
client.publish(topicEstado, "ERROR");
}
}
// Control de potencia
void controlPower() {
if (!systemEnabled) {
digitalWrite(controlPin, LOW);
digitalWrite(statusLedPin, LOW);
if (lastSystemState != systemEnabled) {
Serial.println("🔴 Sistema APAGADO manualmente: Carga desactivada");
client.publish(topicEstado, "INACTIVO");
}
lastSystemState = systemEnabled;
return;
}
bool withinLimits = (VAC >= minVoltage && VAC <= maxVoltage && AmpAC <= maxCurrent);
if (withinLimits) {
digitalWrite(controlPin, HIGH);
digitalWrite(statusLedPin, HIGH);
if (lastSystemState != systemEnabled) {
Serial.println("✅ Carga activada: Condiciones óptimas");
client.publish(topicEstado, "ACTIVO");
}
} else {
digitalWrite(controlPin, LOW);
digitalWrite(statusLedPin, LOW);
if (lastSystemState != systemEnabled) {
if (VAC < minVoltage) {
Serial.println("⚠️ Bajo voltaje: Carga desactivada");
client.publish(topicEstado, "BAJO_VOLTAJE");
}
else if (VAC > maxVoltage) {
Serial.println("⚠️ Sobrevoltaje: Carga desactivada");
client.publish(topicEstado, "SOBREVOLTAJE");
}
else if (AmpAC > maxCurrent) {
Serial.println("⚠️ Sobrecorriente: Carga desactivada");
client.publish(topicEstado, "SOBRECORRIENTE");
}
}
}
lastSystemState = systemEnabled;
}
// Mostrar datos en Serial solo si cambian
void displayData() {
bool voltageChanged = fabs(VAC - lastVAC) > 0.5;
bool currentChanged = fabs(AmpAC - lastAmpAC) > 0.1;
bool powerChanged = fabs(Power - lastPower) > 1.0;
bool frequencyChanged = fabs(Frequency - lastFrequency) > 0.1;
if (voltageChanged || currentChanged || powerChanged || frequencyChanged) {
Serial.println("------- DATOS DEL SISTEMA -------");
Serial.print("Voltaje: "); Serial.print(VAC, 2); Serial.println(" V");
Serial.print("Corriente: "); Serial.print(AmpAC, 2); Serial.println(" A");
Serial.print("Potencia: "); Serial.print(Power, 2); Serial.println(" W");
Serial.print("Frecuencia: "); Serial.print(Frequency, 1); Serial.println(" Hz");
Serial.print("Estado del sistema: "); Serial.println(systemEnabled ? "ACTIVO" : "INACTIVO");
Serial.println("--------------------------------");
lastVAC = VAC;
lastAmpAC = AmpAC;
lastPower = Power;
lastFrequency = Frequency;
}
}
// Publicar datos por MQTT
void publishMQTTData() {
char buffer[10];
// Publicar voltaje
dtostrf(VAC, 6, 2, buffer);
client.publish(topicVoltaje, buffer);
// Publicar corriente
dtostrf(AmpAC, 6, 2, buffer);
client.publish(topicCorriente, buffer);
// Publicar potencia
dtostrf(Power, 6, 2, buffer);
client.publish(topicPotencia, buffer);
// Publicar frecuencia
dtostrf(Frequency, 6, 2, buffer);
client.publish(topicFrecuencia, buffer);
// Publicar estado
client.publish(topicEstado, systemEnabled ? "ACTIVO" : "INACTIVO");
}
// Manejo de botones
void handleButtons() {
bool buttonState = digitalRead(buttonOnOffPin);
bool resetState = digitalRead(buttonResetPin);
// Botón ON/OFF
if (buttonState == LOW && lastButtonState == HIGH) {
systemEnabled = !systemEnabled;
Serial.println(systemEnabled ? "🔵 Sistema ENCENDIDO manualmente" : "🔴 Sistema APAGADO manualmente");
client.publish(topicEstado, systemEnabled ? "ACTIVO" : "INACTIVO");
}
lastButtonState = buttonState;
// Botón RESET
if (resetState == LOW && lastResetState == HIGH) {
resetSystem();
}
lastResetState = resetState;
}
void setup() {
Serial.begin(115200);
Serial.println("Inicializando sistema...");
// Inicializar el generador de números aleatorios
randomSeed(analogRead(0));
analogReadResolution(12);
pinMode(controlPin, OUTPUT);
pinMode(statusLedPin, OUTPUT);
pinMode(buttonOnOffPin, INPUT_PULLUP);
pinMode(buttonResetPin, INPUT_PULLUP);
digitalWrite(controlPin, LOW);
digitalWrite(statusLedPin, LOW);
// Configurar WiFi
setupWiFi();
// Configurar MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
Serial.println("Sistema listo");
}
void loop() {
unsigned long currentMillis = millis();
// Verificar conexión MQTT
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
handleButtons();
if (currentMillis - lastVoltageReadTime >= 100) {
VAC = readVoltageFromADC();
lastVoltageReadTime = currentMillis;
}
if (currentMillis - lastCurrentReadTime >= 100) {
AmpAC = readCurrentFromADC();
lastCurrentReadTime = currentMillis;
}
Power = calculatePower(VAC, AmpAC);
if (currentMillis - lastControlTime >= 200) {
controlPower();
lastControlTime = currentMillis;
}
displayData();
// Publicar datos MQTT cada segundo (1000ms)
if (currentMillis - lastMqttPublishTime >= 1000) {
publishMQTTData();
lastMqttPublishTime = currentMillis;
}
delay(5);
}Voltage Sensor
Current Sensor
SSR Out
POWER ON/OFF
RESET