AWS IoT fornisce comunicazione sicura e bidirezionale tra dispositivi connessi a Internet come sensori, attuatori, microcontrollori incorporati o elettrodomestici intelligenti e il Cloud AWS. Ciò consente di raccogliere dati di telemetria da più dispositivi, archiviarli e analizzarli. È anche possibile creare applicazioni che consentano agli utenti di controllare questi dispositivi dai propri telefoni o tablet.
Fornisce un meccanismo sicuro per dispositivi e applicazioni AWS IoT per pubblicare e ricevere messaggi l'uno dall'altro. È possibile utilizzare direttamente il protocollo MQTT oppure MQTT su WebSocket per pubblicare e sottoscrivere.
L'AWS IoT message broker è un servizio broker publish/subscribe che consente l'invio e la ricezione di messaggi da e verso AWS IoT. Quando comunica con AWS IoT, un client invia un messaggio indirizzato a un topic come Sensor/temp/room1.
Il message broker, a sua volta, invia il messaggio a tutti i client che si sono registrati per ricevere messaggi su quel topic. L'atto di inviare il messaggio è denominato pubblicazione. L'atto di registrarsi per ricevere messaggi su un filtro di topic è denominato sottoscrizione.
Lo spazio dei nomi dei topic è isolato per ogni coppia account e regione AWS. Per esempio, il topic Sensor/temp/room1 per un account AWS è indipendente dal topic Sensor/temp/room1 per un altro account AWS. Questo vale anche per le regioni. Il topic Sensor/temp/room1 nello stesso account AWS in us-east-1 è indipendente dallo stesso topic in us-east-2. AWS IoT non supporta l'invio e la ricezione di messaggi tra account e regioni AWS diversi.
Il broker di messaggi mantiene un elenco di tutte le sessioni client e delle sottoscrizioni per ciascuna sessione. Quando viene pubblicato un messaggio su un argomento, il broker verifica le sessioni con sottoscrizioni corrispondenti all'argomento. Il broker inoltra quindi il messaggio pubblicato a tutte le sessioni che hanno un client attualmente connesso.
TsgcIoTAmazon_MQTT_Client è il componente utilizzato per connettersi ad AWS IoT. Un client può connettersi a un solo dispositivo. Il client si connette utilizzando il protocollo MQTT semplice e si autentica utilizzando un certificato client X.509.
Per connettersi ad AWS IoT, il client necessita delle seguenti proprietà:
Amazon.ClientId: identificazione del client, facoltativa.
Amazon.Endpoint: nome del server a cui si connetterà il client MQTT.
Amazon.Port: per impostazione predefinita utilizza la porta 8883. Se la porta è 443, utilizza ALPN automaticamente per la connessione (richiede la versione Indy personalizzata).
AWS IoT Core supporta dispositivi e client che utilizzano i protocolli MQTT e MQTT over WebSocket Secure (WSS) per pubblicare e sottoscrivere messaggi. La tabella seguente elenca i protocolli supportati dagli endpoint del dispositivo AWS IoT e i metodi di autenticazione e le porte utilizzati.
| Protocol | Authentication | Port | Nome del protocollo ALPN |
| MQTT su WebSocket | Signature Version 4 | 443 | |
| MQTT su WebSocket | Autenticazione personalizzata | 443 | |
| MQTT | Certificato client X.509 | 443 | x-amzn-mqtt-ca |
| MQTT | Certificato client X.509 | 8883 | |
| MQTT | Autenticazione personalizzata | 443 | mqtt |
È necessario creare certificati nella console Amazon AWS e impostare il percorso in cui sono archiviati.
Utilizzando OpenSSL come IOHandler è necessario impostare il certificato nei seguenti percorsi
Certificate.Enabled: imposti su True se desidera utilizzare i certificati.
Certificate.CertFile: percorso del certificato client X.509.
Certificate.KeyFile: percorso del file chiave client X.509.
Utilizzando SChannel come IOHandler, convertire prima il certificato PEM + chiave in un certificato PFX. Questa operazione richiede i binari OpenSSL:
openssl pkcs12 -inkey 884ccf73ff-private.pem.key -in 884ccf73ff-certificate.pem.crt -export -out 884ccf73ff-certificate.pfx
Quindi impostare i seguenti percorsi (non è necessario impostare il file della chiave perché è già incluso nel certificato).
Certificate.Enabled: imposti su True se desidera utilizzare i certificati.
Certificate.CertFile: percorso del certificato PFX
È necessario creare un utente nella console Amazon AWS e salvare le chiavi di accesso e segrete, che verranno utilizzate per firmare la richiesta WebSocket.
SignatureV4.Enabled: impostare su True se si desidera utilizzare questo tipo di autenticazione.
SignatureV4.Region: la regione in cui si trova il Suo dispositivo (esempio: us-east-1).
SignatureV4.AccessKey: la chiave di accesso creata nella console Amazon o ottenuta come credenziale temporanea.
SignatureV4.SecretKey: la chiave segreta creata nella console Amazon o ottenuta come credenziale temporanea
SignatureV4.SessionToken: (condizionale) se si utilizzano credenziali di sicurezza temporanee, impostare qui il token di sicurezza.
OpenSSL_Options: configurazione delle librerie openSSL.
APIVersion: consente di definire quale API OpenSSL verrà utilizzata.
oslAPI_1_0: utilizza l'API OpenSSL 1.0, l'ultima supportata da Indy
oslAPI_1_1: utilizza OpenSSL API 1.1, richiede la nostra libreria Indy personalizzata e consente l'utilizzo delle librerie OpenSSL 1.1.1 (con supporto TLS 1.3).
oslAPI_3_0: utilizza l'API 3.0 OpenSSL, richiede la nostra libreria Indy personalizzata e consente l'uso delle librerie OpenSSL 3.0.0 (con supporto TLS 1.3).
LibPath: qui è possibile configurare la posizione delle librerie openSSL
oslpNone: questa è l'impostazione predefinita; le librerie openSSL devono trovarsi nella stessa cartella del binario o in un percorso noto.
oslpDefaultFolder: imposta automaticamente il percorso openSSL dove le librerie devono essere situate per tutte le personalità IDE.
oslpCustomFolder: se questa è l'opzione selezionata, definire il percorso completo nella proprietà LibPathCustom.
LibPathCustom: quando LibPath = oslpCustomFolder, definire qui il percorso completo dove si trovano le librerie openSSL.
UnixSymLinks: abilita o disabilita il caricamento dei SymLink sui sistemi Unix (per impostazione predefinita è abilitato, tranne che su OSX64):
oslsSymLinksDefault: per impostazione predefinita sono abilitati, eccetto su OSX64 (dopo MacOS Monterey si verifica un errore nel tentativo di caricare la libreria senza versione.).
oslsSymLinksLoadFirst: Carica i SymLink e li elabora prima di tentare il caricamento delle librerie di versione.
oslsSymLinksLoad: Carica i SymLink dopo aver tentato di caricare le librerie di versione.
oslsSymLinksDontLoad: non caricare i SymLink.
*SignatureV4 richiede Indy 10.5.7+
L'autenticazione personalizzata consente di definire come autenticare e autorizzare i client utilizzando risorse di autorizzazione. Il dispositivo trasmette le credenziali nei campi header della richiesta o nei parametri di query (per i protocolli MQTT su WebSockets) oppure nei campi nome utente e password del messaggio MQTT CONNECT (per i protocolli MQTT e MQTT su WebSockets).
CustomAuthentication.Enabled: impostare a True se si desidera utilizzare questo tipo di autenticazione.
CustomAuthentication.Parameters: impostare qui i parametri di query che verranno passati al server (per impostazione predefinita è /mqtt)
CustomAuthentication.Headers: qui è possibile inserire i campi di intestazione personalizzati.
CustomAuthentication.WebSockets: se impostato a true, la connessione funzionerà tramite il protocollo WebSocket, altrimenti funzionerà tramite TCP semplice.
MQTTAuthentication.Enabled: se è necessario passare nome utente/password nella connessione mqtt, abilitare questa proprietà
MQTTAuthentication.Username: nome utente della connessione MQTT
MQTTAuthentication.Password: segreto della connessione mqtt.
Il client può inviare facoltativamente un ClientId per identificare la connessione client; altri client possono quindi iscriversi per ricevere una notifica ogni volta che questo client si connette, si iscrive, si disconnette...
Se non è possibile connettersi utilizzando la porta 8883 e si utilizza TCP come trasporto (che è quello predefinito), Amazon utilizza la "AWS IoT Core policy" per fornire o meno l'autorizzazione ai client e alle sottoscrizioni. Molto probabilmente è necessario autorizzare il proprio client id.
Accedere alla console Amazon AWS, selezionare IoT Core e aprire il menu "Secure/Policies"; selezionare quindi il criterio collegato al proprio IoT Thing e verificare in fondo come è configurata la connessione. Esempio:
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": [
"arn:aws:iot:us-east-1:222178873557:client/sdk-java",
"arn:aws:iot:us-east-1:222178873557:client/basicPubSub",
"arn:aws:iot:us-east-1:222178873557:client/sdk-nodejs-*"
]
}
Questa configurazione significa che solo i client con ID: sdk-java, basicPubSub e sdk-nodejs-* saranno autorizzati a connettersi. Modificare di conseguenza e riprovare.
Se ancora non funziona, abiliti il log e verifichi in cloudwatch il motivo per cui non riesce a connettersi.
MQTTHeartBeat: se abilitato, tenta di mantenere attiva la connessione MQTT inviando un ping ogni x secondi.
Interval: numero di secondi tra ogni ping.
MQTTAuthentication: se abilitato, include nella connessione MQTT il nome utente e la password
UserName: nome dell'utente
Password: stringa segreta
WatchDog: se abilitato, quando viene rilevata una disconnessione inattesa, tenta di riconnettersi automaticamente al server.
Interval: secondi prima dei tentativi di riconnessione.
Attempts: numero massimo di tentativi di riconnessione; zero significa illimitato.
LogFile: se abilitato, salva i messaggi del socket in un file di log (utile per il debugging). L'accesso al file di log non è thread safe se vi si accede da più thread.
Enabled: se abilitato, ogni messaggio ricevuto e inviato tramite socket verrà salvato su un file.
FileName: percorso completo al nome del file.
L'implementazione Amazon MQTT è basata su MQTT versione 3.1.1 ma si discosta dalla specifica come segue:
In AWS IoT, la sottoscrizione a un argomento con Quality of Service (QoS) 0 significa che un messaggio viene recapitato zero o più volte. Un messaggio potrebbe essere recapitato più di una volta. I messaggi recapitati più di una volta potrebbero essere inviati con un ID pacchetto diverso. In questi casi, il flag DUP non viene impostato.
AWS IoT non supporta la pubblicazione e la sottoscrizione con QoS 2. Il message broker di AWS IoT non invia un PUBACK o un SUBACK quando viene richiesto QoS 2.
Quando risponde a una richiesta di connessione, il message broker invia un messaggio CONNACK. Questo messaggio contiene un flag che indica se la connessione sta riprendendo una sessione precedente. Il valore di questo flag potrebbe essere errato se due client MQTT si connettono contemporaneamente con lo stesso client ID.
Quando un client si iscrive a un argomento, potrebbe verificarsi un ritardo tra il momento in cui il broker di messaggi invia un SUBACK e il momento in cui il client inizia a ricevere nuovi messaggi corrispondenti.
La specifica MQTT prevede una disposizione per cui il publisher può richiedere al broker di conservare l'ultimo messaggio inviato a un topic e inviarlo a tutti i futuri sottoscrittori del topic. AWS IoT non supporta i messaggi trattenuti (retained). Se viene effettuata una richiesta per trattenere messaggi, la connessione viene disconnessa.
Il message broker utilizza il client ID per identificare ogni client. Il client ID viene passato dal client al message broker come parte del payload MQTT. Due client con lo stesso client ID non possono essere connessi contemporaneamente al message broker. Quando un client si connette al message broker utilizzando un client ID già in uso da un altro client, un messaggio CONNACK viene inviato a entrambi i client e il client attualmente connesso viene disconnesso.
In rare occasioni, il message broker potrebbe inviare nuovamente lo stesso messaggio PUBLISH logico con un ID pacchetto diverso.
Il message broker non garantisce l'ordine in cui vengono ricevuti i messaggi e gli ACK.
Per prima cosa, deve accedere alla Sua console AWS, registrare un nuovo dispositivo e creare un certificato X.509 per questo dispositivo. Una volta fatto, può creare un nuovo TsgcIoTAmazon_MQTT_Client e connettersi al server AWS IoT. Ad esempio:
oClient := TsgcIoTAmazon_MQTT_Client.Create(nil);
oClient.Amazon.Endpoint := 'a2ohgdjqitsmij-ats.iot.us-west-2.amazonaws.com';
oClient.Amazon.ClientId := 'sgcWebSockets';
oClient.Certificate.CertFile := 'amazon-certificate.pem.crt';
oClient.Certificate.KeyFile := 'amazon-private.pem.key';
oClient.OnMQTTConnect := OnMQTTConnectEvent;
oClient.Active := True;
procedure OnMQTTConnect(Connection: TsgcWSConnection; const Session: Boolean; const ReturnCode: TmqttConnReturnCode);
begin
ShowMessage('Connected to AWS');
end;
Il message broker utilizza i topic per instradare i messaggi dai client publisher ai client subscriber. La barra (/) viene utilizzata per separare la gerarchia dei topic. La tabella seguente elenca i caratteri jolly che possono essere utilizzati nel filtro dei topic al momento della sottoscrizione. # Deve essere l'ultimo carattere nel topic a cui ci si iscrive. Funziona come jolly corrispondendo all'albero corrente e a tutti i sottoalberi.
Ad esempio, una sottoscrizione a Sensor/# riceve i messaggi pubblicati su Sensor/, Sensor/temp, Sensor/temp/room1, ma non i messaggi pubblicati su Sensor.
+ corrisponde esattamente a un elemento nella gerarchia degli argomenti. Ad esempio, una sottoscrizione a Sensor/+/room1 riceve messaggi pubblicati su Sensor/temp/room1, Sensor/moisture/room1 e così via.
oClient := TsgcIoTAmazon_MQTT_Client.Create(nil);
...
oClient.OnSubscribe := OnSubscribeEvent;
vPacketIdentifier := oClient.Subscribe('Sensor/moisture/room1');
procedure OnMQTTSubscribe(Connection: TsgcWSConnection; aPacketIdentifier: Word; aCodes: TsgcWSSUBACKS);
begin
if vPacketIdentifier = aPacketIdentifier then
ShowMessage('Subscribed to topic Sensor/moisture/room1');
end;
// Client, can send a message using Publish method.
oClient.Publish('Sensor/moisture/room1', '{"temp"=10}');
// Messages received from server, are dispatched OnMQTTPublishEvent.
// For extended payload access (string, bytes or stream), use OnMQTTPublishEx.
procedure OnMQTTPublish(Connection: TsgcWSConnection; aTopic, aText: string);
begin
DoLog('Received Message: ' + aTopic + ' ' + aText);
end;
I seguenti metodi vengono utilizzati per sottoscrivere/pubblicare su topic riservati.
Subscribe_ClientConnected(const aClientId: String): AWS IoT pubblica su questo topic quando un client MQTT con l'ID client specificato si connette ad AWS IoT
Subscribe_ClientDisconnected(const aClientId: String): AWS IoT pubblica su questo topic quando un client MQTT con l'ID client specificato si disconnette da AWS IoT
Subscribe_ClientSubscribed(const aClientId: String): AWS IoT pubblica su questo argomento quando un client MQTT con l'ID client specificato si iscrive a un argomento MQTT
Subscribe_ClientUnSubscribed(const aClientId: String): AWS IoT pubblica su questo topic quando un client MQTT con il client ID specificato annulla l'iscrizione a un topic MQTT
Publish_Rule(const aRuleName, aText: String): Un dispositivo o un'applicazione pubblica su questo topic per attivare le regole direttamente
Publish_DeleteShadow(const aThingName, aText: String): Un dispositivo o un'applicazione pubblica su questo topic per eliminare un shadow
Subscribe_DeleteShadow(const aThingName: String): Un dispositivo o un'applicazione si iscrive a questo topic per eliminare uno shadow
Subscribe_ShadowDeleted(const aThingName: String): Il servizio Device Shadow invia messaggi a questo topic quando un'ombra viene eliminata
Subscribe_ShadowRejected(const aThingName: String): Il servizio Device Shadow invia messaggi a questo topic quando una richiesta di eliminazione di uno shadow viene rifiutata
Publish_ShadowGet(const aThingName, aText: String): Un'applicazione o un dispositivo pubblica un messaggio vuoto su questo topic per ottenere uno shadow
Subscribe_ShadowGet(const aThingName: String): Un'applicazione o un dispositivo si iscrive a questo topic per ottenere uno shadow
Subscribe_ShadowGetAccepted(const aThingName: String): Il servizio Device Shadow invia messaggi a questo topic quando una richiesta di shadow viene effettuata con successo
Subscribe_ShadowGetRejected(const aThingName: String): Il servizio Device Shadow invia messaggi a questo topic quando una richiesta per uno shadow viene rifiutata
Publish_ShadowUpdate(const aThingName, aText: String): Un oggetto o un'applicazione pubblica su questo argomento per aggiornare un'ombra
Subscribe_ShadowUpdateAccepted(const aThingName: String): Il servizio Device Shadow invia messaggi a questo argomento quando un aggiornamento viene applicato con successo a un shadow
Subscribe_ShadowUpdateRejected(const aThingName: String): Il servizio Device Shadow invia messaggi a questo topic quando un aggiornamento a uno shadow viene rifiutato
Subscribe_ShadowUpdateDelta(const aThingName: String): Il servizio Device Shadow invia messaggi a questo argomento quando viene rilevata una differenza tra le sezioni reported e desired di un shadow
Subscribe_ShadowUpdateDocuments(const aThingName: String): AWS IoT pubblica un documento di stato su questo topic ogni volta che un aggiornamento al shadow viene eseguito correttamente
Una sessione persistente rappresenta una connessione in corso a un broker di messaggi MQTT. Quando un client si connette al broker di messaggi AWS IoT utilizzando una sessione persistente, il broker di messaggi salva tutte le sottoscrizioni effettuate dal client durante la connessione. Quando il client si disconnette, il broker di messaggi memorizza i messaggi QoS 1 non confermati e i nuovi messaggi QoS 1 pubblicati sui topic a cui il client è sottoscritto. Quando il client si riconnette alla sessione persistente, tutte le sottoscrizioni vengono ripristinate e tutti i messaggi memorizzati vengono inviati al client a una frequenza massima di 10 messaggi al secondo.
Si crea una sessione MQTT persistente impostando il parametro cleanSession su False nell'evento OnMQTTBeforeConnect. Se non esiste alcuna sessione per il client, viene creata una nuova sessione persistente. Se esiste già una sessione per il client, viene ripresa.
I dispositivi devono verificare l'attributo Session nell'evento OnMQTTConnect per determinare se è presente una sessione persistente. Se Session è True, è presente una sessione persistente e i messaggi memorizzati vengono consegnati al client. Se Session è False, non è presente alcuna sessione persistente e il client deve ri-sottoscriversi ai propri filtri di argomento.
Le sessioni persistenti hanno un periodo di scadenza predefinito di 1 ora. Il periodo di scadenza inizia quando il message broker rileva che un client si disconnette (disconnessione MQTT o timeout). Il periodo di scadenza della sessione persistente può essere aumentato tramite il processo standard di aumento del limite. Se un client non ha ripreso la propria sessione entro il periodo di scadenza, la sessione viene terminata e tutti i messaggi archiviati associati vengono eliminati. Il periodo di scadenza è approssimativo: le sessioni potrebbero essere mantenute fino a 30 minuti in più (ma non meno) rispetto alla durata configurata.
AWS IoT Core può funzionare con credenziali temporanee ottenute tramite Identity Pool; esistono 2 tipi di identità:
Se si utilizzano credenziali non autenticate, collegare semplicemente la policy nel ruolo UnAuthenticated creato automaticamente nel menu IAM. Quindi configurare il client impostando Access, Secret Key e Token restituiti dal servizio Cognito.
Di seguito è riportato un codice in .NET per ottenere credenziali non autenticate
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
"us-east-1:cc3c9c48-646d-44ef-bfd5-0c5fb2f0882f", // Identity pool ID
Amazon.RegionEndpoint.USEast1 // Region
);
var identityPoolId = credentials.GetCredentialsAsync();
AmazonCognitoIdentityClient cognitoClient = new AmazonCognitoIdentityClient(
credentials, // the anonymous credentials
Amazon.RegionEndpoint.USEast1 // the Amazon Cognito region
);
GetIdRequest idRequest = new GetIdRequest();
idRequest.AccountId = "222178873557";
idRequest.IdentityPoolId = "us-east-1:cc3c9c48-646d-44ef-bfd5-0c5fb2f0882f";
GetIdResponse idResp = cognitoClient.GetId(idRequest);
string AccessKey = identityPoolId.Result.AccessKey;
string SecretKey = identityPoolId.Result.SecretKey;
string SessionToken = identityPoolId.Result.Token;
string IdentityId = idResp.IdentityId;
Credenziali autenticate, richiede di collegare la policy nell'Authenticated Role creato automaticamente nel menu IAM e di collegare la policy dell'utente nelle policy di AWS IoT Core.
Creare quindi una nuova policy nel menu delle policy di IoT Core e, ogni volta che un nuovo utente si autentica, associare questa policy a tale utente.
È possibile utilizzare il seguente comando di AWS per allegare una policy o creare una funzione lambda.
aws iot attach-policy --policy-name PolicyName --target us-east-1:XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Il servizio Fleet Provisioning supporta le seguenti operazioni dell'API MQTT:
CreateCertificateFromCsr
Utilizzare il metodo CreateCertificateFromCsr passando il CertificateSigningRequest come parametro per creare il certificato. Per ricevere la risposta a questa richiesta, sottoscrivere prima i seguenti metodi: SubscribeCreateCertificateFromCsrResponse e SubscribeCreateCertificateFromCsrError
CreateKeysAndCertificate
Utilizzare il metodo CreateKeysAndCertificate per creare un nuovo certificato e nuove chiavi. Per ricevere la risposta a questa richiesta, sottoscrivere prima i seguenti metodi SubscribeCreateKeysAndCertificateResponse e SubscribeCreateKeysAndCertificateError
RegisterThing
Utilizzi il metodo RegisterThing per registrare un nuovo thing passando come parametri il nome del template e il payload in formato JSON. Per ricevere la risposta a questa richiesta, occorre prima iscriversi ai seguenti metodi: SubscribeRegisterThingResponse e SubscribeRegisterThingError.