← Índice del curso

Internet de las Cosas · Tema 47

Diseño de un dispositivo IoT completo

Ya sabemos medir, comunicar, controlar, proteger y actualizar una placa. Ahora vamos a unir esas capacidades en un diseño coherente: uno que conserve su función cuando se cae la red, tenga recursos para mantenerse y permita demostrar con pruebas qué requisitos cumple.

01 · Integrar decisiones

De las funciones al sistema

Un dispositivo IoT completo es un conjunto de decisiones relacionadas. Una mayor frecuencia de muestreo mejora la observación, pero también genera más registros. El sueño profundo reduce consumo, pero cambia la recepción de órdenes. TLS necesita memoria y tiempo; OTA necesita espacio, energía y una recuperación prevista.

La arquitectura establece qué componente hace cada trabajo, qué información intercambia y qué ocurre cuando falla. No exige comenzar con una plataforma grande: una placa y un servicio pequeño también necesitan límites claros.

Relación entre las capacidades del curso.
CapacidadDecisión al integrarla
Adquisición y control localCadencia, calidad de lectura, histéresis y salida ante una falla
HTTP o MQTTPlazos, autorización, confirmación y política de reconexión
Almacenamiento y telemetríaCuánto conservar, cuándo transmitir y qué descartar
Seguridad y aprovisionamientoIdentidad, credenciales, permisos y recuperación de acceso
OTA y gestión de flotasCompatibilidad, aceptación, reversión y evidencia operativa
Bajo consumoVentanas de actividad y autonomía compatibles con el servicio

Trabajaremos con un controlador de temperatura de banco y una variante de monitor a batería. El tema 48 llevará esas decisiones a un proyecto integrador. Aquí nos interesa entender por qué una combinación de componentes puede funcionar o entrar en contradicción.

02 · Especificar el comportamiento esperado

Requisitos que se pueden comprobar

«Debe ser rápido, seguro y consumir poco» no alcanza para elegir una placa ni escribir una prueba. Se necesita describir escenario, condición, límite y evidencia de aceptación.

El caso principal es un controlador de temperatura de banco alimentado de forma continua. Un sensor entrega lecturas y una salida representa un ventilador; durante el aprendizaje puede usarse un LED de baja tensión. El control local permanece atendido aunque la red deje de estar disponible.

Contrato didáctico del controlador; los límites no son normas universales.
IDRequisitoEvidencia de aceptación
R1Muestrear cada 1 s y decidir localmente en hasta 2 s desde un cambio observableEnsayo de entrada y medida del tiempo hasta la decisión
R2Seguir el control local durante una caída de redDesconectar red y verificar lectura, decisión y salida
R3Atender configuración remota en hasta 15 s bajo la red nominal definidaMedida de extremo a extremo con confirmación del equipo
R4Conservar al menos 6 minutos de muestras sin conexiónInterrumpir entrega y recuperar la historia sin pérdidas dentro del presupuesto
R5Identificar cada unidad y limitar sus permisosIntentar acceder a recursos propios, ajenos y con credenciales revocadas
R6Actualizar solo firmware autorizado y recuperar un arranque fallidoPrueba de rechazo de imagen y recorrido de aceptación o reversión

Definir el alcance de los tiempos

El modelo reservará 0,1 s para procesamiento local y 2 s para una comunicación nominal. Son supuestos de planificación. La conversión del sensor, las colas del sistema y las demoras del servicio deben estar incluidas en mediciones reales antes de sostener una garantía.

Una orden almacenada en la plataforma no garantiza atención mientras no hay red. La especificación distingue respuesta bajo conectividad nominal, comportamiento durante una interrupción y recuperación posterior.

La variante a batería cambia el contrato

El monitor a batería mide cada 60 s, abre una ventana de comunicación cada 600 s y admite hasta 900 s para atención remota bajo condiciones nominales. No gobierna una salida continua. Puede usar sueño profundo entre tareas y conserva 24 horas de muestras. Es otro perfil de servicio, aunque comparta placa y parte del firmware.

03 · Ubicar responsabilidades y límites

Arquitectura y responsabilidades

