DÍA 331 DE 365

Fase 5: Diseño Industrial y Hardware

📖 Teoría a Estudiar

Del SCADA Tradicional al SCADA IoT

Un sistema SCADA (Supervisory Control and Data Acquisition) tradicional en una planta gasera utiliza cables seriales (RS-485) o Ethernet local para conectar todas las máquinas a un servidor físico en la oficina del gerente usando el protocolo Modbus. Si el servidor se apaga, la planta se queda ciega.

Tu Despachador de Gas utiliza un SCADA IoT Cloud-Native. Al usar el ESP32 como puente Wi-Fi (Día 313), cada máquina se conecta directamente a internet, cifrando sus datos con TLS 1.2, y enviándolos a un Broker MQTT global (como AWS IoT Core). Esto significa que puedes monitorear una gasera en Guadalajara y otra en Monterrey desde un mismo panel en tu celular, sin instalar servidores físicos (On-Premise) en ninguna de ellas.

Device Shadows y Jerarquía de Tópicos MQTT

¿Qué pasa si cambias el precio del gas en el servidor, pero una de las máquinas perdió su conexión Wi-Fi en ese momento? En HTTP, el comando se pierde. En MQTT IoT, usamos Device Shadows (Sombras de Dispositivo). El servidor guarda el nuevo precio en la "Sombra" virtual de la máquina en la nube. Cuando la máquina física recupera el Wi-Fi, sincroniza su estado automáticamente con su sombra.

ARQUITECTURA CLOUD SCADA IoT: DE LA VÁLVULA AL DASHBOARD EDGE (ESTACIÓN GASERA) DISPENSADOR_001 STM32 ESP32 (TLS) DISPENSADOR_0NN Flota escalable... Autenticación por X.509 (mTLS) en cada ESP32 (Hardware Crypto) NUBE (AWS IoT CORE) MQTT BROKER PUB: /ventas SUB: /comandos Motor de Reglas (SQL) Device Shadows (Caché de Estado / Precios) BUSINESS LOGIC (SaaS) Time-Series DB (Timestream / InfluxDB) Ingesta API (Node.js/Python) Admin Dashboard (React / Grafana) Métricas Financieras

⚙️ Procedimiento Práctico: Configuración del SCADA

Paso 1: Jerarquía Lógica (Tópicos MQTT).
En el mundo IoT, no usas direcciones IP; usas canales de suscripción (Tópicos). Debes diseñar una estructura jerárquica y escalable.
- Para recibir un corte de emergencia global: mobagas/mexico/gd/ALL/comandos
- Para recibir un ticket de venta específico: mobagas/mexico/gdl/estacion_sur/disp_001/ventas

Paso 2: Criptografía Extremo a Extremo (mTLS).
Un atacante no necesita manipular tu hardware si puede falsificar los mensajes Wi-Fi simulando ser tu máquina. Al compilar el firmware del ESP32, "quemaremos" en su memoria segura un Certificado X.509 y una Llave Privada otorgados por AWS. Esto garantiza Autenticación Mutua: El servidor sabe que la máquina es legítima, y la máquina sabe que no le está hablando a un servidor pirata.

💻 Cloud Backend: Regla de Ingesta Serverless (Python)

En el antiguo SCADA, tendrías una PC encendida 24/7 en un rack corriendo un software en C# esperando mensajes. En Cloud-Native, configuramos una "Regla IoT" en AWS que dispara una función Serverless (Lambda) escrita en Python únicamente en el milisegundo en que llega una venta de gas. Si no hay ventas a las 3:00 AM, el costo de servidor es $0.00.


# =========================================================================
# scada_ingestion_lambda.py (AWS Lambda Backend)
# Recibe el payload JSON de la venta de gas despachado por el ESP32, 
# audita los datos y los inyecta en la Base de Datos Financiera.
# =========================================================================

import json
import boto3
import time
import logging

