← Notas desde el banco de trabajo.
Aprovisionamiento BLE para un dispositivo sin pantalla
El producto tiene un botón, un LED y ninguna forma de escribir. El cliente tiene que cargarle el nombre y la contraseña de su Wi-Fi doméstico antes de que sirva para algo. En el banco, con un kit de desarrollo y una app BLE genérica, esto funciona la primera tarde. Luego se topa con un teléfono que muestra un diálogo de emparejamiento cada vez, un router con dos bandas bajo el mismo nombre y una contraseña mal escrita a las 9 p.m. por alguien que nunca leerá un manual.
Las mismas preguntas aparecen una y otra vez en foros de fabricantes y rastreadores de incidencias, y muchos de los hilos siguen sin respuesta: por qué iOS empareja y se queja al mismo tiempo, por qué un dispositivo aparece en un teléfono Android y en otro no, si «Just Works» es suficiente. Esta nota cubre las decisiones que importan.
Parte de un protocolo existente
No diseñes tu propio servicio GATT para esto. Ya existen tres opciones mantenidas:
- ESP-IDF unified provisioning para partes de Espressif. Soporta los transportes BLE y SoftAP y tres esquemas de seguridad, descritos más abajo.
- Improv Wi-Fi, un estándar abierto de la comunidad de ESPHome y Home Assistant. Corre sobre BLE o serial, y ambos se pueden manejar desde un navegador. Define cuatro estados (autorización requerida, autorizado, aprovisionando, aprovisionado) y un conjunto pequeño de comandos, entre ellos escanear y enviar credenciales.
- Wi-Fi provisioning over BLE de Nordic, una muestra y un servicio en el nRF Connect SDK, para productos construidos con las partes Wi-Fi de Nordic.
Elijas la que elijas, lee qué protege y qué deja a tu cargo. La especificación de Improv trata la autorización como opcional pero recomendada, y la condiciona a una acción física en el dispositivo. Es una buena idea, pero activarla es tu trabajo.
BLE no es el único transporte. El aprovisionamiento SoftAP, donde el dispositivo se convierte brevemente en su propio punto de acceso, es el más interoperable. Pero el teléfono tiene que salir de la red del cliente para unirse a él, y la documentación de Espressif señala que iOS no tiene una API nativa para descubrir y unirse a ese punto de acceso, así que el usuario termina en los ajustes del sistema. BLE ofrece descubrimiento nativo en ambas plataformas. Espressif también cita unos 110 KB de memoria en tiempo de ejecución para su transporte BLE, algo que importa en una parte pequeña. Si el producto tiene un puerto USB, también vale la pena tener una ruta de aprovisionamiento serial.
Qué protege y qué no protege el emparejamiento
BLE ofrece cuatro métodos de emparejamiento: Just Works, Numeric Comparison, Passkey Entry y fuera de banda. Numeric Comparison necesita una pantalla y una entrada de sí/no en ambos lados. Passkey Entry necesita una pantalla de un lado y un teclado del otro. Un dispositivo con un botón y un LED no tiene ninguna de las dos cosas, así que recurre a Just Works, a menos que tenga un canal fuera de banda como NFC.
Just Works con LE Secure Connections cifra el enlace, lo que detiene a un espía pasivo. No demuestra quién está del otro lado. Nada en el intercambio le permite al usuario confirmar que habla con su dispositivo, y un atacante activo dentro del alcance de radio puede colocarse en medio. La contraseña de Wi-Fi es lo que se envía por ese enlace.
Por eso hay que autenticar en la capa de aplicación. Las opciones realistas:
| Enfoque | Qué demuestra | A qué prestar atención |
|---|---|---|
| Ventana de autorización física (pulsar un botón, tiempo límite) | Alguien está junto al dispositivo en este momento | Ventana corta y una forma clara de reabrirla |
| Secreto por dispositivo en la etiqueta o en un código QR | La persona tiene esta unidad en la mano | Cada unidad necesita su propio secreto |
| Solo Just Works | Nada más allá del cifrado del enlace | Aceptable para un juguete, difícil de defender para cualquier cosa en una red doméstica |
El esquema 1 de Espressif admite una prueba de posesión, un secreto único por dispositivo que se ingresa en el cliente, y el esquema 2 usa SRP6a con una sal y un verificador por dispositivo generados con anticipación. El esquema 0 es sin cifrado, y el esquema 1 con una prueba nula es cifrado sin autenticación. Lee la configuración, porque la opción predeterminada más fácil de demostrar no es la que debe salir en el producto.
El secreto por dispositivo tiene una regla estricta: debe ser distinto en cada unidad. Un secreto compilado dentro de la imagen de firmware es un solo secreto para toda la línea de productos, y cualquiera puede extraerlo de una actualización descargada. Genéralo en producción, prográmalo junto con el firmware e imprime la etiqueta a partir del mismo registro. Eso hace que el paso de prueba de fin de línea sea el lugar natural para esto, y significa que el fixture y la impresora de etiquetas deben ponerse de acuerdo sobre el origen del secreto antes de la primera corrida de producción, no después.
Combina las dos. Un botón que abre la ventana más un secreto por dispositivo que autentica la sesión cubren los casos que cada uno deja pasar por separado.
El teléfono es la mitad de tu producto
iOS. El emparejamiento no lo maneja la app. Los desarrolladores reportan que el sistema lo inicia cuando la app toca una característica que requiere cifrado, así que el lugar de tu tabla GATT donde pones el requisito de seguridad decide cuándo aparece el diálogo. Los mismos reportes describen el diálogo regresando en cada conexión, el emparejamiento fallando en el periférico mientras iOS registra un enlace exitoso, y enlaces perdidos después de que el teléfono rota su dirección privada. Algunos de esos hilos no tienen resolución. Tómalos como evidencia de que el bonding es una comodidad, no algo de lo que el aprovisionamiento pueda depender.
La regla práctica: haz que la sesión de aprovisionamiento funcione sin bond. Establece tu sesión de capa de aplicación en cada conexión. Si el bond sobrevive, bien. Si no, nada se rompe.
iOS 18 agregó AccessorySetupKit, que muestra un selector del sistema para tu accesorio y maneja el paso de descubrimiento y emparejamiento sin que la app pida permiso de Bluetooth. Requiere iOS 18 o posterior, el filtro de descubrimiento vive en el Info.plist de la app y no puede cambiar en tiempo de ejecución, y la app sigue comunicándose con el dispositivo a través de CoreBluetooth después. Vale la pena adoptarlo en una app nueva. No reemplaza la ruta anterior para los clientes con versiones más viejas de iOS.
Android. A partir de Android 12, escanear requiere el permiso de tiempo de ejecución BLUETOOTH_SCAN y conectarse requiere BLUETOOTH_CONNECT. Si la app declara que nunca usa el escaneo para derivar la ubicación, el sistema filtra algunos resultados, lo cual está bien para una app de aprovisionamiento pero importa si tu dispositivo anuncia de una manera inusual. Un dispositivo que aparece en el teléfono del desarrollador y no en el de un cliente suele ser un problema de permisos o del formato de advertising, no un problema de radio.
Prueba contra una matriz real: dos o tres iPhones con distintas versiones de iOS y teléfonos Android de más de un fabricante, incluido uno de hace unos años. Los emuladores no pueden hacer esto.
Diseña primero las rutas de falla
La mayor parte de la carga de soporte está en las rutas que nadie demostró.
Contraseña incorrecta. El dispositivo lo intenta, falla y tiene que decirlo. El conjunto de errores de Improv tiene un solo código de «no se pudo conectar», así que si quieres que la app distinga una contraseña incorrecta de una red fuera de alcance, tienes que transportar ese detalle tú mismo. Luego regresa a un estado en el que el usuario pueda intentarlo de nuevo, sin necesidad de apagar y encender.
Banda incompatible. La lista de redes muestra lo que ve la radio del dispositivo, no lo que ve el teléfono. Muchas partes Wi-Fi de bajo costo son solo de 2.4 GHz. Un cliente cuyo teléfono está en una red de 5 GHz buscará algo que no está en la lista. Dilo en la app.
Tiempos de espera. Una ventana de aprovisionamiento abierta debe cerrarse: Improv sugiere alrededor de un minuto para la autorización. El advertising también cuesta batería en un producto que funciona con batería, así que ponle un límite y define qué hace mantener presionado el botón para reabrirla.
Reaprovisionamiento. La gente cambia de router. Decide cómo se reemplazan o se borran las credenciales almacenadas, y qué elimina un restablecimiento de fábrica. Las credenciales en la flash del chip son tan privadas como la protección de lectura del chip, así que actívala en las partes de producción.
Ruta de actualización. Un dispositivo que acepta credenciales Wi-Fi normalmente también aceptará firmware, y ahí se aplican las mismas preguntas de recuperación y reversión. Asegúrate de que la autorización de aprovisionamiento y la autorización de actualización sean decisiones separadas, y de que ambas estén documentadas.
Cada una de estas es un comportamiento del firmware que puedes especificar en papel antes de escribir código, y cada una es más barata de especificar que de corregir después de la primera tanda de devoluciones.
Cómo lo manejamos
Partimos de la pila de aprovisionamiento del fabricante del chip, agregamos el secreto por dispositivo en la prueba de producción y probamos el flujo con teléfonos y routers reales antes de que salga al mercado. Si quieres que esto se diseñe dentro de un producto, envíanos el MCU o módulo de radio, las versiones de teléfono y sistema operativo que debes soportar y qué tendrá en la mano el cliente cuando lo configure.
¿Construyes un producto BLE que debe emparejarse sin pantalla? Escribimos el firmware de aprovisionamiento y la app que se comunica con él.
Herramientas para este tema
- Grabador ESP32 en el navegador Graba un .bin por USB desde el navegador. Lee primero el chip y el archivo, y rechaza firmware compilado para otro chip, otra revisión u otro tamaño de flash.
- Grabador STM32 en el navegador Graba un .dfu, .hex o .bin por USB DFU desde el navegador. Lee primero el mapa de flash y la identidad del chip y rechaza firmware cuyos bytes o tabla de vectores no le pertenecen. Nunca toca los option bytes.
- Terminal serie en el navegador Conecta una placa USB y lee o envía texto y hex por serie desde el navegador. Velocidad y formato, perfiles de reset DTR/RTS para ESP32 y Arduino, marcas de tiempo y registro guardado. Nada sale de tu computadora.
Notas relacionadas
- Preparing for the CRA 24-hour vulnerability reporting duty What triggers a CRA report, the 24-hour, 72-hour and final deadlines, and the firmware and process pieces a small hardware maker needs in place first.
- Aprovisionar números de serie en la línea Dónde van los seriales, las llaves y los bloqueos de depuración por unidad en STM32, nRF52 y ESP32, qué es irreversible y cómo planear el paso de programación.
- Bare-metal o RTOS en un MCU pequeño Cómo decidir cuándo basta un superloop, qué cuesta realmente un RTOS en RAM y en esfuerzo de depuración, y qué revisar antes de comprometerte con uno.