DISPOSITIVO                              PLATAFORMA
┌──────────────────────────────┐          ┌─────────────────────────┐
│ Sensor → validación          │          │ Ingesta autenticada     │
│              ↓               │ estados  │          ↓              │
│ Política local → salida      │ ───────→ │ Historia y estado actual│
│              ↓               │          │          ↓              │
│ Cola acotada → comunicación  │          │ Panel y alertas         │
│              ↑               │ comandos │          ↓              │
│ Validación y configuración   │ ←─────── │ API con autorización    │
│                              │          │                         │
│ Identidad · diagnóstico · OTA│ ←──────→ │ Inventario y campañas   │
└──────────────────────────────┘          └─────────────────────────┘
          ↑ alimentación, reloj y hardware de recuperación

El camino sensor → decisión → salida pertenece al dispositivo. La plataforma almacena historia, organiza la flota y propone cambios autorizados. Una conexión lenta puede retrasar telemetría; no debe bloquear el trabajo local comprometido.

Cada frontera necesita un contrato y una conducta ante falla.
FronteraContratoAnte una falla
Sensor → aplicaciónValor, unidad, calidad y antigüedadNo sustituir una lectura inválida por cero
Aplicación → salidaEstado solicitado y condiciones permitidasAplicar la política física definida
Cola → servidorIdentidad de registro y confirmaciónReintentar sin multiplicar efectos ni crecer sin límite
Servidor → configuraciónVersión, permisos, rangos y vigenciaRechazar y conservar una configuración válida
Servicio OTA → arranqueImagen autorizada, compatible y aceptableConservar recuperación bajo la política elegida

Un responsable por estado

El módulo de control es el único que decide la salida lógica. El receptor de comandos entrega una solicitud validada; no escribe directamente el GPIO desde un callback de red. Así se evita que el control automático, una orden remota y una tarea OTA compitan por la misma salida.

También se distingue la orden lógica del estado físico observado. Guardar salida=true demuestra una decisión de software; confirmar que el ventilador gira requiere una señal de realimentación apropiada.

04 · La arquitectura llega a los pines

Hardware y comportamiento físico

La elección del microcontrolador empieza por interfaces, memoria, alimentación, entorno y mantenimiento. La disponibilidad de Wi-Fi no resuelve por sí sola el número de pines, la corriente de una carga o el espacio de flash necesario para actualizar.

Revisión del hardware antes de programar el sistema completo.
BloqueDecisiones que documentar
SensorRango, precisión, tiempo de conversión, bus, errores y calibración
SalidaEtapa de manejo, corriente, protección de cargas y estado durante arranque
AlimentaciónConsumo continuo, ráfagas de radio, regulación y caída de tensión
ConectividadAntena, cobertura, ubicación y proceso de configuración
MemoriaRAM simultánea, particiones, datos persistentes y crecimiento de imagen
ServicioProgramación, recuperación, identificación física y acceso de diagnóstico

El estado de arranque también es una decisión

Antes de que el firmware configure una salida, el pin puede tener otro comportamiento. Se seleccionan pines y resistencias para que reset, bootloader y programación no activen accidentalmente una carga. El análisis incluye periféricos externos y pérdida parcial de alimentación.

Para el banco de esta lección se define salida desactivada ante lectura inválida o durante reinicio. Ese criterio pertenece al ejemplo: en un sistema térmico real apagar un ventilador podría agravar el problema. La condición segura se determina para la aplicación y puede necesitar circuitos independientes del software.

Alimentación continua frente a batería

El controlador prioriza atención local continua. El monitor a batería acepta mayores demoras y apaga subsistemas entre trabajos. El presupuesto energético del tema 46 debe realizarse para cada perfil y para las fallas de red; cambiar solamente el nombre del modo no demuestra autonomía.

05 · Mantener atendida la función local

Organización del firmware

Se puede implementar con un bucle cooperativo o con tareas de un sistema operativo. En ambos casos hacen falta prioridades, plazos, propietarios de datos y límites de memoria. Crear muchas tareas no elimina un bloqueo de red ni una condición de carrera.

Separación posible para el controlador de banco.
MóduloResponsabilidadLímite
AdquisiciónSolicitar muestra, validar y registrar calidadPlazo del sensor; lectura anterior no presentada como nueva
ControlHistéresis y salida según estado válidoNo esperar red ni escritura extensa
PersistenciaGuardar configuración y colaTamaño, frecuencia de escritura e integridad
ComunicacionesReconectar, intercambiar datos y confirmarTimeouts, lotes y reintentos acotados
MantenimientoDiagnóstico y actualizaciónPermiso local para interrumpir la función y recursos reservados
al iniciar:
    fijar salida de arranque
    validar configuración persistida o cargar valores admitidos
    preparar sensor, almacenamiento y comunicaciones