# Conexión a Base de Datos NoSQL (Ej. DynamoDB) para alto volumen
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Mobagas_Financial_Transactions')

def lambda_handler(event, context):
    """
    Función gatillada automáticamente por AWS IoT Core cuando un Despachador 
    publica un mensaje en el tópico: mobagas/+/+/+/ventas
    """
    try:
        # El 'event' contiene el JSON validado enviado por el ESP32
        device_id = event.get('device_id')
        station_id = event.get('station_id')
        liters_dispensed = float(event.get('vol_liters'))
        total_cents = int(event.get('total_cents'))
        transaction_crc = event.get('tx_crc')
        
        logging.info(f"[INCOMING] Venta de Máquina {device_id} en {station_id}.")
        
        # 1. AUDITORÍA MATEMÁTICA EN NUBE (Doble Verificación)
        # Verificamos si el equipo en campo calculó bien el precio, para detectar 
        # si alguien modificó el hardware localmente.
        expected_price_cents = fetch_current_price_from_cache(station_id)
        calculated_total = int(liters_dispensed * expected_price_cents)
        
        # Margen de tolerancia de 1 centavo por redondeos de Punto Fijo en el STM32
        if abs(calculated_total - total_cents) > 1:
            logging.error(f"[FRAUD ALERT] Discrepancia matemática en {device_id}!")
            trigger_scada_lockdown_command(device_id)
            return {"status": "error", "message": "Incoherencia financiera."}
            
        # 2. ALMACENAMIENTO PERMANENTE
        timestamp = int(time.time())
        response = table.put_item(
            Item={
                'TransactionID': f"{device_id}_{timestamp}",
                'DeviceID': device_id,
                'StationID': station_id,
                'Liters': str(liters_dispensed),
                'AmountCharged_MXN': str(total_cents / 100.0),
                'TimestampEpoch': timestamp
            }
        )
        
        logging.info("[SUCCESS] Venta registrada en Ledger Central.")
        return {"status": "success"}

    except Exception as e:
        logging.error(f"Error procesando telemetría: {str(e)}")
        return {"status": "error"}

def trigger_scada_lockdown_command(device_id):
    """
    Publica un comando MQTT en reversa para bloquear la válvula de la máquina infractora.
    """
    iot_client = boto3.client('iot-data')
    topic = f"mobagas/comandos/{device_id}/lockdown"
    payload = json.dumps({"cmd": "LOCKDOWN", "reason": "CLOUD_AUDIT_FAIL"})
    
    iot_client.publish(
        topic=topic,
        qos=1, # QoS 1 garantiza que el comando llegue aunque la máquina tenga mal Wi-Fi
        payload=payload
    )
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Integración de Sistemas a Nivel Empresarial (SaaS / SCADA).

El diseño electrónico es fascinante, pero las empresas no compran microcontroladores; compran soluciones y flujos de efectivo. Si construyes el mejor Despachador de Gas del mundo pero el contador de la gasera tiene que caminar a cada máquina con una libreta al final del turno para anotar cuántos litros se vendieron, tu tecnología nació obsoleta.

Al diseñar la **Arquitectura SCADA IoT**, cruzaste el abismo entre la electrónica de potencia y la Ingeniería de Software Empresarial. Utilizando el ESP32 (Dominio de Red) que configuramos en el Día 313, tu máquina ahora posee un túnel cifrado y bidireccional (MQTT) directamente hacia la Nube (AWS IoT). El script Python de hoy demuestra el verdadero poder de esta topología: la Nube audita matemáticamente las operaciones del hardware en tiempo real. Si la máquina cobra $500 pero el servidor sabe que por esa cantidad de litros debió cobrar $501, la Nube envía un comando de "Lockdown" invertido que paraliza los actuadores físicos de la gasera en milisegundos. Has creado un ecosistema cibernético donde el dinero, los datos y el gas fluyen bajo control absoluto y centralizado.

📝 Resumen del Día