O blog da AWS

Usando o AWS IoT Core MQTT Broker com Bibliotecas MQTT padrão

Por Philipp Sacha

Introdução

O AWS IoT Core conecta dispositivos de IoT (Internet of Things, ou Internet das Coisas) à plataforma de IoT da AWS e outros de seus serviços. Dispositivos e clientes podem usar o protocolo MQTT para publicar e subscrever-se a mensagens. As bibliotecas MQTT, como os SDKs de dispositivos IoT da AWS, incluem bibliotecas de código aberto (open source), guias para desenvolvedores com exemplos e guias de portabilidade para que você possa criar produtos ou soluções inovadoras de IoT nas plataformas de hardware de sua escolha.

Os clientes frequentemente perguntam à AWS como podem usar o broker de mensagens do AWS IoT Core com bibliotecas MQTT padrão. Pode haver diversas razões para essa abordagem, como a necessidade de migrar de outro broker MQTT para o AWS IoT Core utilizando bibliotecas MQTT padrão, ou no caso em que já as estejam usando em suas soluções.

Neste post, você aprenderá como utilizar bibliotecas MQTT padrão para diferentes linguagens como Python e Node.js, assim como clientes de linha de comando como o HiveMQ CLI MQTT e mosquitto_pub/mosquitto_sub, para interagir com o broker de mensagens do AWS IoT Core. As bibliotecas MQTT contempladas neste post suportam o protocolo MQTT versão 5. Para começar e saber mais sobre o MQTT5 para AWS IoT Core, consulte a documentação técnica.

Metadados

  • Tempo para Leitura: 8 minutos
  • Nível de Aprendizado: 300
  • Serviços Utilizados: AWS IoT Core

Pré-requisitos

Para executar o passo a passo nesta publicação, você precisa:

  • Ter uma conta AWS
  • Possuir permissões no AWS Identity and Access Management (AWS IAM) para:
    • provisionamento de dispositivos IoT. (Nota do Tradutor: neste artigo, o termo “thing” – literalmente “coisa” – será traduzido, na acepção deste contexto, como “dispositivo”.)

(Nota do Tradutor: criação de certificados, políticas e associações [vide o item Passo a passo abaixo])

Passo a passo

Para os exemplos deste post, você usará um dispositivo com o nome mqtt5. Para a autenticação de dispositivo, você usará um certificado X.509 que não é emitido pelo AWS IoT Core. Crie um certificado com openssl e registre-o no AWS IoT Core sem uma CA. Para efeitos desta prova de conceito, vamos criar neste artigo uma política de IoT aberta; em situação de produção, recomendamos o uso de políticas mais restritivas, de acordo com o princípio do mínimo privilégio.

Nota do Tradutor: Um exemplo de política adequada e que cumpre os requisitos desta PoC é a AWSIoTThingsRegistration. Para maiores detalhes, consulte as documentações IAM User GuideAWS Managed Policy Reference

Criando um dispositivo

Utilize os seguintes comandos para criar o seu dispositivo:

# Associe o nome do dispositivo IoT a variavel de ambiente
THING_NAME=mqtt5

# Crie o dispositivo no registro de dispositivos do AWS IoT Core
aws iot create-thing --thing-name $THING_NAME

# Crie um novo par de chaves
openssl req -x509 -newkey rsa:2048 -keyout $THING_NAME.private.key \
-out $THING_NAME.certificate.pem -sha256 -days 365 -nodes -subj "/CN=$THING_NAME"

# Registre o certificado do dispositivo com o AWS IoT Core
aws iot register-certificate-without-ca \
--certificate-pem file://$THING_NAME.certificate.pem --status ACTIVE > /tmp/register_certificate.json
CERTIFICATE_ARN=$(jq -r ".certificateArn" /tmp/register_certificate.json)
CERTIFICATE_ID=$(jq -r ".certificateId" /tmp/register_certificate.json)

# Crie uma politica de IoT
POLICY_NAME=${THING_NAME}_Policy
aws iot create-policy --policy-name $POLICY_NAME \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action": "iot:*","Resource":"*"}]}'

# Associe a politica ao seu certificado
aws iot attach-policy --policy-name $POLICY_NAME --target $CERTIFICATE_ARN

# Associe o certificado ao seu dispositivo
aws iot attach-thing-principal --thing-name $THING_NAME --principal $CERTIFICATE_ARN

IoT Endpoint

Atribua seu endpoint do AWS IoT Core a uma variável de shell. Isso facilitará o uso deste endpoint nos exemplos deste post.

export IOT_ENDPOINT=$(aws iot describe-endpoint --endpoint-type iot:Data-ATS --query 'endpointAddress' --output text)