en cada iteración o activación planificada:
    atender adquisición sin espera indefinida
    evaluar control con lectura y configuración vigentes
    atender escritura y envío con presupuesto de trabajo
    procesar solicitudes validadas sin escribir directamente la salida
    registrar progreso y fallos de cada subsistema
    admitir mantenimiento solo bajo sus condiciones

Es pseudocódigo de responsabilidades, no un firmware listo para cargar. Una biblioteca síncrona puede ocupar todo el intervalo aunque esté dentro de una función llamada «atender». Se mide su peor duración o se aísla de forma que el control conserve sus plazos.

Configuración coherente

Los umbrales se validan como conjunto: por ejemplo, el umbral de encendido debe ser mayor que el de apagado. La aplicación recibe una versión completa y coherente; no observa la mitad de una escritura. Se distingue versión deseada, validada, aplicada y reportada.

Un watchdog detecta determinadas ausencias de progreso, pero un reinicio no corrige necesariamente una configuración inválida. Su alimentación debe depender del avance significativo de las tareas relevantes, y la recuperación debe dejar evidencia del motivo.

06 · Datos con significado estable

Contratos de datos y comandos

El protocolo transporta bytes. El contrato explica qué significan, quién puede producirlos y cómo se rechazan datos incorrectos. Conviene versionar esquema, unidades y reglas de compatibilidad.

{
  "schema": 1,
  "device_id": "banco-017",
  "boot_id": "sesion-opaca-ejemplo",
  "seq": 42,
  "uptime_ms": 42000,
  "temperature_c": 28.4,
  "quality": "valid",
  "output_requested": true,
  "config_applied": 7,
  "firmware_build": 12
}

El ejemplo describe un snapshot actual. El backend vincula la identidad de la conexión con el inventario y agrega su tiempo de recepción. El texto device_id dentro del JSON no autentica al emisor. Si el reloj del equipo no está sincronizado, no se inventa una fecha absoluta a partir de uptime_ms.

Tres intercambios distintos

El historial, la configuración y las acciones tienen reglas diferentes.
IntercambioNecesitaError que evitar
Historia de medicionesIdentidad estable, instante o contexto temporal y deduplicaciónConvertir un lote atrasado en presencia actual
Configuración deseadaVersión, rangos, permisos y reporte de aplicaciónMostrar «aplicada» solo porque se guardó en la nube
Acción puntualID de comando, vigencia, autorización y resultadoReejecutar una acción vieja al reconectar

Una confirmación de transporte y una confirmación de aplicación prueban etapas diferentes. Si el producto promete que una medición ya quedó durable en el servidor, define un acuse a ese nivel. Si promete una acción física, necesita el resultado que efectivamente pueda observar.

HTTP y MQTT dentro de la arquitectura

Ambos pueden servir para telemetría y configuración. Se eligen según patrón de intercambio, infraestructura y restricciones, manteniendo contratos independientes de la biblioteca de transporte. La elección no elimina duplicados, mensajes atrasados, reconexiones ni autorización por recurso.

07 · La desconexión es un escenario previsto

Operación sin conexión

El controlador continúa con la última configuración válida y su política local, mientras conserva muestras dentro de una cola acotada. La pérdida de red y la falla del sensor son estados independientes: puede haber una lectura válida sin conexión o un sensor inválido con transporte disponible.

Políticas de falla para el caso de banco.
SituaciónConducta localEvidencia
Red ausenteContinuar control, guardar y reconectar con límitesEdad de conexión, intentos y ocupación de cola
Sensor inválidoAplicar salida desactivada del ejemplo; no usar lectura vieja indefinidamenteCalidad y antigüedad de la última muestra válida
Cola llenaAplicar descarte definido sin impedir el controlContador de descartes y rango de historia perdida
Configuración inválidaRechazarla y mantener una válidaID, versión y motivo del rechazo
ReinicioSalida de arranque y recuperación validada de datosMotivo, build y nueva sesión

Dimensionar la cola

