¿Te interesa aprender a registrar de forma segura y (relativamente) sencilla millones de dispositivos IoT en tu entorno cloud, almacenar correctamente sus flujos de datos de alto throughput y armar visualizaciones a partir de ellos, todo con ejemplos de código completos? Entonces, ¡manos a la obra! Este artículo cubre el flujo completo, desde la autorización del dispositivo IoT hasta el streaming de datos; el almacenamiento y la visualización los veremos en un artículo posterior. Usaremos AWS como proveedor cloud y Raspberry Pi con sensores de temperatura como dispositivos IoT.

Buenas prácticas de IoT a escala productiva: Implementación con AWS
Panorama general
Este recorrido se divide en las siguientes secciones:
- Configuración de software y hardware del Raspberry Pi
- Cómo aprovisionar credenciales únicas por dispositivo
- Creación práctica de una plantilla de aprovisionamiento y un certificado bootstrap
- Pruebas de conectividad del dispositivo y streaming de datos de temperatura
- Almacenamiento de los datos en streaming (lo veremos en la Parte 2)
- Visualización de los datos en streaming (lo veremos en la Parte 2)
Hay bastante por delante, así que ¡empecemos! Para seguir este artículo solo necesitas experiencia básica con Bash y Python, manejo básico de la consola web de AWS y una buena taza de café para acompañarte durante este recorrido extenso.
Configuración de software y hardware del Raspberry Pi
Primero, pon en marcha varios dispositivos Raspberry Pi (yo usaré modelos Pi 3). Te recomiendo el Raspbian OS Imager para automatizar la instalación del sistema operativo en tarjetas microSD. Cuando ya estés en el escritorio y hayas actualizado el dispositivo, ejecuta el siguiente comando para instalar el SDK específico de AWS IoT:
pip3 install -U awsiotsdk
Conviene entender este paquete antes de avanzar:
1. ¿Por qué el SDK de IoT está separado del SDK de uso general boto3? Boto3 se basa en HTTP, un protocolo útil para ejecutar rápidamente la mayoría de las acciones de AWS. Sin embargo, HTTP no es adecuado para enviar mensajes a través de conexiones de larga duración con alta probabilidad de conectividad intermitente, donde los datos fluyen mayormente desde el dispositivo conectado hacia el exterior. MQTT, el protocolo que usa el SDK de IoT, fue diseñado específicamente para el caso de uso IoT, ya que facilita enormemente que un dispositivo publique mensajes con frecuencia y los reciba ocasionalmente, incluso ante problemas de conectividad.
2. El paquete 'awsiotsdk' corresponde a la v2 del SDK de AWS IoT. Es una entidad distinta del paquete v1 'AWSIoTPythonSDK', de nombre similar. Casi todos los tutoriales publicados hasta la fecha sobre AWS IoT usan la primera versión del SDK de IoT y, lamentablemente, la v1 dificulta implementar un enfoque de registro de dispositivos a escala productiva. La v2 también simplifica la publicación y recepción de mensajes, así que trabajaremos con la última versión.
Ya con los SDK de AWS instalados en tu Raspberry Pi, deberás conectarle un sensor digital de temperatura. Te recomiendo este sensor DS18B20 si quieres seguir el artículo paso a paso.
También necesitarás lo siguiente para conectar el sensor a tu Raspberry Pi:
Kit surtido de resistencias (necesitamos una de 4.7K Ohm)
Si tienes que esperar unos días a que lleguen estos componentes, no hay problema: puedes seguir avanzando en el artículo, ya que también incluiremos un script para transmitir valores de temperatura simulados. Si ya los tienes a mano, los primeros cinco minutos del siguiente tutorial te muestran cómo conectar el sensor al Raspberry Pi y verificar que esté recibiendo valores de temperatura:
Tutorial del sensor de temperatura DS18B20 para Raspberry Pi
Además del proceso descrito en ese tutorial, te recomiendo agregar lo siguiente a /etc/modules para que los módulos onewire se carguen al arrancar y no tengas que ejecutar modprobe después de cada reinicio:
w1-gpio
w1-therm
Cómo aprovisionar credenciales únicas por dispositivo
Entre los distintos posts sobre AWS IoT que circulan, la mayoría usa la v1 del SDK para mostrar un ejemplo simple en el que se registra un único dispositivo en una cuenta cloud. El proceso descrito suele consistir en crear un certificado con sus permisos de AWS IoT asociados y luego copiar los archivos del certificado al dispositivo, lo que le permite hacer llamadas a la API de IoT y transmitir datos a la nube.
Sin embargo, esos ejemplos no son muy aplicables, porque los casos de uso reales de IoT involucran de miles a millones de dispositivos transmitiendo datos a un entorno cloud. A cada dispositivo de una flota así se le debe asignar un conjunto único de credenciales, de modo que si un dispositivo o sus credenciales de AWS quedan comprometidos y se usan con fines ilegítimos (por ejemplo, transmitir datos falsos a tu plataforma), ese conjunto de credenciales pueda deshabilitarse sin afectar al resto de la flota.
¿Cómo se puede hacer la creación de credenciales por dispositivo de la forma más simple posible? ¿Se puede lograr sin tener que crear millones de certificados por adelantado y coordinar su colocación individual durante la fabricación? Y, por otra parte, ¿se puede hacer sin obligar al fabricante a llamar a la API de tu entorno para crear un nuevo certificado bajo demanda cada vez que un dispositivo sale de la línea de producción para inicializarse con software y credenciales? Conviene evitar esos métodos: son complejos, propensos a errores e imponen una carga innecesaria al fabricante.
Por suerte, existe una solución sencilla, y la v2 del SDK de IoT facilita un poco su implementación. La asignación a gran escala de credenciales únicas por dispositivo se logra creando dos entidades en la consola de AWS IoT: (1) una plantilla de aprovisionamiento de flota (fleet provisioning template) y (2) un certificado bootstrap que se coloca en todos los dispositivos. El siguiente flujo explica el proceso:
- Se crea un único certificado de IoT que se colocará en todos los dispositivos IoT. Este certificado, llamado certificado 'bootstrap', se asocia con una política de permisos que solo permite al dispositivo emitir una solicitud para (a) crear un certificado específico del dispositivo y obtener esas credenciales si la solicitud es aprobada, y (b) agregarse al Registro de IoT (IoT Registry). Esta solicitud puede enviar opcionalmente un identificador único del dispositivo, como un número de serie.
- La plataforma AWS IoT, al recibir la solicitud de creación de certificado, generará un nuevo certificado y entregará sus archivos asociados al dispositivo. Los permisos de IoT asociados a cada nuevo certificado, así como los distintos atributos del dispositivo recién registrado, se basan en una plantilla que tú creas y que AWS llama 'fleet provisioning template'.
Esta plantilla asocia atributos a los dispositivos recién registrados, por ejemplo {"DeviceType": "RaspberryPi"}, y además permite que todos los certificados únicos por dispositivo compartan la misma política de permisos, que aun así puede definir permisos específicos por dispositivo.
Por ejemplo, la única política de IoT de una plantilla para dispositivos registrados se puede diseñar para que el dispositivo 'sensor123' solo publique mensajes en el tópico de IoT sensors/temp/sensor123, que 'sensor456' solo publique en sensors/temp/sensor456, y así sucesivamente. Dicho de otra forma, la política de permisos de la fleet provisioning template evita que tengas que crear una política nueva para cada dispositivo y certificado registrado. Este enfoque también te permite desplegar cambios de permisos a toda una flota IoT con una sola actualización de política.
3. El proceso de creación de un certificado de dispositivo puede controlarse opcionalmente mediante lo que AWS llama "pre-provisioning hook". Es una función Lambda que tú escribes y que puede exigir un identificador único en la solicitud del certificado, para compararlo contra una lista blanca (por ejemplo, la lista de todos los números de serie fabricados) o una lista negra (por ejemplo, números de serie asociados a dispositivos comprometidos o abusivos).
4. Si la solicitud se aprueba, los archivos del certificado del dispositivo se entregan al dispositivo para usarlos en el streaming de datos, y el dispositivo se da de alta en el IoT Registry con los atributos de la plantilla. El certificado bootstrap ya no es necesario para el dispositivo.
Con este flujo, el fabricante de dispositivos IoT solo tiene que entregar a cada dispositivo el certificado bootstrap. El certificado único del dispositivo, que habilita el streaming de datos, puede crearse y obtenerse de inmediato dentro de la planta de fabricación si así se quiere, o más adelante, cuando ya esté en manos del usuario final. Sin importar cuándo se obtengan las credenciales, el fabricante instalaría en el dispositivo el software que tú proporcionas, el cual ejecuta el proceso de creación de certificados basado en la fleet provisioning template cada vez que el dispositivo arranca, hay conexión a Internet y se detecta que falta el certificado del dispositivo.
Ejemplo práctico de uso de la fleet provisioning template y el certificado bootstrap
Sé que es bastante información para asimilar; con suerte, todo cobrará más sentido cuando tengas la oportunidad de implementar el proceso.
A continuación verás un ejemplo completo y funcional de cómo configurar tu IoT Registry agregando dispositivos mediante una fleet provisioning template y un certificado bootstrap. Después usaremos los certificados de dispositivo creados para transmitir datos de temperatura a la plataforma AWS IoT.
Empieza navegando al servicio AWS IoT Core. Si nunca lo has usado, te recibirá un asistente que te pedirá 'Onboard a device' u 'Onboard many devices'. Esto nos guiará por el proceso de la fleet provisioning template, pero por una particularidad de este asistente conviene salir primero de esa pantalla y crear el certificado bootstrap.
Desde el panel izquierdo navega a Secure → Certificates y haz clic en "Create"; luego elige "One-click certificate creation". Esto creará al instante un nuevo certificado que usaremos como bootstrap. Asegúrate de descargar el certificado (cert.pem), la llave privada (private.key) y la autoridad certificadora raíz (sigue el enlace Download y guarda el archivo AmazonRootCA1.pem); después haz clic en 'Activate' para habilitar el certificado:

