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:
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:
sense_emu_gui
O código a seguir exemplifica o caso básico de uso.
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>.
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:
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:
#
# 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:
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:
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
