Para una interrupción de duración D y un intervalo de muestra Tm, se estima conservadoramente ceil(D/Tm) registros nuevos con fase arbitraria. El presupuesto del laboratorio supone cola vacía al comenzar, muestras periódicas y ausencia de envíos durante todo el corte.

N = ceil(duración del corte / intervalo de muestra)
espacio requerido = ceil(N × bytes por registro × margen)

En el controlador, 6 minutos equivalen a 360 muestras de 1 s. Con 96 bytes por registro y factor 1,2 se requieren 41 472 bytes = 40,5 KiB. El monitor de 24 horas y muestras de 60 s requiere 1440 registros: 165 888 bytes = 162 KiB. Un KiB representa 1024 bytes.

Los 96 bytes son una reserva de formato persistido por registro, no una afirmación sobre el tamaño del JSON mostrado. El margen del 20 % es un supuesto didáctico; índices, metadatos, alineación, recuperación y sistema de archivos deben medirse.

La recuperación también necesita capacidad

Al volver la red se siguen generando muestras. Para vaciar el atraso, la tasa de entrega confirmada debe superar la de producción durante suficiente tiempo. Se limita el envío por lote para que TLS, almacenamiento y telemetría no desplacen al control local. Una cola que estaba llena antes del corte requiere otro presupuesto.

08 · Reservar para lo que ocurre a la vez

Presupuestos de recursos

Los consumos de RAM se suman cuando coinciden. Tener memoria para TLS en una prueba y para OTA en otra no demuestra que ambas funciones puedan coexistir con el sensor, las pilas de tareas y la cola.

Reservas ficticias del laboratorio; no son requisitos de una biblioteca concreta.
Uso de RAMReservaSupuesto
Aplicación y sistema32 KiBIncluye pilas y estructuras previstas en el modelo
Comunicación protegida48 KiBSe reserva incluso si se desmarca TLS, porque el requisito sigue exigiéndolo
Adquisición4 KiBBuffers del sensor y procesamiento
Gestión de cola persistente8 KiBVentana de trabajo; la historia completa permanece en flash
OTA habilitada16 KiBReserva adicional simultánea durante mantenimiento

Con OTA se requieren 108 KiB de RAM. Reservar 128 KiB supera esa suma en papel, pero todavía hay que comprobar máximos reales, fragmentación, bloques contiguos y variaciones entre builds. El laboratorio no representa la RAM total física de un ESP32 específico.

La imagen debe entrar en su partición

El diseño presupone una imagen de 768 KiB y dos slots de aplicación para la estrategia OTA con reversión. Cada slot debe alojar la imagen completa. Sumar espacio libre disperso en otras particiones no agranda el slot de destino.

flash modelada = 256 KiB de reserva fija
+ almacenamiento de historia
+ cantidad de slots × tamaño por slot
límite del ejemplo = 4096 KiB

Con cola de 64 KiB y dos slots de 1024 KiB se asignan 2368 KiB. La reserva fija agrupa metadatos y otros usos del modelo. Una tabla real debe asignar correctamente bootloader, metadatos OTA, credenciales y particiones con sus requisitos de formato y alineación.

La documentación OTA de ESP-IDF describe particiones de aplicación, selección de arranque y aceptación o reversión. El modelo usa dos slots para su estrategia elegida; no implementa ni verifica una tabla de particiones ESP-IDF.

Tiempo, energía y ancho de banda también se presupuestan

Para el control se usa intervalo de muestra + 0,1 s como demora local estimada. Para atención remota se usa intervalo de comunicación + 2 s: ambos perfiles consultan trabajo pendiente en esa ventana, incluso el controlador despierto. Un diseño con recepción continua tendría otro modelo.

Estos límites presuponen sensor, CPU y red bajo las condiciones definidas. Un dato que tarda en atravesar la nube, una conversión lenta o un lote de recuperación pueden ampliarlos. Los resultados se contrastan con pruebas y con el presupuesto de energía del tema anterior.

09 · Diseñar también el mantenimiento y el retiro

Seguridad y ciclo de vida

La identidad no se agrega al final como un campo del JSON. El diseño define dónde se crea la credencial, cómo se instala, qué recursos autoriza y cómo se reemplaza o revoca. Compartir una misma credencial entre toda la flota dificulta aislar una unidad comprometida.

