estacion_meteorologica_y_bot_de_mastodon
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Próxima revisión | Revisión previa | ||
| estacion_meteorologica_y_bot_de_mastodon [2026/09/07 21:30] – creado hispa | estacion_meteorologica_y_bot_de_mastodon [2026/09/08 06:07] (actual) – hispa | ||
|---|---|---|---|
| Línea 1: | Línea 1: | ||
| + | ~~NOTOC~~ | ||
| + | <WRAP round box> | ||
| + | ====== Estación meteorológica y bot de Mastodon ====== | ||
| + | </ | ||
| + | <WRAP tabs> | ||
| + | * [[Estación meteorológica ESP8266 (D1 Mini), con captación de datos y elaboración de gráficos]] | ||
| + | * [[Informática y cacharreo]] | ||
| + | </ | ||
| + | <WRAP collarge> | ||
| + | ==== Descripción General del Sistema ==== | ||
| + | El programa lee los valores de temperatura, | ||
| + | </ | ||
| + | [{{ : | ||
| + | [{{ : | ||
| + | [{{ : | ||
| + | ==== Código ==== | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // --- CONFIGURACIÓN --- | ||
| + | const char* WIFI_SSID | ||
| + | const char* WIFI_PASSWORD = "[La clave de tu red Wifi]"; | ||
| + | const char* MASTODON_HOST = "[El nombre de la instancia, sin https://, por ejemplo mastodon.social]"; | ||
| + | const char* ACCESS_TOKEN | ||
| + | |||
| + | // --- CONFIGURACIÓN PINES --- | ||
| + | const int PIN_SDA = D2; | ||
| + | const int PIN_SCL = D1; | ||
| + | |||
| + | // --- CONFIGURACIÓN HORARIA (NTP) --- | ||
| + | const char* MY_TZ = " | ||
| + | const char* NTP_SERVER = " | ||
| + | |||
| + | // --- TIEMPO DE HIBERNACIÓN (DEEP SLEEP) --- | ||
| + | const uint64_t TIEMPO_HIBERNACION_US = 15ULL * 60ULL * 1000000ULL; // 15 minutos | ||
| + | |||
| + | Adafruit_BME280 bme; | ||
| + | |||
| + | // --- FUNCIONES AUXILIARES --- | ||
| + | |||
| + | bool conectarWiFi() { | ||
| + | WiFi.mode(WIFI_STA); | ||
| + | WiFi.begin(WIFI_SSID, | ||
| + | Serial.print(" | ||
| + | |||
| + | int intentos = 0; | ||
| + | while (WiFi.status() != WL_CONNECTED && intentos < 30) { | ||
| + | delay(500); | ||
| + | Serial.print(" | ||
| + | intentos++; | ||
| + | } | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) { | ||
| + | Serial.println(" | ||
| + | return true; | ||
| + | } | ||
| + | | ||
| + | Serial.println(" | ||
| + | return false; | ||
| + | } | ||
| + | |||
| + | void sincronizarNTP() { | ||
| + | configTime(MY_TZ, | ||
| + | Serial.print(" | ||
| + | |||
| + | time_t now = time(nullptr); | ||
| + | int intentos = 0; | ||
| + | while (now < 8 * 3600 * 2 && intentos < 30) { | ||
| + | delay(500); | ||
| + | Serial.print(" | ||
| + | now = time(nullptr); | ||
| + | intentos++; | ||
| + | } | ||
| + | Serial.println(" | ||
| + | } | ||
| + | |||
| + | bool leerBME280(float &temp, float &hum, float &pres) { | ||
| + | delay(100); | ||
| + | bme.readTemperature(); | ||
| + | delay(100); | ||
| + | |||
| + | temp = bme.readTemperature(); | ||
| + | hum = bme.readHumidity(); | ||
| + | pres = bme.readPressure() / 100.0F; | ||
| + | |||
| + | if (isnan(temp) || isnan(hum) || isnan(pres)) { | ||
| + | return false; | ||
| + | } | ||
| + | |||
| + | Serial.printf(" | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | String obtenerFechaHora() { | ||
| + | time_t now = time(nullptr); | ||
| + | struct tm timeinfo; | ||
| + | localtime_r(& | ||
| + | |||
| + | char buffer[40]; | ||
| + | strftime(buffer, | ||
| + | return String(buffer); | ||
| + | } | ||
| + | |||
| + | String urlEncode(String str) { | ||
| + | String encodedString = ""; | ||
| + | char c, code0, code1; | ||
| + | for (size_t i = 0; i < str.length(); | ||
| + | c = str.charAt(i); | ||
| + | if (isalnum(c) || c == ' | ||
| + | encodedString += c; | ||
| + | } else if (c == ' ') { | ||
| + | encodedString += " | ||
| + | } else { | ||
| + | code0 = (c >> 4) & 0xF; | ||
| + | code1 = c & 0xF; | ||
| + | encodedString += ' | ||
| + | encodedString += (char)(code0 < 10 ? code0 + ' | ||
| + | encodedString += (char)(code1 < 10 ? code1 + ' | ||
| + | } | ||
| + | } | ||
| + | return encodedString; | ||
| + | } | ||
| + | |||
| + | void publicarToot(String mensaje) { | ||
| + | WiFiClientSecure client; | ||
| + | client.setInsecure(); | ||
| + | |||
| + | HTTPClient http; | ||
| + | String url = " | ||
| + | |||
| + | if (http.begin(client, | ||
| + | http.addHeader(" | ||
| + | http.addHeader(" | ||
| + | http.addHeader(" | ||
| + | |||
| + | String postData = " | ||
| + | int httpCode = http.POST(postData); | ||
| + | |||
| + | if (httpCode > 0) { | ||
| + | Serial.printf(" | ||
| + | Serial.println(" | ||
| + | } else { | ||
| + | Serial.printf(" | ||
| + | } | ||
| + | http.end(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // --- FLUJO PRINCIPAL DE ARDUINO --- | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(9600); | ||
| + | delay(100); | ||
| + | |||
| + | if (conectarWiFi()) { | ||
| + | sincronizarNTP(); | ||
| + | |||
| + | Wire.begin(PIN_SDA, | ||
| + | delay(200); | ||
| + | |||
| + | float temp, hum, pres; | ||
| + | if (bme.begin(0x76, | ||
| + | String mensaje = "📊 *Estación Meteorológica*\n" | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | "# | ||
| + | |||
| + | Serial.println(" | ||
| + | publicarToot(mensaje); | ||
| + | } else { | ||
| + | Serial.println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Serial.println(" | ||
| + | ESP.deepSleep(TIEMPO_HIBERNACION_US); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | // Vacío por el uso de Deep Sleep | ||
| + | } | ||
| + | </ | ||
| + | <WRAP collarge> | ||
| + | ==== Librerías utilizadas ==== | ||
| + | |||
| + | * **< | ||
| + | * **< | ||
| + | * **< | ||
| + | * **< | ||
| + | * **< | ||
| + | * **< | ||
| + | * **< | ||
| + | |||
| + | ====Parámetros de Configuración Global==== | ||
| + | |||
| + | * **WIFI_SSID / WIFI_PASSWORD**: | ||
| + | * **MASTODON_HOST**: | ||
| + | * **ACCESS_TOKEN**: | ||
| + | * **PIN_SDA (D2) / PIN_SCL (D1)**: Pines GPIO asignados al bus I2C. | ||
| + | * **MY_TZ**: Cadena de zona horaria POSIX (CET-1CEST, | ||
| + | * **NTP_SERVER**: | ||
| + | * **TIEMPO_HIBERNACION_US**: | ||
| + | |||
| + | ==== Módulos y Funciones Auxiliares ==== | ||
| + | |||
| + | - **conectarWiFi()** | ||
| + | * Función: Configura el ESP8266 en modo cliente (WIFI_STA) e inicia la asociación a la red Wi-Fi. | ||
| + | * Elemento de lista desordenadaMecanismo de tiempo de espera (Timeout): Realiza hasta 30 intentos con retardos de 500 ms (máximo 15 segundos). Retorna true si la conexión es exitosa (WL_CONNECTED) o false en caso de fallo. | ||
| + | - **sincronizarNTP()** | ||
| + | * Función: Configura el cliente SNTP interno de la pila de código mediante configTime(). | ||
| + | * Mecanismo de validación: | ||
| + | - **leerBME280(float &temp, float &hum, float & | ||
| + | * Función: Realiza la adquisición de datos de los tres sensores físicos. | ||
| + | * Uso de punteros/ | ||
| + | * Filtrado y Conversión: | ||
| + | * Comprueba errores de hardware o lectura mediante la función isnan(). | ||
| + | - **obtenerFechaHora()** | ||
| + | * Función: Obtiene la marca de tiempo UTC actual, le aplica los desplazamientos de la zona horaria (MY_TZ) mediante localtime_r() y genera un String con formato DD/MM/YYYY - HH:MM:SS usando strftime(). | ||
| + | - **urlEncode(String str)** | ||
| + | * Función: Codifica caracteres especiales para cumplir con el estándar application/ | ||
| + | - **publicarToot(String mensaje)** | ||
| + | * Función: Construye y ejecuta la petición HTTPS POST hacia el endpoint / | ||
| + | * Seguridad SSL: Utiliza client.setInsecure() para omitir la validación rigurosa de la cadena del certificado X.509 de la CA (ahorra memoria RAM en la placa). | ||
| + | * Cabeceras HTTP: | ||
| + | * User-Agent: Identificador de la aplicación cliente. | ||
| + | * Content-Type: | ||
| + | * Authorization: | ||
| + | |||
| + | ==== Flujo de Ejecución Principal ==== | ||
| + | |||
| + | Debido al uso de Deep Sleep, el flujo completo del programa se ejecuta exclusivamente dentro de la función setup(). La función loop() permanece vacía puesto que el procesador se reinicia completamente tras cada despertar. | ||
| + | {{ : | ||
| + | </ | ||
| + | {{tag> informática_y_cacharreo electrónica ESP8266 D1_Mini C++}} | ||
