#include <WiFi.h>
#include "ThingSpeak.h"
#include "DHTesp.h"
#include <OneWire.h>
#include <DallasTemperature.h>
const char* MINI_CASO = "Caso D - Seguridad ambiental";
const char* SENSORES_USADOS =
"Gas Sensor MQ-2 (AO) + DHT22 (SDA) + DS18B20 (DQ)";
const char* INTERFACES_USADAS =
"ADC1 (gas) | Digital propietaria de un hilo (DHT22) | 1-Wire (DS18B20)";
// Red Wi-Fi del simulador
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
const unsigned long WIFI_TIMEOUT_MS = 10000;
// ThingSpeak
unsigned long CHANNEL_ID = 3450394;
const char* WRITE_API_KEY = "API_KEY";
// Pines
const int GAS_PIN = 4; // MQ-2 AO
const int DHT_PIN = 35; // DHT22 SDA
const int ONE_WIRE_PIN = 6; // DS18B20 DQ (+ pull-up 4.7k a 3V3)
// Umbrales de alerta
const int UMBRAL_GAS = 2170; // fijado con barrido de ppm. 843 ADC sin gas, 3497 ADC a 200 ppm
const float UMBRAL_TEMP = 35.0;
const unsigned long INTERVALO_ENVIO_MS = 20000; // no bajar de 15000 ms
// Umbrales para detectar MQ-2 desconectado (ADC saturado varios ciclos seguidos)
const int GAS_MARGEN_SATURACION = 5;
const int GAS_CICLOS_INVALIDOS = 3;
DHTesp dht;
OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature ds18b20(&oneWire);
WiFiClient cliente;
unsigned long ultimoEnvio = 0;
bool ds18b20Detectado = false;
int muestrasSaturadasGas = 0;
// Conecta Wi-Fi con límite de tiempo
bool conectarWiFi() {
if (WiFi.status() == WL_CONNECTED) return true;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD, 6);
Serial.print("Conectando a Wi-Fi");
unsigned long inicio = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - inicio > WIFI_TIMEOUT_MS) {
Serial.println("\nError: no se logró conectar a Wi-Fi en el tiempo límite");
return false;
}
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi conectado");
Serial.print("Dirección IP: ");
Serial.println(WiFi.localIP());
return true;
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("========================================");
Serial.println(MINI_CASO);
Serial.print("Sensores seleccionados: ");
Serial.println(SENSORES_USADOS);
Serial.print("Interfaces: ");
Serial.println(INTERFACES_USADAS);
Serial.println("========================================");
analogReadResolution(12);
dht.setup(DHT_PIN, DHTesp::DHT22);
ds18b20.begin();
ds18b20Detectado = (ds18b20.getDeviceCount() > 0);
if (!ds18b20Detectado) {
Serial.println("Error de inicialización: no se detectó ningún DS18B20 en el bus 1-Wire (revisar cableado o pull-up)");
}
conectarWiFi();
ThingSpeak.begin(cliente);
}
void loop() {
if (millis() - ultimoEnvio < INTERVALO_ENVIO_MS) return;
ultimoEnvio = millis();
bool wifiOK = conectarWiFi();
// Lectura: gas (MQ-2)
int gasADC = analogRead(GAS_PIN);
bool gasSaturado = (gasADC <= GAS_MARGEN_SATURACION) ||
(gasADC >= 4095 - GAS_MARGEN_SATURACION);
muestrasSaturadasGas = gasSaturado ? (muestrasSaturadasGas + 1) : 0;
bool gasValido = (muestrasSaturadasGas < GAS_CICLOS_INVALIDOS);
// Lectura: temperatura (DS18B20)
float temperaturaC = NAN;
bool dsValido = false;
if (ds18b20Detectado) {
ds18b20.requestTemperatures();
temperaturaC = ds18b20.getTempCByIndex(0);
dsValido = (temperaturaC != DEVICE_DISCONNECTED_C);
}
// Lectura: humedad (DHT22)
TempAndHumidity datosDHT = dht.getTempAndHumidity();
bool dhtValido = !isnan(datosDHT.humidity);
Serial.println("----------------------------------------");
Serial.println(MINI_CASO);
// Mensajes de error
if (!wifiOK) {
Serial.println("Aviso: sin conexión Wi-Fi, no se envían a ThingSpeak");
}
if (!ds18b20Detectado) {
Serial.println("Error: DS18B20 no inicializado; no se puede leer temperatura");
} else if (!dsValido) {
Serial.println("Error: lectura inválida del DS18B20 (sensor desconectado o fuera de rango)");
}
if (!dhtValido) {
Serial.println("Error: lectura inválida del DHT22");
}
if (!gasValido) {
Serial.println("Error: MQ-2 posiblemente desconectado (ADC saturado durante varios ciclos)");
}
if (!dsValido || !dhtValido || !gasValido) {
return;
}
// Estado calculado
bool alerta = (gasADC > UMBRAL_GAS) || (temperaturaC > UMBRAL_TEMP);
int estado = alerta ? 1 : 0;
Serial.printf("Gas (MQ-2, ADC1_CH3 - analógica): %d / 4095\n", gasADC);
Serial.printf("Temperatura (DS18B20, 1-Wire): %.2f °C\n", temperaturaC);
Serial.printf("Humedad (DHT22, digital propietaria): %.2f %%\n", datosDHT.humidity);
Serial.printf("Estado calculado: %s\n", alerta ? "ALERTA" : "SEGURO");
if (!wifiOK) return;
// Envío a ThingSpeak
ThingSpeak.setField(1, gasADC);
ThingSpeak.setField(2, estado);
ThingSpeak.setField(3, temperaturaC);
ThingSpeak.setField(4, datosDHT.humidity);
int respuesta = ThingSpeak.writeFields(CHANNEL_ID, WRITE_API_KEY);
if (respuesta == 200) {
Serial.println("Datos recibidos correctamente por ThingSpeak");
} else {
Serial.printf("Error de envío. Código HTTP: %d\n", respuesta);
}
}