La línea base NISTIR 8259A organiza capacidades como identificación, configuración, protección de datos, acceso a interfaces, actualización y conocimiento del estado de seguridad. Es un punto de partida para requisitos propios, no una lista que por sí sola pruebe seguridad.

El ciclo de vida requiere decisiones operativas.
EtapaQué dejar resuelto
Preparación y altaIdentidad única, vínculo con inventario y credencial inicial protegida
InstalaciónRed, pertenencia, validación del sensor y configuración inicial
OperaciónPermisos mínimos, calidad, versiones y antigüedad de evidencia
MantenimientoRenovación de credenciales, OTA autorizada y diagnóstico acotado
RecuperaciónAcceso local autorizado y procedimiento ante credenciales o firmware inválidos
Retiro o transferenciaRevocar acceso, tratar datos y cambiar pertenencia de forma trazable

Cuándo puede actualizar el controlador

Una campaña propone trabajo; el equipo comprueba si puede ejecutarlo. En el banco se admite mantenimiento cuando la salida está desactivada, la alimentación cumple la política y no hay una tarea esencial pendiente. Si no se dan las condiciones, se posterga y se reporta el motivo.

La autorización y compatibilidad del firmware se verifican antes de aceptarlo. El primer arranque confirma salud bajo criterios locales. Migrar configuración o datos exige preservar la compatibilidad necesaria para una eventual reversión, como vimos en el tema 44.

Qué comprueba el laboratorio

Los controles de identidad única, TLS con validación y OTA recuperable representan decisiones declaradas. Marcarlos no genera certificados, no prueba criptografía ni instala un bootloader. Las diez comprobaciones del modelo son una revisión de consistencia, que debe acompañarse con evidencia de implementación.

10 · Vincular decisiones con evidencia

Pruebas y trazabilidad

Un diseño revisable relaciona cada requisito con un componente responsable y una prueba. Si nadie puede explicar qué evidencia demostraría el requisito, todavía falta precisión en el contrato.

Matriz de verificación del controlador de banco.
RequisitoResponsablePruebaEvidencia
R1: respuesta localAdquisición y controlCambio de entrada mientras se transmiteTiempos de muestra y decisión; salida lógica y física si se instrumenta
R2: control sin redControl y comunicacionesCorte de enlace, DNS y servidorContinuidad del control y plazos de reintento
R3: cambio remotoAPI y gestor de configuraciónEnviar versión válida, repetida y fuera de rangoVersión aplicada, rechazo y demora observada
R4: historia localCola e ingestaCorte de 6 minutos, recuperación y confirmación perdidaRegistros únicos, duplicados tratados y ocupación
R5: aislamientoIdentidad y autorizaciónUna unidad intenta operar sobre otraRechazo y auditoría sin secretos
R6: OTA recuperableActualizador y arranqueImagen no autorizada, corte y diagnóstico fallidoRechazo, recuperación y build finalmente aceptada

Probar combinaciones

La integración falla a menudo cuando dos situaciones coinciden: publicar mientras se guarda configuración, reconectar mientras hay muestras pendientes o actualizar mientras crece la memoria de TLS. Se comprueba que las exclusiones previstas se respeten y que los recursos simultáneos sigan dentro de su presupuesto.

Incluí corte de alimentación durante escritura, sensor ausente, credencial vencida, reloj incorrecto, cola llena y servidor que recibe pero pierde la confirmación de aplicación. La recuperación debe ser acotada y conservar la función definida para cada estado.

Una entrega mínima de diseño

  1. Ficha del caso de uso, entorno, límites y requisitos numerados.
  2. Diagrama de bloques y responsable de cada estado y recurso.
  3. Tabla de interfaces, mensajes, configuración y confirmaciones.
  4. Presupuestos de tiempos, energía, RAM, flash y almacenamiento.
  5. Políticas ante red caída, dato inválido, reinicio y mantenimiento.
  6. Matriz de pruebas, resultados y limitaciones todavía abiertas.
  7. Instrucciones de alta, instalación, recuperación y retiro.

El panel debería mostrar build, configuración aplicada, salud, antigüedad de contacto y contadores útiles. Los registros incluyen contexto para diagnosticar, sin contraseñas, tokens ni claves privadas.

11 · Revisar restricciones de forma reproducible

