- Trocando informações com uma Raspberry Pi e plataforma dojot
- Configurando conexão segura com o uso de TLS na plataforma dojot
A dojot é uma plataforma brasileira desenvolvida principalmente pelo CPqD e que surgiu com uma proposta open source, visando facilitar o desenvolvimento de soluções e subsidiar o ecossistema IoT com conteúdo local voltado às necessidades do País.
O código dos componentes que compõem a solução está disponível no repositório do Github. Descritivos detalhados da arquitetura, do funcionamento dos componentes e alguns casos de uso podem ser encontrados na documentação.
Introdução
Na série introdutória da dojot, foram exploradas as funcionalidades iniciais da plataforma, permitindo a criação de dispositivos virtuais, visualização de seus atributos e definição de fluxos de processamento a partir de sinais enviados por um dispositivo.
Neste artigo, utilizaremos o que foi abordado para estabelecer comunicação entre um dispositivo real e a plataforma, monitorando sensores de entrada e controlando uma saída a partir do resultado de um fluxo de processamento.
Mapeando o dispositivo na plataforma dojot
Inicialmente, seria utilizada uma Raspberry Pi em conjunto com o add-on SenseHat.
Visando a comodidade dos leitores – principalmente daqueles que não contam com acesso a este tipo de hardware – este artigo utilizará o emulador Sense HAT Emulator.
Ainda que o dispositivo “real” seja emulado, a biblioteca utilizada simula de forma transparente as APIs do SenseHat, de forma que a aplicação possa ser portada para o dispositivo físico sem grandes problemas.
De maneira similar à descrita nos artigos introdutórios, os passos a serem seguidos para estabelecer a comunicação são:
- criação de um modelo que descreva os principais atributos do dispositivo
- criação do dispositivo a partir do modelo que o representa
- mapeamento do deviceId nas aplicações cliente
Criando o modelo
Neste caso, ao mapear o SenseHat, serão realizadas as seguintes ações:
- leitura de temperatura
- leitura de umidade
- leitura de pressão
- escrita no visor
Assim, o modelo que dará origem a este dispositivo pode ser visualizado a seguir
humidity: pressure: temperature: display: protocol: |
entrada do tipo float (dynamic) entrada do tipo float (dynamic) entrada do tipo float (dynamic) saída do tipo string (actuator) configuração |
Instanciando um dispositivo a partir do modelo
Após termos o modelo criado, o utilizamos para instanciar um dispositivo.
Obtendo o deviceId
Uma vez salvo, já é possível obter o valor do deviceId na tela de detalhes para este dispositivo.
No caso deste exemplo, o ID é 1d89f2. Note que este valor é gerado cada vez que um dispositivo é criado – e, portanto, deve ser atualizado de acordo.
Interagindo com a plataforma
Até então, apenas foi abordado o uso diretamente via linha de comando de um cliente MQTT para envio de mensagens, simulando o comportamento de um dispositivo.
Nesta seção, utilizaremos uma biblioteca que permite realizar o envio das mesmas mensagens diretamente do código Python sendo executado no dispositivo real.
Instalando as dependências
Os códigos apresentados abaixo fazem uso de Python 3 e suas dependências são gerenciadas a partir do pip3, então esses devem estar instalados.
As dependências estão listadas no arquivo requirements.txt e podem ser instaladas a partir do comando:
1 |
pip3 install -r ./requirements.txt |
São elas:
Paho MQTT
utilizada na comunicação com o broker mqtt. O uso neste exemplo será básico. Mais detalhes podem ser encontrados na documentação oficial.
sense_emu
biblioteca que espelha as APIs existentes no sense_hat. A documentação oficial pode ser encontrada neste endereço.
Utilizando o emulador
Uma vez instalado, o emulador pode ser executado com o comando:
1 |
sense_emu_gui |
O código a seguir exemplifica o caso básico de uso.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from sense_emu import SenseHat import time # # Raspberry Pi's Sensor initialization sense = SenseHat() # # Execution loop while True: print("Temperatura:", sense.temperature, "; Pressão:", sense.pressure, "; Umidade:", sense.humidity) time.sleep(4) |
A referência sense dá acesso às APIs do SenseHat de forma simples e direta.
Neste exemplo, os valores de temperatura, pressão e umidade são impressos na tela com intervalos de 4 segundos.
Publicando valores na dojot
Conforme visto anteriormente, os atributos de um dispositivo podem ser enviados à plataforma a partir da publicação no tópico de formato /<tenant_name>/<device_id>/attrs
Assim, para que o dispositivo identificado por 36fc0a publique os valores lidos – assumindo o tenant default admin – o tópico de destino deve ser /admin/36fc0a/attrs
No código abaixo, o cliente Paho é utilizado para comunicação MQTT e envio dos atributos definidos manualmente. Note que o ID do cliente mantém o padrão visto ao utilizar o mosquitto: <tenant_name>:<device_id>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import paho.mqtt.client as mqtt import json import time # # Properties definition tenant_name = "admin" device_id = "36fc0a" # # Internal definitions setup client_id = "{}:{}".format(tenant_name, device_id) topic_to_publish = "/{}/{}/attrs".format(tenant_name, device_id) # # MQTT Client setup and connection client = mqtt.Client(client_id) print("Connecting to mqtt broker") client.connect(host='localhost', port=1883) client.loop_start() # # Execution loop while True: message = { "temperature" : 35.11, "pressure": 773.29, "humidity": 66.23 } print("Publishing", message, 'to topic', topic_to_publish) client.publish(topic_to_publish, json.dumps(message)) time.sleep(4) |
Monitorando o dispositivo
Combinando os dois scripts anteriores, podemos realizar o envio das medições à plataforma dojot com a frequência desejada.
O trecho abaixo ilustra este caso de uso:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
from sense_emu import SenseHat import paho.mqtt.client as mqtt import json import time # # Properties definition tenant_name = "admin" device_id = "36fc0a" # # Internal definitions setup client_id = "{}:{}".format(tenant_name, device_id) topic_to_publish = "/{}/{}/attrs".format(tenant_name, device_id) # # MQTT Client setup and connection client = mqtt.Client(client_id) print("Connecting to mqtt broker") client.connect(host='localhost', port=1883) client.loop_start() # # Raspberry Pi's Sensor initialization print("Initializing SenseHat emulator") sense = SenseHat() # # Execution loop while True: message = { "temperature" : sense.temperature, "pressure": sense.pressure, "humidity": sense.humidity } print("Publishing", message, 'to topic', topic_to_publish) client.publish(topic_to_publish, json.dumps(message)) time.sleep(4) |
Configurando um fluxo de processamento
Visando manter o exemplo o mais simples possível, iremos simular um cenário de uso onde a temperatura medida deve permanecer entre 20 e 30 ºC.
Assim, o fluxo deverá tomar nos casos extremos: valores abaixo de 20ºC ou acima de 30ºC.
Para tal, o seguinte fluxo deve ser criado:
RaspberryPi: define o dispositivo de entrada.
Envia os atributos a partir da variável payload
temperatureController: verifica os limiares de temperatura.
A mensagem recebida via payload é analisada neste bloco. Como o valor de interesse é a temperatura, a propriedade payload.temperature é configurada para verificação.
Os critérios configurados são:
- Se temperatura maior que 30, acione saída 1
- Se temperatura menor que 20, acione saída 2
highTemperatureWarning e lowTemperatureWarning: são ativados nos casos de alerta de temperatura alta e baixa, respectivamente.
Esse bloco é responsável por mapear a saída desejada ao modelo de saída do dispositivo.
Neste exemplo, configura-se uma variável output com o objeto { “display” : “high” }.
setDisplay: define o dispositivo de saída (actuator) para o fluxo e a variável que deve ser enviada ao mesmo.
No exemplo, a saída é o próprio Raspberry Pi e a variável é a output, definida no bloco anterior.
Obtendo a mensagem de retorno
Uma vez configurado, o fluxo emitirá um sinal nos casos de temperatura alta ou baixa.
Para que o dispositivo receba as mensagens destinadas a ele, o tópico /<tenant>/<device_id>/config deve ser subscrito.
O código abaixo destaca o trecho adicionado para que a subscrição ocorra, configurando também a função de callback a ser executada quando uma mensagem é recebida:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# # Internal definitions setup client_id = "{}:{}".format(tenant_name, device_id) topic_to_publish = "/{}/{}/attrs".format(tenant_name, device_id) topic_to_subscribe = "/{}/{}/config".format(tenant_name, device_id) def on_message(client, userdata, message): decoded_message = json.loads(message.payload.decode()) message_text = decoded_message['attrs']['message'] print("Received", decoded_message) # # MQTT Client setup and connection client = mqtt.Client(client_id) client.on_message = on_message print("Connecting to mqtt broker") client.connect(host='localhost', port=1883) client.loop_start() print("Subscribing to topic", topic_to_subscribe) client.subscribe(topic_to_subscribe) |
Assim que uma mensagem for publicada no tópico, essa função será invocada.
Como o fluxo foi definido para atuar nos casos onde a temperatura é menor que 20 ou maior que 30ºC, podemos validar seu funcionamento variando a temperatura no SensorHat.
Valores publicados e recebidos. Note que apenas são recebidos valores quando ultrapassados os limiares definidos no fluxo de processamento. |
Uma vez recebida a mensagem, fica a critério do desenvolvedor decidir como utilizá-la.
Imprimindo a mensagem de retorno no display
Neste exemplo, será impresso no display do SensorHat a situação definida a partir da mensagem recebida, indicando os casos de temperatura baixa e alta.
Modificando o código do on_message, o trecho a seguir mostra a adição que nos permite escrever no visor do dispositivo:
1 2 3 4 5 6 7 8 9 |
def on_message(client, userdata, message): decoded_message = json.loads(message.payload.decode()) message_text = decoded_message['attrs']['message'] print("Received", decoded_message) sense.clear() if message_text == "high": sense.show_message("HOT") elif message_text == "low": sense.show_message("COLD") |
É possível forçar os valores de temperatura no dispositivo e validar a atualização do visor:
O código final do script é exibido a seguir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
https://github.com/znti/dojot-raspi-sensehat/blob/master/main.py from sense_emu import SenseHat import paho.mqtt.client as mqtt import json import time # # Properties definition tenant_name = "admin" device_id = "36fc0a" # # Internal definitions setup client_id = "{}:{}".format(tenant_name, device_id) topic_to_publish = "/{}/{}/attrs".format(tenant_name, device_id) topic_to_subscribe = "/{}/{}/config".format(tenant_name, device_id) def on_message(client, userdata, message): decoded_message = json.loads(message.payload.decode()) message_text = decoded_message['attrs']['message'] print("Received", decoded_message) sense.clear() if message_text == "high": sense.show_message("HOT") elif message_text == "low": sense.show_message("COLD") # # MQTT Client setup and connection client = mqtt.Client(client_id) client.on_message = on_message print("Connecting to mqtt broker") client.connect(host='localhost', port=1883) client.loop_start() print("Subscribing to topic", topic_to_subscribe) client.subscribe(topic_to_subscribe) # # Raspberry Pi's Sensor initialization print("Initializing SenseHat emulator") sense = SenseHat() # # Execution loop while True: message = { "temperature" : sense.temperature, "pressure": sense.pressure, "humidity": sense.humidity } print("Publishing", message, 'to topic', topic_to_publish) client.publish(topic_to_publish, json.dumps(message)) time.sleep(4) |
Conclusão
Até aqui, foram realizadas as configurações necessárias para estabelecer a conexão entre uma Raspberry Pi e a plataforma dojot. Tanto o envio quanto o recebimento de informações foram abordados, o que já permite realizar o controle de um atuador a partir dos sinais enviados ao fluxo de processamento.
No próximo artigo, serão adicionadas camadas de segurança nesta troca de dados a partir do uso de TLS com certificados digitais: com eles, é possível garantir a comunicação segura entre o dispositivo e a plataforma dojot.
Saiba mais
Introdução à plataforma dojot – Instalação e configuração
Simulação de dispositivos na plataforma dojot
Configurando fluxos de processamento de dados da plataforma dojot