Le interessa scoprire come registrare in modo sicuro e (relativamente) semplice milioni di dispositivi IoT nel proprio ambiente cloud, archiviare correttamente i loro flussi di dati ad alto throughput e gestire le visualizzazioni a valle, il tutto con esempi di codice completi? Allora entriamo subito nel vivo. Questo articolo copre l'intero flusso, dall'autorizzazione del dispositivo IoT allo streaming dei dati, mentre archiviazione e visualizzazione saranno trattate in un secondo articolo. Useremo AWS come cloud provider e dei Raspberry Pi con sensori di temperatura come dispositivi IoT.

Best practice IoT su scala produttiva: implementazione con AWS
Panoramica
La trattazione è suddivisa nelle sezioni seguenti:
- Configurazione software e hardware del Raspberry Pi
- Panoramica sull'assegnazione di credenziali univoche per ogni dispositivo
- Creazione pratica di un provisioning template e di un certificato di bootstrap
- Test di connettività dei dispositivi e streaming dei dati di temperatura
- Archiviazione dei dati in streaming (trattata nella Parte 2)
- Visualizzazione dei dati in streaming (trattata nella Parte 2)
C'è parecchio da affrontare, quindi iniziamo. Per seguire l'articolo Le bastano un'esperienza di base con Bash e Python, una conoscenza essenziale della console web di AWS e una bella tazza di caffè per arrivare in fondo a questa lunga guida.
Configurazione software e hardware del Raspberry Pi
Per prima cosa, prepari diversi dispositivi Raspberry Pi (io userò dei Pi 3). Consiglio di utilizzare l'Imager di Raspbian OS per automatizzare l'installazione del sistema operativo sulle schede microSD. Una volta arrivato al desktop e aggiornato il dispositivo, esegua il comando seguente per installare l'SDK specifico per AWS IoT:
pip3 install -U awsiotsdk
Prima di proseguire è importante capire bene questo pacchetto:
1. Perché l'SDK IoT è separato dall'SDK boto3 di uso generale? Boto3 si basa su HTTP, un protocollo utile per eseguire rapidamente la maggior parte delle azioni AWS. HTTP, però, non è adatto per l'invio di messaggi su connessioni di lunga durata con un'alta probabilità di interruzioni intermittenti, in cui i dati fluiscono prevalentemente in uscita dal dispositivo connesso. MQTT, il protocollo utilizzato dall'SDK IoT, è progettato proprio per i casi d'uso IoT: semplifica notevolmente la pubblicazione frequente di messaggi e la ricezione sporadica, anche in presenza di problemi di connettività.
2. Il pacchetto 'awsiotsdk' rappresenta la v2 dell'AWS IoT SDK ed è un'entità distinta dal pacchetto v1 'AWSIoTPythonSDK', dal nome simile. Quasi tutte le guide pubblicate finora su AWS IoT utilizzano la prima versione dell'SDK IoT e, purtroppo, la v1 rende più complesso implementare un approccio al device registry su scala produttiva. La v2 semplifica anche la pubblicazione e la ricezione dei messaggi, quindi useremo l'ultima versione.
Ora che il Suo Raspberry Pi ha gli SDK AWS richiesti, occorre collegarvi un sensore digitale di temperatura. Se desidera seguire l'articolo passo dopo passo, consiglio questo sensore DS18B20.
Per collegare il sensore al Raspberry Pi Le serviranno anche:
Kit di resistori assortiti (ci serve un resistore da 4,7K Ohm)
Se deve attendere qualche giorno per ricevere il materiale, può proseguire tranquillamente con la lettura: forniremo anche uno script per simulare lo streaming di valori di temperatura. Se ha già tutto a disposizione, i primi cinque minuti del tutorial seguente Le mostrano come collegare il sensore al Raspberry Pi e verificare che riceva i valori di temperatura:
Tutorial sensore di temperatura DS18B20 per Raspberry Pi
Oltre alla procedura descritta nel tutorial, consiglio di aggiungere a /etc/modules le righe seguenti, in modo che i moduli onewire vengano caricati all'avvio senza dover eseguire modprobe dopo ogni riavvio:
w1-gpio
w1-therm
Panoramica sull'assegnazione di credenziali univoche per ogni dispositivo
Tra i vari post di blog dedicati ad AWS IoT, la maggior parte usa la v1 dell'SDK IoT per illustrare un esempio didattico in cui un singolo dispositivo viene registrato in un account cloud. Il processo descritto prevede tipicamente la creazione di un certificato con le relative permission AWS IoT, seguita dal posizionamento dei file del certificato sul dispositivo, in modo da consentirgli di effettuare chiamate API IoT che inviano i dati al cloud.
Esempi di questo tipo, però, hanno un'applicabilità limitata, perché i casi d'uso IoT reali coinvolgono migliaia o milioni di dispositivi che inviano dati in streaming a un ambiente cloud. A ogni dispositivo di una flotta del genere andrebbe assegnato un set univoco di credenziali, così che, in caso di compromissione e utilizzo illecito (ad esempio per inviare dati falsi alla Sua piattaforma), quel set di credenziali possa essere disabilitato senza impattare gli altri dispositivi della flotta.
Come si può rendere il più semplice possibile la creazione di credenziali specifiche per ogni dispositivo? Si può fare senza creare in anticipo milioni di certificati e senza dover coordinare la loro assegnazione univoca ai dispositivi durante la produzione? E si può fare senza richiedere al produttore di chiamare le API del Suo ambiente per creare un nuovo certificato on-demand quando un dispositivo esce dalla linea di produzione per essere preparato con software e credenziali? Questi metodi sono da evitare, perché complessi, soggetti a errori e gravano inutilmente sul produttore.
Per fortuna esiste una soluzione semplice, che la v2 dell'SDK IoT rende ancora più immediata da implementare. L'assegnazione su larga scala di credenziali univoche per ogni dispositivo si realizza creando due entità nella console AWS IoT: (1) un fleet provisioning template e (2) un certificato di bootstrap da installare su tutti i dispositivi. Il flusso di lavoro qui sotto spiega il processo:
- Viene creato un singolo certificato IoT da installare su tutti i dispositivi IoT. Questo certificato, definito di 'bootstrap', è associato a una policy di permission che consente al dispositivo di emettere una richiesta solo per (a) creare un certificato specifico per quel dispositivo e recuperarne le credenziali se la richiesta viene approvata, e (b) aggiungersi al registro IoT dei dispositivi. La richiesta può facoltativamente includere un identificatore univoco del dispositivo, ad esempio un numero di serie.
- Alla ricezione della richiesta di creazione del certificato, la piattaforma AWS IoT crea un nuovo certificato e ne consegna i file al dispositivo. Le permission IoT associate a ogni nuovo certificato, così come i vari attributi relativi al dispositivo appena registrato, si basano su un template che Lei crea e che AWS chiama 'fleet provisioning template'.
Questo template associa attributi ai dispositivi appena registrati, ad esempio {"DeviceType": "RaspberryPi"}, e consente inoltre di associare tutti i certificati univoci dei dispositivi alla stessa policy di permission, che è comunque in grado di definire permission specifiche per ciascun dispositivo.
Ad esempio, l'unica policy IoT di un template per i dispositivi registrati può essere costruita per consentire al dispositivo 'sensor123' di pubblicare messaggi solo sul topic IoT sensors/temp/sensor123, al dispositivo 'sensor456' di pubblicare messaggi solo sul topic IoT sensors/temp/sensor456, e così via. In altre parole, la policy di permission del fleet provisioning template Le evita di dover creare una nuova policy per ogni nuovo dispositivo e relativo certificato in fase di registrazione. Questo approccio Le permette inoltre di applicare modifiche alle permission a un'intera flotta IoT con un singolo aggiornamento della policy.
3. La creazione di un certificato per il dispositivo può facoltativamente essere subordinata a quello che AWS chiama "pre-provisioning hook". Si tratta di una funzione Lambda che Lei scrive e che può richiedere la presenza di un identificatore univoco nella richiesta di certificato, da verificare rispetto a una whitelist (ad esempio l'elenco di tutti i numeri di serie prodotti) e/o a una blacklist (ad esempio i numeri di serie associati a dispositivi compromessi o abusivi).
4. Se la richiesta viene approvata, i file del certificato vengono consegnati al dispositivo per essere usati nello streaming dei dati e il dispositivo viene inserito nel registro IoT con gli attributi del template. A quel punto il certificato di bootstrap non serve più al dispositivo.
Con questo flusso di lavoro, il produttore di dispositivi IoT deve semplicemente fornire ogni dispositivo con il certificato di bootstrap. Il certificato univoco che abilita lo streaming dei dati può essere creato e ottenuto immediatamente all'interno dello stabilimento, se lo si desidera, oppure in un secondo momento, quando il dispositivo è già nelle mani dell'utente finale. In ogni caso, il produttore installa sul dispositivo il software che Lei fornisce, il quale esegue il processo di creazione del certificato basato sul fleet provisioning template ogni volta che il dispositivo si avvia, è disponibile una connessione Internet e si rileva l'assenza di un certificato di dispositivo.
Esempio pratico di utilizzo del fleet provisioning template e del certificato di bootstrap
Sappiamo che si tratta di parecchie informazioni da assimilare; tutto risulterà più chiaro una volta messo in pratica il processo.
Qui sotto trova un esempio funzionante completo di come configurare il proprio registro IoT con dispositivi aggiunti tramite un fleet provisioning template e un certificato di bootstrap. Useremo poi i certificati dei dispositivi così creati per inviare in streaming i dati di temperatura alla piattaforma AWS IoT.
Inizi accedendo al servizio AWS IoT Core. Se non l'ha mai utilizzato, sarà accolto da una procedura guidata che Le chiederà di scegliere tra 'Onboard a device' o 'Onboard many devices'. La procedura ci accompagnerà attraverso il fleet provisioning template, ma a causa di una particolarità della wizard è meglio uscire da questa schermata e creare prima il certificato di bootstrap.
Sul lato sinistro della schermata vada su Secure → Certificates e clicchi su "Create", quindi scelga "One-click certificate creation". Verrà creato immediatamente un nuovo certificato che useremo come certificato di bootstrap. Si assicuri di scaricare il certificato (cert.pem), la chiave privata (private.key) e la root certificate authority (segua il link Download e salvi il file AmazonRootCA1.pem), quindi clicchi su 'Activate' per abilitare il certificato:

Una volta abilitato il certificato e scaricate le chiavi, clicchi su "Attach a policy". Creeremo una policy che trasformerà questo certificato in un certificato di bootstrap. Dalla schermata "Add authorization to certificate", clicchi su "Create New Policy" e crei una policy denominata "IoT_Bootstrapping_Certificate". Le assegneremo le permission per pubblicare, sottoscrivere e ricevere messaggi da e verso due topic riservati di AWS utilizzati per la creazione del certificato e per il fleet provisioning template:

Si ricordi di sostituire region, account ID e templateName con i valori specifici del Suo account
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/*
Clicchi su 'Create'. Una volta creata la policy del certificato, vada al certificato che ha creato e colleghi questa policy:


Ora che abbiamo un certificato di bootstrap pronto per i nostri dispositivi, torniamo alla procedura guidata del fleet provisioning template. Vi accederà cliccando su Onboard → Get started.
Dalla wizard scelga "Onboard many devices" e inserisca i seguenti valori:

- Template name: "SensorTemplate"
- Provisioning role: crei un ruolo denominato "IoTProvisioningRole" e lo associ alla policy gestita da AWS "AWSIoTThingsRegistration". Questo ruolo consente alla piattaforma AWS IoT di registrare i nuovi dispositivi al momento della connessione.
- In uno scenario reale scriverebbe una funzione Lambda di pre-provisioning hook che convalida il numero di serie prima di consentire la creazione di un certificato per il dispositivo, ma per brevità lasceremo invariata questa opzione. Potrebbe ad esempio usarla per confrontare un numero di serie con tabelle DynamoDB di numeri di serie noti o inseriti in blacklist. Di seguito un semplice esempio di come potrebbe apparire:
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}
- Selezioni l'opzione facoltativa "Use the AWS IoT registry to manage your device fleet". Le consentirà di visualizzare i dispositivi associati nella console web IoT e di inviare aggiornamenti allo stato o al software del dispositivo.
Nella pagina successiva definiremo una policy IoT, associata al template, che assegna ai nostri dispositivi le permission per pubblicare e ricevere messaggi da un topic IoT specifico per ciascun dispositivo. Creeremo la policy IoT utilizzando una thing policy variable. Le thing policy variable consentono ai dispositivi di pubblicare o ricevere messaggi da un topic IoT univoco per il singolo dispositivo. In questo esempio, i dispositivi pubblicheranno e si iscriveranno a un topic basato su BuildingName, Location (all'interno dell'edificio) e 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}
Nella pagina successiva, definisca le impostazioni del Suo registro AWS IoT — sono gli attributi assegnati a ciascun dispositivo appena fornito:

- Thing name prefix: sensor_
- Crei un nuovo Thing Type 'TemperatureSensor' con un Searchable Thing Attribute 'Location' (es. 'loft', 'downstairs') e "BuildingName" (es. 'home417')
- Crei i seguenti attributi non ricercabili: 'DeviceType' (es. 'RaspberryPi') e 'ModelNumber' (es. '3')
Nella schermata finale, dopo aver cliccato su "Create template", selezioni il certificato di bootstrap creato in precedenza, clicchi su "Attach policy" e quindi su 'Enable template'. Questa associazione consente ora ai dispositivi che utilizzano il certificato di bootstrap di sfruttare il template per ottenere un certificato di dispositivo con le permission necessarie a pubblicare messaggi su un topic IoT specifico per il nome del dispositivo. Oltre a ottenere il certificato, il dispositivo si serve del fleet provisioning template anche per inserirsi nel registro IoT e ricevere gli attributi che abbiamo definito.

Ricapitolando, abbiamo appena fatto quanto segue:
- Creato un certificato di bootstrap, associandolo a una policy che consente a un dispositivo che utilizza tale certificato solo di effettuare una richiesta tramite un Fleet Provisioning Template per (1) ottenere un nuovo certificato univoco e (2) essere aggiunto al registro IoT con gli attributi predefiniti.
- I certificati creati per i dispositivi appena registrati sono associati a una IoT Policy che consente al dispositivo di pubblicare e ricevere messaggi da un topic IoT specifico per quel dispositivo.
Il lavoro preparatorio sul servizio IoT è quasi terminato. Resta soltanto da aggiornare il fleet provisioning template affinché accetti e richieda gli attributi ricercabili durante la richiesta di provisioning. Torni a "SensorTemplate" e aggiunga al JSON del template quanto segue:
# 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": [],
Abbiamo apportato molte modifiche nella console IoT. Verifichiamo ora, con esempi di codice pratici, che il certificato di bootstrap e il fleet provisioning template funzionino correttamente.
Test di connettività dei dispositivi e streaming dei dati di temperatura
Copi i file del certificato che ha scaricato in una cartella sui Suoi dispositivi RPi, quindi crei il file config.ini riportato di seguito con i valori appropriati. Oltre ad aggiornare i percorsi dei file del certificato, dovrà recuperare l'IoT Endpoint del Suo account dalla pagina Settings nella console 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 questo punto esegua lo script seguente, che usa il certificato di bootstrap per ottenere un certificato di dispositivo (salvato in iot_certs/permanent_cert/) e aggiunge il dispositivo al registro IoT. Con il parametro -l indichi l'attributo Location associato al punto della casa in cui sarà collocato il dispositivo. Ad esempio:
./connect_rpi_to_iot_core.py -c config.ini -b home417 -l loft
Qui succedono molte cose, quindi consiglio vivamente di prendersi il tempo di esaminare il codice per capire la sequenza di chiamate API dell'SDK IoT. Se ha configurato tutto correttamente, vedrà lo script terminare con "Success" stampato a schermo, troverà tre file di certificato all'interno di permanent_cert/ e un nuovo file perm_config.ini nella stessa cartella per i file del certificato del dispositivo.
Noterà che, mano a mano che aggiunge i Suoi dispositivi RPi tramite questo script, nella console IoT compaiono nuovi certificati, tutti associati all'unica policy IoT che abbiamo definito nel fleet provisioning template, che abilita la pubblicazione di messaggi e la sottoscrizione a un topic basato su BuildingName, Location e ThingName.
Ogni dispositivo aggiunto dallo script viene registrato con ThingName sensor_{UUID}, dove UUID è un identificatore univoco fornito da /etc/machine-id sul dispositivo. Di conseguenza, ogni dispositivo pubblicherà messaggi sul proprio topic IoT univoco. In uno scenario IoT reale, potrebbe utilizzare il numero di serie del dispositivo come ThingName univoco.
Testiamo i certificati dei dispositivi con valori di temperatura simulati. Esegua lo script seguente, che (1) pubblica numeri casuali sul topic IoT del dispositivo e (2) si iscrive allo stesso topic e stampa a video i valori ricevuti.
./pubsub_simulated_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
Dovrebbe vedere un output simile al seguente:

Congratulazioni: ha appena completato con successo l'onboarding di una piccola flotta di dispositivi IoT seguendo la metodologia AWS pensata per gestire questo processo di registrazione in modo sicuro e su larga scala.
Per testare le connessioni con dati reali, esegua lo script seguente. È simile al precedente, con due differenze: (1) non si iscrive al topic su cui pubblica e (2) invia valori di temperatura reali ogni cinque secondi:
./publish_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
L'output dovrebbe apparire come segue:

Se esegue questo script al riavvio tramite un job crontab (preceduto da uno sleep di 30s per consentire il caricamento dei moduli onewire al boot), il Suo dispositivo IoT riprenderà lo streaming in caso di riavvio (in)atteso:
$ crontab -e
@reboot sleep 30 && /home/pi/publish_temps.py -c /home/pi/iot_certs/permanent_cert/perm_config.ini
Ripeta i processi di onboarding e di streaming per tutti i Raspberry Pi distribuiti in casa. È sulla buona strada per gestire dati IoT su larga scala.
Prossimo passo: archiviazione e visualizzazione
Non perda la parte 2, in cui parlerò della corretta archiviazione e visualizzazione di dati IoT in streaming su larga scala.
Avvertenza
L'approccio pub/sub per la pubblicazione dei messaggi adottato sopra funziona al meglio nei casi di telemetria dei dispositivi, in cui i dati trasmessi vengono utilizzati non solo da un'app di analytics di backend, ma anche direttamente dagli utenti finali, ad esempio tramite un'app che permette loro di consultare i valori di temperatura della propria abitazione. Se i dati in streaming saranno utilizzati solo da un'app di backend, è più conveniente pubblicare i messaggi tramite l'approccio "IoT Basic Ingest" descritto nel documento AWS IoT Core Best Practices for Designing MQTT Topics. Pubblicando i messaggi su un topic associato a una IoT Rule anziché a un topic IoT Core generico, perde la possibilità di iscriversi al topic, ma in cambio non dovrà pagare la componente di messaggistica del pricing IoT.