Modelo ejecutable en Python

El evaluador calcula almacenamiento, tiempos y reservas, y devuelve diez resultados independientes. Una restricción fallida no oculta las demás. Los perfiles comparten el requisito de identidad única, transporte validado y actualización recuperable; el monitor no exige control continuo.

El código usa biblioteca estándar de Python 3. El botón carga Pyodide la primera vez. No simula un sensor ni una red: verifica las hipótesis de planificación que se declararon en esta lección.

from math import ceil, isfinite


def base(perfil="control"):
    if perfil not in ("control", "monitor"):
        raise ValueError("Perfil desconocido")
    p = dict(perfil=perfil, modo="activo", muestra=1, envio=10,
             plazo=15, corte=0.1, almacen=64, ram=128, slot=1024,
             identidad="unica", tls=True, ota=True)
    if perfil == "monitor":
        p.update(modo="profundo", muestra=60, envio=600,
                 plazo=900, corte=24, almacen=256)
    return p


def evaluar(p):
    if (p["perfil"] not in ("control", "monitor")
            or p["modo"] not in ("activo", "profundo")
            or p["identidad"] not in ("unica", "compartida")):
        raise ValueError("Opción desconocida")
    limites = {"muestra": (1, 3600), "envio": (1, 86400),
               "plazo": (1, 86400), "corte": (0, 168),
               "almacen": (16, 4096), "ram": (64, 256),
               "slot": (512, 2048)}
    for clave, (minimo, maximo) in limites.items():
        v = p[clave]
        if (type(v) not in (int, float) or not isfinite(v)
                or not minimo <= v <= maximo):
            raise ValueError(f"Magnitud inválida: {clave}")
    if any(type(p[k]) is not bool for k in ("tls", "ota")):
        raise ValueError("TLS y OTA requieren booleanos")
    if p["envio"] < p["muestra"]:
        raise ValueError("El envío debe ser al menos el intervalo de muestra")

    registros = ceil(p["corte"] * 3600 / p["muestra"])
    bytes_cola = ceil(registros * 96 * 1.2)
    ram = 32 + 48 + 4 + 8 + (16 if p["ota"] else 0)
    flash = 256 + p["almacen"] + (2 if p["ota"] else 1) * p["slot"]
    local = p["muestra"] + 0.1
    remoto = p["envio"] + 2
    control = p["perfil"] == "control"
    criterios = [
        ("Atención continua", None if not control else p["modo"] == "activo"),
        ("Respuesta local hasta 2 s", None if not control else local <= 2),
        ("Ventana remota", remoto <= p["plazo"]),
        ("Cola para el corte", bytes_cola <= p["almacen"] * 1024),
        ("RAM simultánea", ram <= p["ram"]),
        ("Imagen de 768 KiB por slot", 768 <= p["slot"]),
        ("Asignación de flash", flash <= 4096),
        ("Identidad por unidad", p["identidad"] == "unica"),
        ("TLS con validación", p["tls"]),
        ("OTA recuperable", p["ota"]),
    ]
    fallos = sum(ok is False for _, ok in criterios)
    aplicables = sum(ok is not None for _, ok in criterios)
    return dict(registros=registros, bytes_cola=bytes_cola, ram=ram,
                flash=flash, local=local, remoto=remoto,
                criterios=criterios, fallos=fallos, aplicables=aplicables)


for perfil in ("control", "monitor"):
    r = evaluar(base(perfil))
    print(f"{perfil}: {r['fallos']} fallos / {r['aplicables']} aplicables")
    print(f"  Cola: {r['registros']} registros; {r['bytes_cola'] / 1024:g} KiB")
    print(f"  RAM: {r['ram']} KiB; flash asignada: {r['flash']} KiB")

mal = dict(base(), modo="profundo", plazo=5, corte=24,
           ram=64, slot=512, identidad="compartida", tls=False, ota=False)
r = evaluar(mal)
print("\nDiseño contradictorio:")
for nombre, ok in r["criterios"]:
    print(f"  {nombre}: {'no aplica' if ok is None else 'cumple' if ok else 'falla'}")