Certificado de CA raiz

Baixe o certificado de CA raiz usado para assinar o certificado de servidor do AWS IoT Core. Armazene o certificado de CA raiz no arquivo AmazonRootca1.pem.

Nota do Tradutor: o arquivo de certificado pode ser encontrado em https://www.amazontrust.com/repository/, seção Certification Authorities, primeiro item da tabela.

Pode-se também obter o arquivo acima com o seguinte comando:

wget https://www.amazontrust.com/repository/AmazonRootCA1.pem

HiveMQ CLI MQTT

O MQTT CLI é um projeto de código aberto apoiado pela HiveMQ. Ele suporta MQTT 3.1.1 e MQTT 5.0. Você pode usar a CLI do MQTT para interagir com o corretor de mensagens de IoT Core da AWS. O HiveMQ MQTT CLI é executado como mqtt.

Subscrição

Subscreva-se ao tópico hivemq/with/aws usando o MQTT versão 5.

mqtt sub -h $IOT_ENDPOINT -p 8883 \
--cafile AmazonRootCA1.pem \
--cert mqtt5.certificate.pem \
--key mqtt5.private.key \
-d -V 5 -q 0 \
-t hivemq/with/aws

Publicação

Execute o subscritor e publique uma mensagem para o tópico hivemq/with/aws. Você deverá ver a mensagem a chegar ao subscritor.

O comando abaixo publica uma mensagem. Execute o comando várias vezes para publicar múltiplas mensagens.

mqtt pub -h $IOT_ENDPOINT -p 8883 \
--cafile AmazonRootCA1.pem \
--cert mqtt5.certificate.pem \
--key mqtt5.private.key \
-d -V 5 -q 0 \
-t hivemq/with/aws \
-m "{\"mqtt5\": \"arrived\", \"client lib\": \"hivemq\", \"date\": \"$(date)\"}"

Você verá todas as mensagens publicadas chegarem ao subscritor.

Mosquitto

O Eclipse Mosquitto é um broker de mensagens de código aberto e fornece clientes para publicação (mosquitto_pub) e subscrição (mosquitto_sub).

Subscrevendo a um tópico com o mosquitto_sub.

Utilizam-se o mosquitto_sub para subscrever-se a um tópico e o mosquitto_pub para publicar ao mesmo tópico. O AWS IoT Core roteia as mensagens do publicador ao subscritor.

Subscrição

Utilize o cliente mosquitto_sub para subscrever-se ao tópico mosquitto/with/aws.

mosquitto_sub --cafile AmazonRootCA1.pem \
--cert $THING_NAME.certificate.pem \
--key $THING_NAME.private.key -h $IOT_ENDPOINT -p 8883 \
-q 0 -t mosquitto/with/aws -i ${THING_NAME}-sub \
--tls-version tlsv1.2 -d -V mqttv5

Publicação

Publique múltiplas mensagens com o cliente mosquitto_pub. Para publicar múltiplas mensagens em sequência, crie um arquivo contendo as mensagens e passe-as ao mosquitto_pub para lê-las.

Crie um arquivo chamado messages.txt com o seguinte conteúdo:

{"mqtt5": "arrived", "message": "1"}
{"mqtt5": "arrived", "message": "2"}
{"mqtt5": "arrived", "message": "3"}

Alias de tópico

Publique uma mensagem usando um alias de tópico. Um alias de tópico é um número inteiro que pode ser usado em vez do nome de um tópico.

Nota do Tradutor: o alias de tópico é uma funcionalidade introduzida na versão 5 do protocolo MQTT para agilizar a publicação repetida de mensagens para um mesmo tópico, em especial quando os nomes dos tópicos são longos. Para mais informações, consulte a especificação do protocolo em https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113).

A primeira solicitação de publicação introduz um alias de tópico para ele; a partir daí, todas as solicitações de publicação subsequentes usam o alias deste tópico em vez de seu nome. No exemplo a seguir, você usa o alias de tópico "2" para o tópico mosquitto/with/aws.

cat messages.txt | mosquitto_pub --cafile AmazonRootCA1.pem \
--cert $THING_NAME.certificate.pem \
--key $THING_NAME.private.key -h $IOT_ENDPOINT -p 8883 \
-q 0 -t mosquitto/with/aws -i $THING_NAME --tls-version tlsv1.2 \
-d -V mqttv5 -D publish topic-alias 2 -l

O retorno do publicador deve parecer similar ao da tela abaixo:

