DÍA 213 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

Ping de Red vs. Latido de Aplicación

No debes confundir las herramientas de red con la lógica de negocio.

Arquitectura del Evento Periódico en RTOS

Para publicar el Latido de Vida, NO vamos a crear un "Timer Bloqueante" que congele la máquina. Utilizaremos el osKernelGetTickCount() dentro de nuestro Bucle de Store & Forward (Día 210). Esto permite que el STM32 envíe ventas almacenadas, y si no hay ventas urgentes, aproveche el silencio para enviar su paquete de salud, por ejemplo, cada 5 minutos.

ARQUITECTURA DEL LATIDO DE VIDA (APPLICATION HEARTBEAT) Task_WiFi (STM32) osThreadGetStackSpace() osKernelGetTickCount() Hardware_Status (I2C/SPI) Generar JSON (snprintf) {"status":"OK", "ram":1024, "up_h":42} Disparo Lógico cada 300 Seg. AT+MQTTPUB Topic: .../estado/salud ESP32 MQTT PUSH (QoS 0) AWS IoT Panel DISP_01: ONLINE Último Latido: Hace 12 Segundos Salud HW: OK (RAM: 1024b) DISP_02: OFFLINE

⚙️ Ejercicios Prácticos

Circuito: Utilizaremos la misma infraestructura de red. Sin embargo, extraeremos los valores de uso de memoria (Stack High Water Mark) que programamos el Día 197 para inyectarlos en nuestro paquete. Así, el servidor AWS será alertado meses antes de que nuestra máquina sufra un desbordamiento de memoria real.

Ejercicio 1: Programaremos la función Publicar_Latido_Vida() y la insertaremos de manera no bloqueante dentro del estado ESTADO_IDLE_READY de nuestra máquina de estados IoT.


/**
 * @file mqtt_heartbeat.c
 * @brief Rutina de Latido de Vida (Application Heartbeat) en FreeRTOS
 */

#include "stm32f401xe.h"
#include "cmsis_os2.h"
#include <stdio.h>
#include <string.h>

// Utilidades previas
extern bool AT_Enviar_Comando(const char* comando, uint32_t timeout_ms);
extern bool Construir_Comando_MQTT_Publicar(const char* sub_topic, const char* json_payload, char* buffer_salida, size_t tam_maximo);

// Variables globales del sistema
extern osThreadId_t hilo_metro_id; // Para revisar su memoria (Día 197)

// =======================================================
// CONSTRUCTOR Y PUBLICADOR DEL HEARTBEAT
// =======================================================
void Publicar_Latido_Vida(void) {
    
    char buffer_json[128];
    char buffer_comando_at[256];
    
    // 1. Recolección de Métricas de Salud del Hardware
    uint32_t ram_libre_metro = osThreadGetStackSpace(hilo_metro_id);
    uint32_t uptime_segundos = osKernelGetTickCount() / 1000;
    
    // Asumiremos que una variable global verifica si la válvula está en corto circuito
    // extern bool sensor_valvula_ok;
    int estado_hw = 1; // 1 = OK, 0 = FALLA
    
    // 2. Construcción segura del JSON (Día 207)
    int len_json = snprintf(buffer_json, sizeof(buffer_json),
                            "{\"status\":%d,\"ram_met\":%lu,\"uptime_s\":%lu}",
                            estado_hw, ram_libre_metro, uptime_segundos);
                            
    // Verificación MISRA-C de seguridad de buffer
    if (len_json < 0 || (size_t)len_json >= sizeof(buffer_json)) {
        return; // JSON truncado, abortamos el latido
    }
    
    // 3. Ensamblar el Comando MQTT (Día 212)
    // Tópico final resultante: "gas_corp/mexico/guadalajara/disp_01/estado/salud"
    if (Construir_Comando_MQTT_Publicar("estado/salud", buffer_json, buffer_comando_at, sizeof(buffer_comando_at))) {
        
        // 4. Inyección al ESP32
        // Nota: A diferencia de una Venta de Gas (QoS 1), un Heartbeat puede ser QoS 0 
        // (Dispara y olvida), porque si se pierde en la red, no hay un impacto financiero. 
        // El servidor simplemente recibirá el siguiente latido en unos minutos.
        UART_Enviar_String("[HEARTBEAT] Enviando constantes vitales a AWS...\r\n");
        AT_Enviar_Comando(buffer_comando_at, 2000); 
    }
}

// =======================================================
// INTEGRACIÓN EN LA FSM PRINCIPAL
// =======================================================
/*
void Thread_WiFi_Modem(void *argument) {
    
    uint32_t ultimo_latido_tick = 0;
    const uint32_t INTERVALO_LATIDO_MS = 300000; // 5 minutos (300,000 ms)
    
    for (;;) {
        switch (estado_actual) {
            
            // ... (Fases de Conexión, TCP, etc.) ...
            
            case ESTADO_IDLE_READY:
                
                // 1. Prioridad: Vaciado de ventas atrasadas (Store & Forward - Día 210)
                if (Hay_Ventas_Pendientes()) {
                    Sincronizar_Venta_Nube();
                } 
                else {
                    // 2. Tiempo Ocioso: Verificar si es momento de latir
                    if ((osKernelGetTickCount() - ultimo_latido_tick) >= INTERVALO_LATIDO_MS) {
                        Publicar_Latido_Vida();
                        ultimo_latido_tick = osKernelGetTickCount();
                    }
                }
                
                osDelay(100); // Ritmo de la tarea (Yield de CPU)
                break;
        }
    }
}
*/
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Mantenimiento Predictivo y Gestión de Flota (Fleet Management).

A nivel empresarial, saber que un Despachador falló porque un cliente te llama enojado quejándose de que no sale gas, es un modelo reactivo inaceptable y costoso. El corporativo exige proactividad.

Al dotar a tu firmware de una **Rutina de Application Heartbeat** enviada por MQTT cada 5 minutos, has transformado una "máquina estúpida" en un nodo autogestionado. El servidor en AWS IoT Core mantiene un Device Shadow (una sombra digital) de tu máquina. Si el reloj de AWS marca que han pasado 15 minutos sin recibir un Heartbeat del Despachador N°405 de Guadalajara, AWS cambia automáticamente el ícono de esa máquina a color ROJO en el panel web y envía un mensaje de Telegram al técnico de la zona indicando: "Posible caída de energía eléctrica o destrucción del equipo". Más aún, si la máquina está viva pero la gráfica de RAM enviada en el JSON muestra una tendencia a la baja (Memory Leak silencioso), puedes enviar una orden de "Reinicio Remoto" a las 2:00 AM antes de que la máquina sufra un HardFault crítico en hora pico. Esto es la esencia pura de la Industria 4.0.

📝 Resumen del Día