assert evaluar(base())["bytes_cola"] == 41472
assert evaluar(base("monitor"))["bytes_cola"] == 165888
assert evaluar(base())["ram"] == 108
assert evaluar(base())["flash"] == 2368
assert evaluar(base())["fallos"] == 0
assert evaluar(base("monitor"))["aplicables"] == 8
assert evaluar(base("monitor"))["fallos"] == 0
assert r["fallos"] == 8
assert evaluar(dict(base(), corte=0))["bytes_cola"] == 0
assert evaluar(dict(base(), almacen=40.5))["fallos"] == 0
assert evaluar(dict(base(), muestra=1.9))["local"] == 2
assert evaluar(dict(base(), muestra=2))["fallos"] == 1
assert evaluar(dict(base(), slot=2048))["flash"] > 4096
for cambio in ({"muestra": 0}, {"envio": 0.5}, {"corte": -1},
               {"plazo": float("nan")}, {"tls": 1}, {"envio": 0.8}):
    try:
        evaluar(dict(base(), **cambio))
    except ValueError:
        pass
    else:
        raise AssertionError(f"Debía rechazar {cambio}")
print("\nComprobaciones superadas; faltan ensayos reales de implementación.")

Se verifican los dos perfiles, límites inclusivos, almacenamiento, RAM, flash y entradas inválidas. El modelo acepta magnitudes decimales dentro del rango; el laboratorio ofrece algunos tamaños discretos para facilitar la comparación.

12 · Revisar un diseño antes de implementarlo

Laboratorio de arquitectura

Los controles describen una propuesta. El evaluador calcula sus consecuencias y muestra qué restricciones cumple bajo los supuestos anteriores. Cambiar el perfil conserva los demás parámetros para que puedas descubrir incompatibilidades; los botones cargan un conjunto completo.

Ficha de diseño

Servicio y tiempos

Recursos reservados

Decisiones de seguridad y mantenimiento

Preparando evaluación.

Resultados bajo los supuestos—
Historia requerida, incluido margen—
RAM simultánea requerida—
Flash asignada de 4096 KiB—
Demora local estimada—
Espera remota nominal estimada—
«Cumple» indica consistencia con el modelo. Las opciones declaradas necesitan implementación y pruebas.
RestricciónResultadoMotivo y siguiente comprobación

Decisiones por revisar

Recorrido guiado

  1. Cargá el controlador. Hay 10 restricciones aplicables sin fallos, 40,5 KiB de historia, 108 KiB de RAM requerida y 2368 KiB de flash asignada. Todavía faltan pruebas reales.
  2. Elegí sueño profundo sin cambiar el perfil. Falla la atención continua comprometida para este controlador. Volvé a atención activa.
  3. Cambiá el intervalo de muestra a 2 s. La demora local estimada pasa a 2,1 s y supera el requisito de 2 s. El límite con 0,1 s de proceso sería 1,9 s.
  4. Cargá de nuevo el controlador y subí el corte a 1 h. Se requieren 405 KiB de historia: la reserva de 64 KiB ya no alcanza.
  5. Restaurá el controlador y fijá cada slot en 2048 KiB. La imagen entra, pero el total de 4416 KiB supera la flash disponible. Un recurso puede cumplir un límite y romper otro.
  6. Cargá el monitor. Hay 8 restricciones aplicables y dos que no corresponden a su servicio. Necesita 162 KiB para sus 24 horas de historia y estima hasta 602 s de espera remota nominal.
  7. En el monitor reducí el plazo remoto a 15 s. Dormir y comunicarse cada 600 s no satisface ese contrato. No se arregla aumentando el tamaño de la batería.
  8. Cargá el diseño contradictorio. Aparecen 8 fallos independientes. Corregir solo TLS deja pendientes memoria, historia, tiempos, identidad, atención continua y mantenimiento.
  9. Vaciá un campo o poné el intervalo de envío por debajo del de muestra. Se ocultan resultados anteriores y aparece un error de entrada. Eso se distingue de un diseño válido como entrada que incumple requisitos.
¿Puedo habilitar OTA y dar por resuelta la actualización?

No. Esa opción reserva dos slots y memoria de trabajo, y declara una intención. Todavía faltan autenticidad, compatibilidad, manejo de cortes, criterios de aceptación, datos persistentes y pruebas de recuperación.

¿Un resultado sin fallos significa que el dispositivo está listo?