Client mqtt5 sending CONNECT
Client mqtt5 received CONNACK (0)
Client mqtt5 sending PUBLISH (d0, q0, r0, m1, ‘mqtt5’, … (36 bytes))
Client mqtt5 sending PUBLISH (d0, q0, r0, m2, ‘(null)’, … (36 bytes))
Client mqtt5 sending PUBLISH (d0, q0, r0, m3, ‘(null)’, … (36 bytes))
Client mqtt5 sending DISCONNECT

Somente a primeira solicitação de publicação inclui o nome do tópico. Para as solicitações subsequentes, você receberá '(null)' como tópico, o que significa que o alias do tópico está sendo usado.

No subscritor, você pode observar as mensagens recebidas do publicador.

Cliente Paho Python

Os trechos de código a seguir demonstram como a biblioteca Cliente Eclipse Paho Python pode ser utilizada com o AWS IoT Core. Em primeiro lugar, conecte-se ao AWS IoT Core. Após uma conexão bem-sucedida, é possível calcular o alias do tópico e subscrever-se a ele; a partir de então, você pode publicar para este tópico.

Cliente MQTT

Crie um cliente MQTT versão 5 e os respectivos handlers para uma conexão bem-sucedida e, quando uma mensagem chegar, conecte-se ao endpoint do AWS IoT Core. Neste exemplo, o certificado raiz da CA, o certificado do dispositivo, a chave do dispositivo e o endpoint são fornecidos como opções na linha de comando.

import paho.mqtt.client as mqtt

# OBS.: args: dict com os argumentos passados em linha de comando

mqttc = mqtt.Client(protocol=mqtt.MQTTv5)
mqttc.tls_set(
ca_certs=args['ca'], # Arquivo com o certificado do dispositivo
certfile=args['certificate'], # Arquivo com o certificado de CA raiz
keyfile=args['key'], # Arquivo com private key
tls_version=2
)

mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect(args['endpoint'], 8883, 60)

Handler de Conexão

Após a conexão, o cliente MQTT receberá uma resposta CONNACK do AWS IoT Core que inclui o valor máximo utilizável para um alias de tópico. Com base neste retorno, o código gera um alias de tópico aleatório no intervalo de 0 até o valor máximo obtido da resposta.

def on_connect(mqttc, userdata, flags, rc, properties=None):
global TOPIC_ALIAS_MAX
LOGGER.info("connected to endpoint %s with result code %s", args['endpoint'], rc)
LOGGER.info("userdata: %s, flags: %s properties: %s", userdata, flags, properties)
LOGGER.info("topic_alias_maximum: %s", properties.TopicAliasMaximum)
TOPIC_ALIAS_MAX = properties.TopicAliasMaximum

LOGGER.info('subscribing to topic: %s', args['topic'])
mqttc.subscribe(args['topic'], qos=0, options=None, properties=None)

topic_alias = random.SystemRandom().randint(0, TOPIC_ALIAS_MAX)

Quando uma mensagem for recebida pelo handler on_message(), ela será registrada.

def on_message(mqttc, userdata, msg):
LOGGER.info('received message: topic: %s payload: %s',
msg.topic, msg.payload.decode())

Para definir um alias para o nome do seu tópico, você pode publicar a primeira mensagem incluindo o alias e o nome do tópico. Todas as mensagens subsequentes serão publicadas em um laço while usando este alias.

# OBS.: As seguintes declaracoes devem ter sido feitas em algum ponto # do código:
# from paho.mqtt.properties import Properties
# from paho.mqtt.packettypes import PacketTypes
# publish_properties = Properties(PacketTypes.PUBLISH)

publish_properties.TopicAlias = topic_alias

message = {
'mqttv5': 'has arrived',
'date_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'topic_alias': topic_alias
}

LOGGER.info('publish: topic: %s message: %s', args.topic, message)
mqttc.publish(args.topic, payload=json.dumps(message),
qos=0, retain=False, properties=publish_properties)

