O AWS IoT fornece comunicação segura e bidirecional entre dispositivos conectados à Internet, como sensores, atuadores, microcontroladores embarcados ou eletrodomésticos inteligentes, e a Nuvem AWS. Isto permite que você colete dados de telemetria de múltiplos dispositivos, e armazene e analise os dados. Você também pode criar aplicações que permitam que seus usuários controlem esses dispositivos a partir de seus telefones ou tablets.
Fornece um mecanismo seguro para que dispositivos e aplicações AWS IoT publiquem e recebam mensagens entre si. Você pode usar o protocolo MQTT diretamente ou MQTT sobre WebSocket para publicar e assinar.
O message broker do AWS IoT é um serviço de broker publish/subscribe que permite o envio e o recebimento de mensagens de e para o AWS IoT. Ao se comunicar com o AWS IoT, um cliente envia uma mensagem endereçada a um tópico como Sensor/temp/room1.
O message broker, por sua vez, envia a mensagem a todos os clientes que se registraram para receber mensagens daquele tópico. O ato de enviar a mensagem é chamado de publicação. O ato de registrar-se para receber mensagens de um filtro de tópico é chamado de assinatura.
O namespace de tópicos é isolado para cada par de conta e região AWS. Por exemplo, o tópico Sensor/temp/room1 de uma conta AWS é independente do tópico Sensor/temp/room1 de outra conta AWS. Isso também vale para as regiões. O tópico Sensor/temp/room1 na mesma conta AWS em us-east-1 é independente do mesmo tópico em us-east-2. O AWS IoT não suporta o envio e recebimento de mensagens entre contas e regiões AWS.
O message broker mantém uma lista de todas as sessões de cliente e as assinaturas de cada sessão. Quando uma mensagem é publicada em um tópico, o broker verifica as sessões com assinaturas que mapeiam para o tópico. O broker então encaminha a mensagem de publicação para todas as sessões que têm um cliente atualmente conectado.
TsgcIoTAmazon_MQTT_Client é o componente usado para conectar ao AWS IoT. Um cliente pode conectar a apenas um dispositivo. O cliente conecta usando o protocolo MQTT simples e autentica usando um Certificado de Cliente X.509.
Para conectar ao AWS IoT, o cliente precisa das seguintes propriedades:
Amazon.ClientId: identificação do cliente, opcional.
Amazon.Endpoint: nome do servidor onde o cliente MQTT se conectará.
Amazon.Port: por padrão utiliza a porta 8883. Se a porta for 443, utiliza ALPN automaticamente para conectar (Requer versão Indy personalizada).
O AWS IoT Core suporta dispositivos e clientes que usam os protocolos MQTT e MQTT over WebSocket Secure (WSS) para publicar e assinar mensagens. A tabela a seguir lista os protocolos que os endpoints de dispositivo do AWS IoT suportam e os métodos de autenticação e portas que utilizam.
| Protocol | Authentication | Port | ALPN Protocol Name |
| MQTT sobre WebSocket | Signature Version 4 | 443 | |
| MQTT sobre WebSocket | Custom Authentication | 443 | |
| MQTT | Certificado de cliente X.509 | 443 | x-amzn-mqtt-ca |
| MQTT | Certificado de cliente X.509 | 8883 | |
| MQTT | Custom Authentication | 443 | mqtt |
Você precisa criar certificados em seu console Amazon AWS e definir o caminho onde eles estão armazenados.
Utilizando OpenSSL como IOHandler, você deve definir o certificado nos seguintes caminhos
Certificate.Enabled: defina como True se você quiser utilizar certificados.
Certificate.CertFile: caminho para o certificado de cliente X.509.
Certificate.KeyFile: caminho para o arquivo de chave cliente X.509.
Usando SChannel como IOHandler, primeiro converta o Certificado PEM + Chave para um certificado PFX. Isso requer os binários do OpenSSL:
openssl pkcs12 -inkey 884ccf73ff-private.pem.key -in 884ccf73ff-certificate.pem.crt -export -out 884ccf73ff-certificate.pfx
Em seguida, defina os seguintes caminhos (não é necessário definir o arquivo de chave porque ele já está incluído no certificado).
Certificate.Enabled: defina como True se você quiser utilizar certificados.
Certificate.CertFile: caminho para o certificado PFX
Você precisa criar um usuário no seu console Amazon AWS e salvar as chaves Access e Secret, que serão usadas para assinar a requisição WebSocket.
SignatureV4.Enabled: defina como True se você quiser utilizar este tipo de autenticação.
SignatureV4.Region: a região onde seu dispositivo está localizado (exemplo: us-east-1).
SignatureV4.AccessKey: a access key criada em seu console Amazon ou obtida como credencial temporária.
SignatureV4.SecretKey: a chave secreta criada no seu console da amazon ou obtida como credencial temporária
SignatureV4.SessionToken: (condicional) se você estiver utilizando Temporary Security Credentials, defina aqui o token de segurança.
OpenSSL_Options: configuração das bibliotecas openSSL.
APIVersion: permite definir qual API OpenSSL será usada.
oslAPI_1_0: usa a API 1.0 do OpenSSL, é a mais recente suportada pelo Indy
oslAPI_1_1: usa a API 1.1 do OpenSSL, requer nossa biblioteca Indy personalizada e permite usar as bibliotecas OpenSSL 1.1.1 (com suporte a TLS 1.3).
oslAPI_3_0: utiliza a API 3.0 do OpenSSL, requer nossa biblioteca Indy personalizada e permite utilizar as bibliotecas OpenSSL 3.0.0 (com suporte a TLS 1.3).
LibPath: aqui você pode configurar onde estão localizadas as bibliotecas openSSL
oslpNone: este é o padrão, as bibliotecas openSSL devem estar na mesma pasta onde está o binário ou em um caminho conhecido.
oslpDefaultFolder: define automaticamente o caminho openSSL onde as bibliotecas devem estar localizadas para todas as personalidades do IDE.
oslpCustomFolder: se esta for a opção selecionada, defina o caminho completo na propriedade LibPathCustom.
LibPathCustom: quando LibPath = oslpCustomFolder, defina aqui o caminho completo onde estão localizadas as bibliotecas openSSL.
UnixSymLinks: habilita ou desabilita o carregamento de SymLinks em sistemas Unix (por padrão está habilitado, exceto no OSX64):
oslsSymLinksDefault: por padrão estão habilitados, exceto sob OSX64 (após o MacOS Monterey falha ao tentar carregar a biblioteca sem versão.).
oslsSymLinksLoadFirst: Carrega os SymLinks e faz isso antes de tentar carregar as bibliotecas de versão.
oslsSymLinksLoad: Carrega os SymLinks após tentar carregar as bibliotecas de versão.
oslsSymLinksDontLoad: não carrega os SymLinks.
*SignatureV4 requer Indy 10.5.7+
A autenticação personalizada permite que você defina como autenticar e autorizar clientes utilizando recursos authorizer. O dispositivo passa as credenciais nos campos de cabeçalho da requisição ou em parâmetros de query (para os protocolos MQTT over WebSockets) ou nos campos de nome de usuário e senha da mensagem MQTT CONNECT (para os protocolos MQTT e MQTT over WebSockets).
CustomAuthentication.Enabled: defina como True se você quiser utilizar este tipo de Autenticação.
CustomAuthentication.Parameters: defina aqui os parâmetros de query que serão passados ao servidor (por padrão é /mqtt)
CustomAuthentication.Headers: aqui você pode colocar os campos de cabeçalho personalizados.
CustomAuthentication.WebSockets: se definido como true, a conexão funcionará sobre o protocolo WebSocket, caso contrário funcionará sobre TCP puro.
MQTTAuthentication.Enabled: se você precisar passar o nome de usuário/senha na conexão mqtt, habilite esta propriedade
MQTTAuthentication.Username: nome de usuário da conexão mqtt
MQTTAuthentication.Password: segredo da conexão mqtt.
O cliente pode enviar opcionalmente um ClientId para identificar a conexão do cliente; então, outros clientes podem se inscrever para receber uma notificação toda vez que este cliente conectar, se inscrever, desconectar...
Se você não conseguir conectar utilizando a porta 8883 e utilizar TCP como transporte (que é o padrão), a amazon utiliza a "AWS IoT Core policy" para fornecer ou não autorização a clientes e inscrições. Muito provavelmente você deve autorizar seu client id.
Entre no seu console Amazon AWS, vá para o IoT Core e acesse o menu "Secure/Policies", lá selecione a política anexada ao seu IoT Thing e verifique no final como a conexão está configurada. Exemplo:
{
"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-*"
]
}
Esta configuração significa que apenas clientes com ID: sdk-java, basicPubSub e sdk-nodejs-* terão permissão para conectar. Altere de acordo e tente novamente.
Se ainda não funcionar, habilite o log e verifique no cloudwatch o motivo pelo qual você não consegue conectar.
MQTTHeartBeat: se habilitado, tenta manter a conexão MQTT ativa enviando um ping a cada x segundos.
Interval: número de segundos entre cada ping.
MQTTAuthentication: se habilitado, inclui na conexão MQTT o nome de usuário e a senha
UserName: nome do usuário
Senha: secret string
WatchDog: se habilitado, quando uma desconexão inesperada é detectada, tenta reconectar-se ao servidor automaticamente.
Interval: segundos antes das tentativas de reconexão.
Attempts: número máximo de tentativas de reconexão; zero significa ilimitado.
LogFile: se habilitado, salva as mensagens do socket em um arquivo de log (útil para depuração). O acesso ao arquivo de log não é thread safe se for acessado a partir de várias threads.
Enabled: se habilitado, cada vez que uma mensagem é recebida e enviada pelo socket ela será salva em um arquivo.
FileName: caminho completo para o nome do arquivo.
A implementação do Amazon MQTT é baseada na versão MQTT 3.1.1, mas desvia da especificação da seguinte forma:
No AWS IoT, assinar um tópico com Quality of Service (QoS) 0 significa que uma mensagem é entregue zero ou mais vezes. Uma mensagem pode ser entregue mais de uma vez. Mensagens entregues mais de uma vez podem ser enviadas com um packet ID diferente. Nesses casos, a flag DUP não é definida.
O AWS IoT não suporta publicação e assinatura com QoS 2. O broker de mensagens do AWS IoT não envia um PUBACK ou SUBACK quando QoS 2 é solicitado.
Ao responder a uma requisição de conexão, o message broker envia uma mensagem CONNACK. Esta mensagem contém uma flag para indicar se a conexão está retomando uma sessão anterior. O valor dessa flag pode estar incorreto se dois clientes MQTT se conectarem com o mesmo client ID simultaneamente.
Quando um cliente assina um tópico, pode haver um atraso entre o momento em que o message broker envia um SUBACK e o momento em que o cliente começa a receber novas mensagens correspondentes.
A especificação MQTT fornece uma disposição para que o publicador solicite que o broker retenha a última mensagem enviada a um tópico e a envie a todos os futuros assinantes do tópico. O AWS IoT não suporta mensagens retidas. Se for feita uma requisição para reter mensagens, a conexão é desconectada.
O message broker usa o client ID para identificar cada cliente. O client ID é passado do cliente para o message broker como parte do payload MQTT. Dois clientes com o mesmo client ID não podem estar conectados simultaneamente ao message broker. Quando um cliente se conecta ao message broker usando um client ID que outro cliente está usando, uma mensagem CONNACK é enviada a ambos os clientes e o cliente atualmente conectado é desconectado.
Em raras ocasiões, o message broker pode reenviar a mesma mensagem PUBLISH lógica com um id de pacote diferente.
O message broker não garante a ordem em que mensagens e ACK são recebidos.
Primeiro, você deve fazer login no seu console AWS, registrar um novo dispositivo e criar um certificado X.509 para esse dispositivo. Uma vez feito isso, você pode criar um novo TsgcIoTAmazon_MQTT_Client e conectar-se ao AWS IoT Server. Por exemplo:
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;
O message broker usa tópicos para rotear mensagens dos clientes publicadores para os clientes assinantes. A barra (/) é usada para separar a hierarquia de tópicos. A tabela a seguir lista os wildcards que podem ser usados no filtro de tópico quando você assina. # Deve ser o último caractere no tópico que você está assinando. Funciona como um wildcard correspondendo à árvore atual e a todas as subárvores.
Por exemplo, uma inscrição em Sensor/# recebe mensagens publicadas em Sensor/, Sensor/temp, Sensor/temp/room1, mas não as mensagens publicadas em Sensor.
+ Corresponde exatamente a um item na hierarquia de tópicos. Por exemplo, uma assinatura de Sensor/+/room1 recebe mensagens publicadas em Sensor/temp/room1, Sensor/moisture/room1 e assim por diante.
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;
Os métodos a seguir são utilizados para assinar / publicar em tópicos reservados.
Subscribe_ClientConnected(const aClientId: String): O AWS IoT publica neste tópico quando um cliente MQTT com o client ID especificado se conecta ao AWS IoT
Subscribe_ClientDisconnected(const aClientId: String): o AWS IoT publica neste tópico quando um cliente MQTT com o client ID especificado se desconecta do AWS IoT
Subscribe_ClientSubscribed(const aClientId: String): o AWS IoT publica neste tópico quando um cliente MQTT com o client ID especificado assina um tópico MQTT
Subscribe_ClientUnSubscribed(const aClientId: String): O AWS IoT publica neste tópico quando um cliente MQTT com o client ID especificado cancela a assinatura de um tópico MQTT
Publish_Rule(const aRuleName, aText: String): Um dispositivo ou uma aplicação publica neste tópico para acionar regras diretamente
Publish_DeleteShadow(const aThingName, aText: String): Um dispositivo ou uma aplicação publica neste tópico para excluir um shadow
Subscribe_DeleteShadow(const aThingName: String): Um dispositivo ou uma aplicação se inscreve neste tópico para excluir um shadow
Subscribe_ShadowDeleted(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando um shadow é excluído
Subscribe_ShadowRejected(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando uma requisição para excluir um shadow é rejeitada
Publish_ShadowGet(const aThingName, aText: String): Uma aplicação ou um thing publica uma mensagem vazia neste tópico para obter um shadow
Subscribe_ShadowGet(const aThingName: String): Uma aplicação ou um thing assina este tópico para obter um shadow
Subscribe_ShadowGetAccepted(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando uma requisição por um shadow é feita com sucesso
Subscribe_ShadowGetRejected(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando uma requisição de shadow é rejeitada
Publish_ShadowUpdate(const aThingName, aText: String): Um thing ou aplicação publica neste tópico para atualizar um shadow
Subscribe_ShadowUpdateAccepted(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando uma atualização é feita com sucesso em um shadow
Subscribe_ShadowUpdateRejected(const aThingName: String): O serviço Device Shadow envia mensagens a este tópico quando uma atualização de um shadow é rejeitada
Subscribe_ShadowUpdateDelta(const aThingName: String): O serviço Device Shadow envia mensagens para este tópico quando uma diferença é detectada entre as seções reported e desired de um shadow
Subscribe_ShadowUpdateDocuments(const aThingName: String): O AWS IoT publica um documento de estado neste tópico sempre que uma atualização do shadow é realizada com sucesso
Uma sessão persistente representa uma conexão contínua com um broker de mensagens MQTT. Quando um cliente conecta ao broker de mensagens do AWS IoT usando uma sessão persistente, o broker de mensagens salva todas as assinaturas que o cliente faz durante a conexão. Quando o cliente se desconecta, o broker de mensagens armazena as mensagens QoS 1 não confirmadas e as novas mensagens QoS 1 publicadas em tópicos aos quais o cliente está assinado. Quando o cliente reconecta à sessão persistente, todas as assinaturas são restabelecidas e todas as mensagens armazenadas são enviadas ao cliente a uma taxa máxima de 10 mensagens por segundo.
Você cria uma sessão MQTT persistente definindo o parâmetro cleanSession como False no evento OnMQTTBeforeConnect. Se não existir sessão para o cliente, uma nova sessão persistente é criada. Se já existir uma sessão para o cliente, ela é retomada.
Os dispositivos precisam olhar o atributo Session no evento OnMQTTConnect para determinar se uma sessão persistente está presente. Se Session for True, uma sessão persistente está presente e as mensagens armazenadas são entregues ao cliente. Se Session for False, nenhuma sessão persistente está presente e o cliente deve assinar novamente seus filtros de tópico.
As sessões persistentes têm um período de expiração padrão de 1 hora. O período de expiração começa quando o message broker detecta que um cliente se desconecta (desconexão MQTT ou timeout). O período de expiração da sessão persistente pode ser aumentado por meio do processo padrão de aumento de limite. Se um cliente não retomar sua sessão dentro do período de expiração, a sessão é encerrada e quaisquer mensagens armazenadas associadas são descartadas. O período de expiração é aproximado; as sessões podem ser persistidas por até 30 minutos a mais (mas não menos) do que a duração configurada.
O AWS IoT Core pode trabalhar com Credenciais Temporárias obtidas através de Identity Pools, há 2 tipos de Identidades:
Se você estiver utilizando credenciais não autenticadas, basta anexar a policy à Role UnAuthenticated criada automaticamente no menu IAM. Em seguida, configure o cliente definindo a Access, a Secret Key e o Token retornados pelo serviço Cognito.
Encontre abaixo um código em .NET para obter credenciais não autenticadas
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;
Credenciais autenticadas, requer anexar a política na Authenticated Role criada automaticamente no menu IAM e anexar a política do usuário nas políticas do AWS IoT Core.
Portanto, crie uma nova política no menu de políticas do IoT Core e, toda vez que um novo usuário se autenticar, anexe esta política a esse usuário.
Você pode utilizar o seguinte comando da AWS para anexar uma policy ou criar uma função lambda.
aws iot attach-policy --policy-name PolicyName --target us-east-1:XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
O serviço Fleet Provisioning suporta as seguintes operações da API MQTT:
CreateCertificateFromCsr
Utilize o método CreateCertificateFromCsr passando o CertificateSigningRequest como parâmetro para criar o certificado. Para receber a resposta a esta requisição, primeiro inscreva-se nos seguintes métodos: SubscribeCreateCertificateFromCsrResponse e SubscribeCreateCertificateFromCsrError
CreateKeysAndCertificate
Use o método CreateKeysAndCertificate para criar um novo certificado e chaves. Para receber a resposta a esta requisição, primeiro assine os seguintes métodos SubscribeCreateKeysAndCertificateResponse e SubscribeCreateKeysAndCertificateError
RegisterThing
Utilize o método RegisterThing para registrar uma nova thing passando como parâmetro o Template Name e o Payload em formato JSON. Para receber a resposta a esta requisição, primeiro assine os seguintes métodos SubscribeRegisterThingResponse e SubscribeRegisterThingError.