No. Significa que estas restricciones son coherentes bajo ciertos supuestos. El laboratorio no mide sensor, autonomía, cobertura, picos, seguridad real, consumo de CPU ni comportamiento físico.

13 · Práctica guiada

Predecí antes de comprobar

1. Una nube lenta

La publicación tarda 8 s y bloquea el mismo bucle que debería decidir la salida cada segundo. ¿Qué contradicción hay y qué evidencia pedirías?

Ver solución

La comunicación puede impedir cumplir el plazo local. Se rediseña la espera o su aislamiento y se mide el tiempo hasta la decisión mientras la red está lenta. Una prueba sin publicaciones no alcanza.

2. Cola para una hora

Se produce una muestra por segundo, con 96 bytes reservados y factor 1,2. ¿Alcanzan 64 KiB para una hora sin entrega?

Ver solución

No. Son 3600 registros y 3600 × 96 × 1,2 = 414 720 bytes = 405 KiB. Se modifica la reserva, el contrato de historia, el formato o la cadencia, verificando sus consecuencias.

3. La suma de RAM

Hay 128 KiB disponibles y el presupuesto simultáneo suma 108 KiB. ¿Qué queda por demostrar?

Ver solución

El máximo real, las pilas, las bibliotecas, la fragmentación y las asignaciones contiguas bajo concurrencia y fallas. Los 20 KiB de diferencia son margen del cálculo, no evidencia de ejecución.

4. Imagen y partición

Una imagen ocupa 768 KiB, el slot de destino 512 KiB y hay 1 MiB libre en otra partición. ¿La imagen entra en el slot?

Ver solución

No. La capacidad debe estar en la partición de destino. Cambiar el mapa requiere una estrategia de actualización y recuperación compatible con los equipos instalados.

5. Una muestra inválida

Un sensor desconectado devuelve error. ¿Conviene convertirlo a 0 °C para mantener el JSON numérico?

Ver solución

No. Se conserva una calidad inválida y se aplica la política del caso. Cero sería un dato físico falso y podría producir una decisión incorrecta.

6. Orden aceptada por la API

La plataforma responde que guardó configuración 8, pero el dispositivo sigue reportando configuración 7. ¿Qué puede mostrar el panel?

Ver solución

Deseada: 8; última aplicada reportada: 7, con antigüedad y estado pendiente o rechazado según la evidencia. La respuesta de la API no demuestra aplicación local.

7. Recuperar historia

La cola tiene atraso y se confirma un registro por segundo, mientras el sensor genera uno nuevo por segundo. ¿Se vacía?

Ver solución

No con esas tasas sostenidas. La entrega debe superar la producción para reducir el atraso. También se verifica el presupuesto de recursos durante esa recuperación.

8. Mismo firmware, otro servicio

Un monitor despierta para comunicarse cada diez minutos. Se le exige atender órdenes en cinco segundos manteniendo esa política. ¿Basta cambiar un timeout?

Ver solución

No. La ventana de recepción contradice la latencia. Hay que revisar requisitos, conectividad, modo de actividad y energía, y medir el diseño que resulte.

14 · Síntesis

Ideas para recordar

  • Los requisitos se expresan con escenarios, límites y evidencia de aceptación.
  • La arquitectura asigna responsables y separa el control local de las demoras de red.
  • La condición física ante sensor inválido, arranque y mantenimiento se define para cada aplicación.
  • Los contratos distinguen historia, estado actual, configuración y acciones puntuales.
  • Una cola necesita capacidad, descarte, confirmación y una recuperación más rápida que la producción.
  • RAM, flash, energía y tiempos se presupuestan para los escenarios que pueden coincidir.
  • Identidad, permisos, OTA, recuperación y retiro pertenecen al diseño desde el inicio.
  • Un monitor dormido y un controlador continuo pueden compartir componentes, pero tienen contratos diferentes.
  • Las revisiones de consistencia se completan con mediciones y pruebas de fallas reales.

¿Listo para el tema 48?

Antes de avanzar, elegí un perfil de servicio y redactá su ficha: requisitos numerados, bloques, mensajes, presupuestos y pruebas. Explicá qué sigue funcionando sin red, cómo se trata una lectura inválida y qué evidencia permite aceptar una actualización.

En el próximo tema, Proyecto integrador, construimos un dispositivo medidor y controlador conectado de punta a punta a partir de estas decisiones.