while True:
message['date_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
LOGGER.info('publish: topic_alias: %s message: %s', topic_alias, message)
mqttc.publish('', payload=json.dumps(message),
qos=0, retain=False, properties=publish_properties)
time.sleep(2)

MQTT.js

Na seção anterior, você aprendeu a usar o Cliente Paho Python. A Paho também fornece um cliente JavaScript que usa WebSockets para se conectar ao corretor MQTT. A biblioteca de cliente MQTT.js suporta não apenas WebSockets, mas também conexões TLS com autenticação baseada em certificado. Os seguintes trechos de código em Node.js pressupõem que você forneça a CA raiz, a chave privada e o certificado do dispositivo, bem como o endpoint e o tópico do AWS IoT Core, usando a linha de comando. Neste exemplo, você também usará um alias de tópico para publicar mensagens.

Cliente MQTT

Crie um cliente para se conectar ao AWS IoT Core com o MQTT versão 5.

const mqtt = require('mqtt');

// OBS.: args: Object com os argumentos passados em linha de comando

const client = mqtt.connect(
'mqtts://' + args.endpoint + ':8883',
{
key:  fs.readFileSync(args.key),
cert: fs.readFileSync(args.certificate),
ca: [ fs.readFileSync(args.ca) ],
protocolId: 'MQTT',
protocolVersion: 5,
}
);

function generateMessage(topicAlias) {
return JSON.stringify({
mqttv5: 'has arrived',
date_time: (new Date()).toISOString(),
topic_alias: topicAlias
});
}

Handler de Conexão

Após uma conexão bem-sucedida, obtenha o valor máximo para o alias de tópico anunciado pelo AWS IoT Core. Calcule o alias do tópico usando uma função aleatória (Nota do Tradutor: calculando um valor aleatório entre 1 e o valor máximo possível para o alias, enviado pelo AWS IoT Core. Vide seção “Cliente Paho Python”, item “Handler de Conexão”) e defina as propriedades de publicação para usar o alias do tópico. Subscreva-se ao tópico em que você está publicando e publique uma mensagem usando o tópico e seu alias.

client.on('connect', function () {
const topicAliasMax = client.topicAliasSend.numberAllocator.max;
const topicAlias = Math.floor(Math.random() * (topicAliasMax + 1));

// OBS.: A seguinte declaracao deve ter sido feita em algum ponto     // do código:
// publishOptions = {properties: {topicAlias: null}};

publishOptions.properties.topicAlias = topicAlias;

console.log('subscribe: topic: ' + args.topic);
client.subscribe(args.topic, function (err) {
if (err) {
console.log('subscribe error: ' + err);
} else {
const message = generateMessage(topicAlias);
console.log('publish first message to set topicAlias: ' + topicAlias +
' topic: ' + args.topic + ' message: ' + message);
client.publish(args.topic, message, publishOptions);
};
});
});

Recebendo mensagens

As mensagens serão registradas no console.

client.on('message', (topic, message) => {
console.log('message received: subscription topic: ' + topic +
'; message: ' + message.toString());
});

Publicando mensagens

Publique mensagens continuamente usando o alias do tópico.

// OBS.: antes de se usar o alias de tópico para publicar as
// mensagens, usando o nome do tópico vazio ('') como argumento, é   // preciso que o método client.publish() tenha sido executado pelo uma // vez com o tópico em questão – no caso, o valor em args.topic.

client.publish(args.topic, generateMessage(), publishOptions);

setInterval(function () {
const message = generateMessage(topicAlias);
console.log('publish: topic: ' + args.topic + ' message: ' + message);
client.publish('', message, publishOptions);
}, 5000);

Você deve ver as mensagens chegando ao seu subscritor, que as registra no console.

Limpando o ambiente

Exclua os recursos criados, o certificado associado e a política de IoT. Você pode encontrar etapas detalhadas na documentação Como gerenciar coisas com o registro.

Conclusão

Neste post, aprendemos a usar o AWS IoT Core com bibliotecas padrão do MQTT, que já incluem suporte para o MQTT5. O uso dos SDKs de dispositivos IoT da AWS simplifica e acelera o desenvolvimento de código executado em dispositivos conectados ao incluir métodos que facilitam o uso dos recursos do AWS IoT, como descoberta do AWS IoT Greengrass, autenticação personalizada ou sombras de dispositivos. Os SDKs de dispositivos IoT da AWS incluem bibliotecas de código aberto, guias para desenvolvedores com exemplos e guias de portabilidade para que você possa criar produtos ou soluções de IoT inovadores nas plataformas de hardware de sua escolha. Os SDKs de dispositivos IoT da AWS estão disponíveis gratuitamente como projetos de código aberto.

 

Este artigo foi traduzido do Blog da AWS em Inglês.


Sobre o autor

Philipp Sacha (psacha@amazon.de) é Arquiteto de Soluções para Parceiros na Amazon Web Services e trabalha com parceiros na área de Manufatura. Ele se juntou à AWS em 2015 e possui diversos papéis como Arquiteto de Soluções e também como especialista na área de IoT.

 

 

 

 

Tradutor

Alessandro Martins (alfermar@amazon.com) é Arquiteto de Soluções na Amazon Web Services, trabalhando no segmento de Large Enterprises. Ele se juntou à AWS em 2021 e atende clientes do Setor Industrial.