Hola! tengoun ESP32 trabajando para levantar datos de una estacion meteorologica para mi web, el tema es que tengo falsas activaciones en el pluviometro, me tira datos falsos
Ya descarte que sea el reedswitch que se activa.
Es ruido xq de la nada me suba un monton de activaciones
tengo conectado al reedswitch asi
3.3v A entrada del reedswitch y a la vuelta hay una resistencia de 10k directo a GND en paralelo con un capacitor ceramico 104
Ya probe mandando GND al sensor y es peor.
estoy alimentando con un cargador de celular Xiaomi original, empalme con un USB, cable de telefono apantallado hasta arriba del techo y conectado al 5v del esp32
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <time.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <WiFiServer.h>
#include "SinricPro.h"
#include "SinricProTemperaturesensor.h"
// ==========================================
// CREDENCIALES
// ==========================================
#define WIFI_SSID "ParraX_IoT"
#define WIFI_PASSWORD ""
#define SERVER_URL ""
#define SINRIC_APP_KEY ""
#define SINRIC_APP_SECRET ""
#define SINRIC_DEVICE_ID ""
#define BOT_TOKEN ""
#define CHAT_ID_GENERAL ""
#define CHAT_ID_ALERTAS ""
#define OTA_PASSWORD "admin123"
// --- CREDENCIALES WUNDERGROUND ---
const char* WU_ID = "";
const char* WU_KEY = "";
// ==========================================
// CONSTANTES DE HARDWARE
// ==========================================
const int PIN_VELETA = 34;
const int PIN_PLUVIOMETRO = 25;
const int PIN_ANEMOMETRO = 26;
const float FACTOR_VIENTO_KMH = 2.4f;
const float TEMP_MIN = -10.0f;
const float TEMP_MAX = 55.0f;
const float LLUVIA_POR_CLICK = 0.2794f;
// ==========================================
// CONSTANTES DE TIEMPO
// ==========================================
const long GMT_OFFSET_SEC = -10800;
const int DST_OFFSET_SEC = 0;
const unsigned long INTERVALO_ENVIO_MS = 60000UL;
const unsigned long INTERVALO_TELEGRAM_MS = 5000UL;
const unsigned long DEBOUNCE_LLUVIA_MS = 100UL;
const unsigned long DEBOUNCE_VIENTO_MS = 15UL;
const unsigned long TIMEOUT_WIFI_MS = 15000UL;
const unsigned long COOLDOWN_ALERTA_LLUVIA = 300000UL; // 5 minutos entre alertas de lluvia
// ==========================================
// VARIABLES VOLÁTILES (ISR)
// ==========================================
volatile unsigned long totalClicksLluvia = 0;
volatile unsigned long clicksLluviaPeriodo = 0;
volatile unsigned int clicksViento = 0;
volatile unsigned long ultimoClickLluvia = 0;
volatile unsigned long ultimoClickViento = 0;
volatile bool banderaLluvia = false;
unsigned long tiempoAnteriorEnvio = 0;
unsigned long ultimaVezTelegram = 0;
unsigned long tiempoReconexionWiFi = 0;
unsigned long ultimoAvisoTelegramLluvia = 0;
long ultimoUpdateId = 0;
Adafruit_BME280 bme;
WiFiServer serverTelnet(23);
WiFiClient clienteTelnet;
// ==========================================
// PROTOTIPOS
// ==========================================
void IRAM_ATTR registroLluvia();
void IRAM_ATTR registroViento();
void conectarWiFi();
void chequearWiFi();
void configurarOTA();
void logConsola(const String& mensaje);
void manejarConsola();
void enviarTelegram(String mensaje, String targetChatId);
void revisarComandosTelegram();
void reiniciarSistema(const String& motivo);
float leerTemperaturaSegura();
float leerHumedadSegura();
float leerPresionSegura();
String obtenerDireccionViento(int pin);
int obtenerGradosViento(int pin);
String obtenerFechaHora();
void enviarWeatherUnderground(float tempC, float hum, float presHpa, float vientoKmh, int vientoDirDeg, float lluviaMm);
// ==========================================
// SETUP
// ==========================================
void setup() {
Serial.begin(115200);
Wire.begin();
analogReadResolution(10);
pinMode(PIN_VELETA, INPUT);
pinMode(PIN_PLUVIOMETRO, INPUT);
pinMode(PIN_ANEMOMETRO, INPUT_PULLUP);
bool bmeOk = bme.begin(0x77);
conectarWiFi();
serverTelnet.begin();
configurarOTA();
configTime(GMT_OFFSET_SEC, DST_OFFSET_SEC, "pool.ntp.org", "time.nist.gov");
String miIP = WiFi.localIP().toString();
if (!bmeOk) {
enviarTelegram("⚠️ BME280 no detectado. IP: " + miIP, CHAT_ID_ALERTAS);
} else {
enviarTelegram("🚀 Estación online. IP: " + miIP, CHAT_ID_ALERTAS);
}
SinricPro.begin(SINRIC_APP_KEY, SINRIC_APP_SECRET);
attachInterrupt(digitalPinToInterrupt(PIN_PLUVIOMETRO), registroLluvia, RISING);
attachInterrupt(digitalPinToInterrupt(PIN_ANEMOMETRO), registroViento, FALLING);
tiempoAnteriorEnvio = millis();
}
// ==========================================
// LOOP
// ==========================================
void loop() {
ArduinoOTA.handle();
manejarConsola();
SinricPro.handle();
chequearWiFi();
unsigned long ahora = millis();
if (ahora - ultimaVezTelegram >= INTERVALO_TELEGRAM_MS) {
revisarComandosTelegram();
ultimaVezTelegram = ahora;
}
// AVISO INMEDIATO DE LLUVIA POR TELEGRAM
if (banderaLluvia) {
banderaLluvia = false;
if (ahora - ultimoAvisoTelegramLluvia > COOLDOWN_ALERTA_LLUVIA || ultimoAvisoTelegramLluvia == 0) {
enviarTelegram("🌧️ ¡Atención! Se detectó lluvia en la estación.", CHAT_ID_ALERTAS);
ultimoAvisoTelegramLluvia = ahora;
}
}
// ENVÍO PERIÓDICO (Web ASPX, Sinric, WU)
if (ahora - tiempoAnteriorEnvio >= INTERVALO_ENVIO_MS) {
tiempoAnteriorEnvio = ahora;
if (WiFi.status() != WL_CONNECTED) return;
float t = leerTemperaturaSegura();
float h = leerHumedadSegura();
float p = leerPresionSegura();
String dirStr = obtenerDireccionViento(PIN_VELETA);
int dirDeg = obtenerGradosViento(PIN_VELETA);
if (isnan(t)) return;
noInterrupts();
unsigned int vClicksPeriodo = clicksViento;
unsigned long lluviaPeriodo = clicksLluviaPeriodo;
unsigned long lluviaTotal = totalClicksLluvia;
clicksViento = 0;
clicksLluviaPeriodo = 0;
interrupts();
float duracionSegundos = INTERVALO_ENVIO_MS / 1000.0f;
float vKmh = ((float)vClicksPeriodo / duracionSegundos) * FACTOR_VIENTO_KMH;
float lluviaMm = (float)lluviaPeriodo * LLUVIA_POR_CLICK;
SinricProTemperaturesensor &sensorGoogle = SinricPro[SINRIC_DEVICE_ID];
sensorGoogle.sendTemperatureEvent(t, h);
JsonDocument doc;
doc["temp"] = serialized(String(t, 1));
doc["hum"] = serialized(String(h, 1));
doc["pres"] = serialized(String(p, 1));
doc["dir"] = dirStr;
doc["vel"] = serialized(String(vKmh, 1));
doc["lluvia_c"] = lluviaTotal;
doc["lluvia_p"] = lluviaPeriodo;
doc["fecha_rpi"] = obtenerFechaHora();
String jsonString;
serializeJson(doc, jsonString);
logConsola("[TX ASPX] " + jsonString);
WiFiClientSecure clientSecure;
clientSecure.setInsecure();
HTTPClient http;
http.begin(clientSecure, SERVER_URL);
http.addHeader("Content-Type", "application/json");
http.POST(jsonString);
http.end();
enviarWeatherUnderground(t, h, p, vKmh, dirDeg, lluviaMm);
}
}
// ==========================================
// WEATHER UNDERGROUND
// ==========================================
void enviarWeatherUnderground(float tempC, float hum, float presHpa, float vientoKmh, int vientoDirDeg, float lluviaMm) {
WiFiClient client;
HTTPClient http;
float tempF = (tempC * 9.0 / 5.0) + 32.0;
float presIn = presHpa * 0.02953;
float vientoMph = vientoKmh * 0.621371;
float lluviaIn = lluviaMm * 0.0393701;
String url = "http://rtupdate.wunderground.com/weatherstation/updateweatherstation.php?";
url += "ID=" + String(WU_ID);
url += "&PASSWORD=" + String(WU_KEY);
url += "&dateutc=now";
url += "&tempf=" + String(tempF, 2);
url += "&humidity=" + String(hum, 0);
url += "&baromin=" + String(presIn, 2);
url += "&windspeedmph=" + String(vientoMph, 2);
url += "&winddir=" + String(vientoDirDeg);
url += "&rainin=" + String(lluviaIn, 3);
url += "&action=updateraw";
logConsola("[TX WU] Enviando datos...");
http.begin(client, url);
int httpCode = http.GET();
if (httpCode > 0) {
logConsola("[TX WU] Respuesta: " + String(httpCode));
} else {
logConsola("[TX WU] Error: " + http.errorToString(httpCode));
}
http.end();
}
// ==========================================
// INTERRUPCIONES
// ==========================================
void IRAM_ATTR registroLluvia() {
// FILTRO POR SOFTWARE: Espera 1ms para matar el ruido electromagnético
delayMicroseconds(1000);
if (digitalRead(PIN_PLUVIOMETRO) == HIGH) {
unsigned long ahora = millis();
if (ahora - ultimoClickLluvia > DEBOUNCE_LLUVIA_MS) {
totalClicksLluvia++;
clicksLluviaPeriodo++;
ultimoClickLluvia = ahora;
banderaLluvia = true;
}
}
}
void IRAM_ATTR registroViento() {
unsigned long ahora = millis();
if (ahora - ultimoClickViento > DEBOUNCE_VIENTO_MS) {
clicksViento++;
ultimoClickViento = ahora;
}
}
// ==========================================
// FUNCIONES AUXILIARES
// ==========================================
void reiniciarSistema(const String& motivo) {
enviarTelegram("🔄 Reiniciando: " + motivo, CHAT_ID_ALERTAS);
delay(500);
ESP.restart();
}
void conectarWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long inicio = millis();
while (WiFi.status() != WL_CONNECTED && millis() - inicio < TIMEOUT_WIFI_MS) { delay(500); }
}
void chequearWiFi() {
if (WiFi.status() != WL_CONNECTED && (millis() - tiempoReconexionWiFi >= TIMEOUT_WIFI_MS)) {
WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
tiempoReconexionWiFi = millis();
}
}
void configurarOTA() {
ArduinoOTA.setHostname("Estacion_Peyrano");
ArduinoOTA.setPassword(OTA_PASSWORD);
ArduinoOTA.begin();
}
void logConsola(const String& mensaje) {
String linea = "[" + obtenerFechaHora() + "] " + mensaje;
Serial.println(linea);
if (clienteTelnet && clienteTelnet.connected()) clienteTelnet.println(linea);
}
void manejarConsola() {
if (serverTelnet.hasClient()) {
if (!clienteTelnet || !clienteTelnet.connected()) clienteTelnet = serverTelnet.available();
else serverTelnet.available().stop();
}
}
void enviarTelegram(String mensaje, String targetChatId) {
if (WiFi.status() != WL_CONNECTED) return;
mensaje.replace(" ", "%20");
WiFiClientSecure client; client.setInsecure();
HTTPClient http;
String url = "https://api.telegram.org/bot" + String(BOT_TOKEN) + "/sendMessage?chat_id=" + targetChatId + "&text=" + mensaje;
http.begin(client, url);
http.GET();
http.end();
}
void revisarComandosTelegram() {
if (WiFi.status() != WL_CONNECTED) return;
WiFiClientSecure client; client.setInsecure();
HTTPClient http;
String url = "https://api.telegram.org/bot" + String(BOT_TOKEN) + "/getUpdates?offset=" + String(ultimoUpdateId + 1) + "&limit=1";
http.begin(client, url);
if (http.GET() == HTTP_CODE_OK) {
JsonDocument doc;
deserializeJson(doc, http.getStream());
for (JsonObject update : doc["result"].as<JsonArray>()) {
ultimoUpdateId = update["update_id"];
String texto = update["message"]["text"] | "";
if (texto == "/reset") { http.end(); reiniciarSistema("Telegram"); return; }
}
}
http.end();
}
float leerTemperaturaSegura() { float t = bme.readTemperature(); return (isnan(t) || t < TEMP_MIN || t > TEMP_MAX) ? NAN : t; }
float leerHumedadSegura() { float h = bme.readHumidity(); return (isnan(h) || h < 0 || h > 100) ? NAN : h; }
float leerPresionSegura() { return bme.readPressure() / 100.0F; }
String obtenerDireccionViento(int pin) {
int v = analogRead(pin);
if (v < 90) return "E"; if (v < 180) return "SE"; if (v < 350) return "S";
if (v < 550) return "NE"; if (v < 700) return "SW"; if (v < 830) return "N";
if (v < 940) return "NW"; return "W";
}
int obtenerGradosViento(int pin) {
int v = analogRead(pin);
if (v < 90) return 90; if (v < 180) return 135; if (v < 350) return 180;
if (v < 550) return 45; if (v < 700) return 225; if (v < 830) return 0;
if (v < 940) return 315; return 270;
}
String obtenerFechaHora() {
struct tm ti;
if (!getLocalTime(&ti)) return "1970-01-01 00:00:00";
char b[25];
strftime(b, sizeof(b), "%Y-%m-%d %H:%M:%S", &ti);
return String(b);
}
que puedo hacer?

