Una vez habilitado el certificado y descargadas las llaves, haz clic en "Attach a policy". Vamos a crear una política que lo convierta en certificado de bootstrapping. Desde la pantalla "Add authorization to certificate", haz clic en "Create New Policy" y crea una política llamada "IoT_Bootstrapping_Certificate". Le daremos permisos para publicar, suscribirse y recibir mensajes hacia y desde dos tópicos reservados de AWS que se utilizan para el proceso de creación de certificados y la fleet provisioning template:

Asegúrate de reemplazar la región, el ID de la cuenta y templateName con los valores específicos de tu cuenta
Action: iot:Connect
Resource ARN: *Action: iot:Publish
Action: iot:Receive
Resource ARN: arn:aws:iot:us-west-2:123456789012:topic/$aws/certificates/create/*Action: iot:Publish
Action: iot:Receive
Resource ARN: arn:aws:iot:us-west-2:123456789012:topic/$aws/provisioning-templates/SensorTemplate/provision/*Action: iot:Subscribe
Resource ARN: arn:aws:iot:us-west-2:123456789012:topicfilter/$aws/certificates/create/*Action: iot:Subscribe
Resource ARN: arn:aws:iot:us-west-2:123456789012:topicfilter/$aws/provisioning-templates/SensorTemplate/provision/*
Haz clic en 'Create'. Una vez creada la política del certificado, ve al certificado que creaste y adjúntale esta política:


Ya con un certificado de bootstrapping listo para nuestros dispositivos, regresemos al asistente de la fleet provisioning template. Llegas haciendo clic en Onboard → Get started.
En el asistente, elige "Onboard many devices" e ingresa lo siguiente:

- Template name: "SensorTemplate"
- Provisioning role: crea un rol llamado "IoTProvisioningRole" y asócialo con la política administrada por AWS "AWSIoTThingsRegistration". Este rol le permite a la plataforma AWS IoT registrar nuevos dispositivos cuando se conectan.
- En un escenario real, escribirías una función Lambda como pre-provisioning hook para validar el número de serie antes de permitir la creación de un certificado de dispositivo, pero por brevedad lo dejaremos de lado. Podrías usarla, por ejemplo, para comparar un número de serie contra tablas de DynamoDB con números de serie en lista negra y conocidos. Aquí tienes un ejemplo simple de cómo se vería:
def lambda_handler(event, context):
serial = event["parameters"]["SerialNumber"] # Implement serial number validation functions
if is_valid_serial(serial) and not is_blacklisted(serial):
return {"allowProvisioning": True} return {"allowProvisioning": False}
- Marca la opción "Use the AWS IoT registry to manage your device fleet". Esto te permitirá ver los dispositivos asociados en la consola web de IoT, así como aplicar actualizaciones al estado o al software del dispositivo.
En la siguiente página definiremos una política de IoT, asociada a la plantilla, que les da a nuestros dispositivos permisos para publicar y recibir mensajes desde un tópico de IoT específico de cada dispositivo. La crearemos usando una thing policy variable. Las thing policy variables permiten que los dispositivos publiquen o reciban mensajes en un tópico de IoT que es único para cada uno. En este ejemplo, los dispositivos publicarán y se suscribirán a un tópico basado en BuildingName, Location (dentro del edificio) y ThingName:

Action: iot:Connect
Resource ARN: arn:aws:iot:us-west-2:123456789012:client/${iot:Connection.Thing.ThingName}
Action: iot:Publish
Action: iot:Receive
Resource ARN: arn:aws:iot:us-west-2:123456789012:topic/temperature/${iot:Connection.Thing.Attributes[BuildingName]}/${iot:Connection.Thing.Attributes[Location]}/${iot:Connection.Thing.ThingName}
Action: iot:Subscribe
Resource ARN: arn:aws:iot:us-west-2:123456789012:topicfilter/temperature/${iot:Connection.Thing.Attributes[BuildingName]}/${iot:Connection.Thing.Attributes[Location]}/${iot:Connection.Thing.ThingName}
En la siguiente página, define la configuración de tu AWS IoT registry: estos son los atributos que se asignan a cada dispositivo recién aprovisionado:

- Thing name prefix: sensor_
- Crea un nuevo Thing Type 'TemperatureSensor' con un Searchable Thing Attribute de 'Location' (por ejemplo, 'loft', 'downstairs') y "BuildingName" (por ejemplo, 'home417')
- Crea los siguientes atributos no buscables: 'DeviceType' (por ejemplo, 'RaspberryPi') y 'ModelNumber' (por ejemplo, '3')
En la pantalla final, después de hacer clic en "Create template", selecciona el certificado de bootstrapping que creaste antes y haz clic en "Attach policy"; luego selecciona 'Enable template'. Esta asociación permite que los dispositivos que usan el certificado de bootstrapping se apoyen en esta plantilla para recibir un certificado de dispositivo con los permisos necesarios para publicar mensajes en un tópico de IoT específico al nombre del dispositivo. Además de obtener el certificado, el dispositivo también usa la fleet provisioning template para darse de alta en el IoT Registry y recibir los atributos que definimos.

Para recapitular, esto es lo que acabamos de lograr:
- Creamos un certificado de bootstrapping y lo asociamos con una política que solo permite a un dispositivo que use ese certificado emitir, mediante una Fleet Provisioning Template, una solicitud para (1) un nuevo certificado único de dispositivo y (2) ser agregado al IoT Registry con atributos por defecto.
- Los certificados de dispositivo creados para los dispositivos recién registrados quedan asociados con una IoT Policy que permite al dispositivo publicar y recibir mensajes en un tópico de IoT específico de ese dispositivo IoT.
Ya casi terminamos con la preparación del servicio IoT. Solo nos queda actualizar la fleet provisioning template para que acepte y exija los atributos buscables durante la solicitud de aprovisionamiento. Vuelve a "SensorTemplate" y agrega lo siguiente al JSON de la plantilla:
# Add "BuildingName" and "Location" within "Parameters"
{
"Parameters": {
"SerialNumber": {
"Type": "String"
},
"BuildingName": {
"Type": "String"
},
"Location": {
"Type": "String"
},
"AWS::IoT::Certificate::Id": {
"Type": "String"
}
}
}# Reference these attribute parameters within "thing": "Properties"
"Properties": {
"AttributePayload": {
"DeviceType": "RaspberryPi",
"ModelNumber": "3",
"BuildingName": {
"Ref": "BuildingName"
},
"Location": {
"Ref": "Location"
}
},
"ThingGroups": [],
¡Hicimos muchos cambios en la consola de IoT! Ahora verifiquemos con ejemplos prácticos de código que el certificado de bootstrapping y la fleet provisioning template funcionan como esperamos.
Pruebas de conectividad del dispositivo y streaming de datos de temperatura
Copia los archivos del certificado que descargaste a una carpeta en tus dispositivos RPi y luego crea el archivo config.ini que se muestra a continuación con los valores apropiados. Además de actualizar las rutas a los archivos del certificado, deberás obtener el IoT Endpoint de tu cuenta desde la página de Settings dentro de la consola de AWS IoT:
# Set the path to the location containing your bootstrap certificates (root, private, claim certificate)
SECURE_CERT_PATH = /home/pi/iot_certs/
# Specify the names for the root cert, provisioning claim cert, and the private key.
ROOT_CERT = AmazonRootCA1.pem
CLAIM_CERT = <YOURCERT>-certificate.pem.crt
SECURE_KEY = <YOURCERT>-private.pem.key
# Set the name of your IoT Endpoint
IOT_ENDPOINT = <YOUR_ENDPOINT>-ats.iot.us-west-2.amazonaws.com
# Set the IoT topic name
IOT_TOPIC = temperature/${iot:Connection.Thing.Attributes[BuildingName]}/${iot:Connection.Thing.Attributes[Location]}/${iot:Connection.Thing.ThingName}
# Set the IoT provisioning template name
PROVISIONING_TEMPLATE_NAME = SensorTemplate
A continuación, ejecuta el siguiente script, que usa tu certificado bootstrap para obtener un certificado de dispositivo (que se guarda en iot_certs/permanent_cert/) y agrega el dispositivo al IoT Registry. Con el parámetro -l, define el atributo Location, asociado al lugar dentro de tu casa donde estará el dispositivo. Por ejemplo:
./connect_rpi_to_iot_core.py -c config.ini -b home417 -l loft
Aquí pasan muchas cosas, así que recomiendo encarecidamente que te tomes el tiempo de revisar el código para entender el flujo de las llamadas a la API del SDK de IoT. Si lo configuraste todo correctamente, verás que el script termina con "Success" impreso en pantalla, un conjunto de tres archivos de certificado dentro de permanent_cert/ y un nuevo archivo perm_config.ini en esa carpeta para los archivos del certificado del dispositivo.
Notarás que, a medida que vas agregando tus dispositivos RPi con este script, aparecen nuevos certificados en la consola de IoT, todos asociados a la única IoT policy que definimos en la fleet provisioning template, que permite publicar y suscribirse a mensajes en un tópico cuyo nombre se basa en BuildingName, Location y ThingName.
Cada dispositivo agregado por el script se registra con el ThingName sensor_{UUID}, donde UUID es un identificador único proporcionado por /etc/machine-id en el dispositivo. Así, cada dispositivo publicará mensajes en su propio IoT Topic único. En un escenario real de IoT, podrías incorporar el número de serie del dispositivo como su ThingName único.
¡Probemos los certificados de nuestros dispositivos con valores de temperatura simulados! Ejecuta el siguiente script, que (1) publica números aleatorios en el IoT Topic del dispositivo y (2) se suscribe a ese mismo tópico e imprime los valores recibidos.
./pubsub_simulated_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
Deberías ver una salida similar a esta:

¡Felicitaciones! Acabas de hacer el onboarding exitoso de una pequeña flota de dispositivos IoT siguiendo la metodología de AWS pensada para realizar este registro de manera segura y a escala.
Para probar tus conexiones con datos reales, ejecuta el siguiente script. Es similar al anterior, salvo que (1) no se suscribe al tópico al que publica y (2) envía valores reales de temperatura cada cinco segundos:
./publish_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
La salida debería verse así:

Si ejecutas este script al reiniciar mediante un trabajo de crontab (precedido por un sleep de 30s para dar tiempo a que los módulos onewire se carguen al arrancar), tu dispositivo IoT retomará el streaming ante un reinicio (in)esperado:
$ crontab -e
@reboot sleep 30 && /home/pi/publish_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
Repite los procesos de onboarding y streaming con todos los Raspberry Pi distribuidos por tu casa. ¡Ya estás muy bien encaminado para trabajar con datos IoT a escala!
Lo que viene: Almacenamiento y Visualización
No te pierdas la parte 2, donde hablaré sobre cómo almacenar y visualizar correctamente datos de IoT en streaming a gran escala.
Una salvedad
El enfoque de publicación de mensajes pub/sub que vimos arriba funciona mejor para el caso de uso de telemetría de dispositivos, donde los datos transmitidos serán consumidos no solo por una app de analítica de backend, sino también directamente por los usuarios finales, por ejemplo a través de una app que les permite ver los valores de temperatura de su casa. Si los datos en streaming solo van a ser usados por una app de backend, conviene más, en términos de costo, publicar los mensajes con el enfoque "IoT Basic Ingest", tal como se define en el documento AWS IoT Core Best Practices for Designing MQTT Topics. Al publicar mensajes en un tópico asociado a una IoT Rule en lugar de un tópico genérico de IoT Core, pierdes la capacidad de suscribirte al tópico a cambio de no tener que pagar el componente de mensajería de los Precios de IoT.