DÍA 215 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

Los Niveles de Confianza: QoS en MQTT

En el protocolo MQTT, puedes decidir qué tan importante es el mensaje que estás a punto de enviar. Esto se configura con un solo número (0, 1 o 2) llamado **Calidad de Servicio (Quality of Service)**.

El Impacto de QoS 1 en el ESP32

Cuando utilizas la instrucción AT+MQTTPUB=0,"tema","datos",1,0 en tu ESP32 (Observa el `1` indicando QoS 1), el firmware interno del módem se encarga de la burocracia por ti. El módem no te devolverá la palabra OK por el puerto UART hasta que el propio módem haya recibido el sagrado `PUBACK` desde los servidores de Amazon. Si falla, el ESP32 responderá ERROR. ¡Esto facilita increíblemente nuestra vida en el STM32!

CALIDAD DE SERVICIO (QoS): DISPARA Y OLVIDA VS GARANTÍA ABSOLUTA QoS 0: At Most Once (Para Heartbeats y Métricas) Máquina AWS Broker PUBLISH (Salud HW) ESP32: "OK" local Interferencia RF ESP32: "OK" local DATO PERDIDO PARA SIEMPRE La máquina cree que se envió. QoS 1: At Least Once (Para Transacciones Financieras) Máquina AWS Broker PUBLISH (Venta $500) Esperando PUBACK... RE-PUBLISH Automático PUBACK (Recibido!) ESP32: "OK" Borrando EEPROM GARANTÍA ABSOLUTA DE ENTREGA

⚙️ Ejercicios Prácticos

Circuito: Físicamente seguimos operando sobre el módulo ESP32. La diferencia radicará en cómo nuestra Máquina de Estados del STM32 (Día 210) interpreta las respuestas del UART al enviar transacciones monetarias versus datos de mantenimiento.

Ejercicio 1: Modificaremos nuestra librería mqtt_topics.c para soportar el envío paramétrico de QoS. Luego, actualizaremos el método Sincronizar_Venta_Nube para que utilice QoS 1 y condicione el borrado del ticket en EEPROM a la validación estricta de este protocolo.


/**
 * @file mqtt_qos_manager.c
 * @brief Gestión estricta de Calidad de Servicio (QoS) en transacciones financieras MQTT
 */

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

// =======================================================
// CONSTRUCTOR AVANZADO DE COMANDO MQTTPUB
// =======================================================
/**
 * @brief Ensambla el comando AT permitiendo seleccionar el nivel de QoS
 */
bool Construir_MQTTPUB_QoS(const char* sub_topic, const char* json_payload, int qos_level, char* buffer_salida, size_t tam_maximo) {
    
    // Tópico duro: gas_corp/jalisco/guadalajara/disp_01
    char topic_abs[128];
    snprintf(topic_abs, sizeof(topic_abs), "%s/%s/%s/%s/%s", 
             MQTT_ROOT_COMPANY, MQTT_REGION, MQTT_CITY, DEVICE_ID, sub_topic);

    // Inyectamos el nivel de QoS solicitado (0 o 1)
    int len_at = snprintf(buffer_salida, tam_maximo,
                          "AT+MQTTPUB=0,\"%s\",\"%s\",%d,0\r\n",
                          topic_abs, json_payload, qos_level);
                          
    if (len_at < 0 || (size_t)len_at >= tam_maximo) return false;
    return true;
}

// =======================================================
// EL TRANSMISOR CON PROTECCIÓN FINANCIERA (Store & Forward)
// =======================================================
bool Sincronizar_Venta_Nube_Segura(Ticket_Fisico_t* ticket) {
    
    char buffer_json[128];
    char comando_mqtt[256];
    
    // 1. Generamos el Payload JSON
    if (!Generar_Payload_JSON(ticket, buffer_json, sizeof(buffer_json))) return false;
    
    // 2. CRÍTICO: Solicitamos QoS 1 (Garantía de entrega)
    if (!Construir_MQTTPUB_QoS("telemetria/ventas", buffer_json, 1, comando_mqtt, sizeof(comando_mqtt))) {
        return false;
    }
    
    UART_Enviar_String("[QoS 1] Publicando venta... Esperando acuse de AWS (PUBACK).\r\n");
    
    // 3. Envío y Espera (Bloqueo lógico)
    // El módem ESP32 tardará más de lo habitual porque la radio frecuencia 
    // debe viajar a la nube, la nube verificar el JSON, y enviar la respuesta.
    // Damos 5000 ms de Timeout para no declarar un falso error de red.
    bool resultado_qos1 = AT_Enviar_Comando_Asincrono(comando_mqtt, 5000);
    
    if (resultado_qos1 == true) {
        // La bandera UART_OK se disparó. 
        // Esto significa matemáticamente que AWS recibió el paquete.
        UART_Enviar_String("[QoS 1] ¡PUBACK Recibido! Transacción Sellada.\r\n");
        return true; 
    } else {
        // Pudo haber sido Timeout o ERROR explícito. 
        // El ESP32 reintentó internamente varias veces y se rindió.
        UART_Enviar_String("[QoS 1] FALLO CRÍTICO. Protegiendo datos en EEPROM.\r\n");
        return false; 
    }
}

// =======================================================
// RECORDATORIO: EL LATIDO DE VIDA (QoS 0)
// =======================================================
/*
void Publicar_Latido_Vida(void) {
    char json_salud[64] = "{\"status\":1}";
    char cmd_mqtt[128];
    
    // Para el Latido, pedimos QoS 0 (Ahorramos ancho de banda y tiempo)
    Construir_MQTTPUB_QoS("estado/salud", json_salud, 0, cmd_mqtt, sizeof(cmd_mqtt));
    
    // El ESP32 regresará OK inmediatamente sin esperar a AWS
    AT_Enviar_Comando_Asincrono(cmd_mqtt, 1000);
}
*/
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Garantía de Idempotencia y Prevención de Robo Cibernético de Datos.

Imagina que la Tarea de Red de tu Despachador intenta subir una venta de $1000 pesos usando QoS 0. El mensaje sale al aire, pero hay ruido celular. El STM32, confiado, borra la venta de la EEPROM creyendo que ya se fue. Al finalizar el mes, al dueño de la gasolinera le faltan $1000 pesos en el portal web corporativo, pero el nivel del tanque físico dice que el gas sí salió. El dueño acusará a los empleados de robo físico, cuando en realidad fue "robo de datos" en tránsito.

Al elevar la exigencia de tus transmisiones financieras a **MQTT QoS 1**, le has prohibido a tu STM32 borrar cualquier registro de su disco duro físico (EEPROM) hasta obtener un recibo firmado por el servidor de Amazon (PUBACK). Si hay ruido celular, el ESP32 retransmitirá internamente el paquete hasta el cansancio. Aviso de Arquitectura: QoS 1 garantiza que el paquete llegue *al menos una vez*, lo que significa que a veces, AWS podría recibir el mismo ticket de venta dos veces. Para solucionar esto sin usar el lento QoS 2, tu corporativo simplemente programará la base de datos para ignorar tickets que tengan el mismo `folio_numero`. Has cerrado la brecha de pérdida de dinero a nivel de telecomunicaciones.

📝 Resumen del Día