Fala galera, tudo bem? Muitas vezes pensamos em como desenvolver uma interface gráfica para nossos sistemas de automação e não sabemos qual plataforma utilizar ou por onde começar. Neste artigo, irei apresentar a plataforma ThingsBoard e ensinar, de forma prática, a criar um painel de automação para controlar seus dispositivos ESP8266. Então, vem comigo?!
Conhecendo a Plataforma ThingsBoard e sua Arquitetura
O ThingsBoard é uma plataforma IoT que permite a integração e o gerenciamento de dispositivos através de uma infraestrutura Web. Ela fornece uma interface de usuário e aplicações através de protocolos como HTTP, MQTT e CoAP, além de diversos recursos que viabilizam a implementação do projeto de automação.
Este sistema permite que você crie clientes, dispositivos, painéis de controle, ativos e outros componentes estabelecendo vínculos entre eles de acordo com seu ambiente de automação. Dessa forma, você pode criar diversos usuários de clientes e conceder a eles o acesso a determinados dispositivos, ativos ou painel de controle. Para exemplificar, apresento, a seguir, um cenário IoT e a descrição de cada elemento do sistema.
No contexto da plataforma, os elementos são tratados como entidades. O Tenant Administrador é a entidade que gerencia clientes, cria ou possui dispositivos e estabelece o vínculo entre ativos. Em nosso cenário, temos uma casa e seus cômodos, os quais definimos como ativos. Eles são utilizados para criar relações entre si, permitindo que dispositivos e clientes sejam gerenciados para cada ativo.
Nesta hierarquia, o ativo casa contém outros ativos como a sala de estar que contém o dispositivo NodeMCU, responsável por controlar e obter dados do ambiente. Essas informações podem ser acessados pelo Dashboard, painel destinado à visualização dos dados e controle dos dispositivos por meio da interface do usuário. Assim, um cliente pode ter acesso a um ou mais ativos e dispositivos, cabendo ao administrador dar a permissão.
Após essa visão geral da plataforma, iremos apresentar a estrutura do nosso projeto.
Estrutura do Projeto
Neste artigo, ensinaremos como configurar os dispositivos ESP8266 e criar painéis de visualização e controle no ThingsBoard. Não abordaremos as definições de relacionamento de ativos e clientes, pois tornaria os post muito extenso. Portanto, este artigo foi organizado nos seguintes tópicos:
- Funcionamento do Sistema
- Adicionando Dispositivo na Plataforma
- Desenvolvendo Painel de Controle no ThingsBoard
- Código detalhado do Projeto
Para isso, precisaremos, inicialmente, instalar a plataforma em alguma máquina hospedeira ou um servidor em nuvem. O ThingsBoard disponibiliza o serviço para diversos hardwares, como o Raspberry Pi. Entretanto, para fins de simplificação, utilizaremos a versão de demonstração disponível no próprio site da plataforma.
Você pode acessá-la neste link. A seguir, ensinaremos como adicionar um dispositivo no sistema. A seguir, explicaremos como ocorrerá a comunicação do dispositivo com a plataforma.
Funcionamento do Sistema
A plataforma do ThingsBoard possui APIs que fornecem a comunicação com os dispositivos, utilizando protocolos da camada de aplicação. Em nosso projeto, utilizaremos o MQTT para realizar a conexão entre o serviço do ThingsBoard e nosso dispositivo ESP8266.
Para isso, a plataforma dispõe os recursos de telemetria, onde os dispositivos podem enviar seus dados, podendo salvá-los no banco de dados do sistema e o recurso RPC, que permite o usuário enviar chamadas para o dispositivo e vice-versa.
Logo, utilizaremos esses dois recursos para realizar a comunicação. Basicamente, o ESP8266 enviará seus dados obtidos dos sensores em formato JSON para o tópico de telemetria específico “v1/devices/me/telemetry” e deverá se inscrever no tópico de RPC “v1/devices/me/rpc/request/+” por onde receberá os comandos do usuário, podendo respondê-los publicando no tópico “v1/devices/me/rpc/response/$response_id”, onde “$response_id” corresponde ao id do usuário que enviou o comando. A imagem a seguir ilustra como ocorre essa comunicação:
Após a compreensão do sistema, iniciaremos a configuração deste. Mãos à obra!
Adicionando Dispositivo na Plataforma
Para adicionar um novo dispositivo, siga os passos:
- Na página principal, clique em “Devices”.
- Em seguida, clique em Add new item, de símbolo “+” e, depois, em “Add new device”.
- No campo “Name” preencha com o nome do dispositivo, como o exemplo: ESP8266 Sala de Estar. Em seguida, no campo “Device Type” indique que tipo de dispositivo ele é, no caso: CONTROLE.
- Por último, clique em “ADD”.
Os passos descritos podem ser acompanhados na imagem a seguir:
Pronto, você acabou de adicionar um novo dispositivo. Clicando sobre ele você poderá visualizar e editar suas características, como seus atributos, dados de telemetria, relacionamentos e outros. Um dos dados essenciais para a comunicação é seu “Access Token”, disponível na guia “Details”.
Ele será necessário para estabelecer a comunicação e obter os dados deste dispositivo. A seguir, ensinaremos como criar o painel de visualização e controle do dispositivo que acabamos de criar.
Desenvolvendo Painel no ThingsBoard
Para criarmos um painel de visualização e controle, devemos realizar os seguintes passos:
- Na página principal, clique em “Dashboards”.
- Em seguida, clique em Add new dashboard, de símbolo “+” e, depois, em “Create new dashboard”.
- No campo “Title” preencha com o nome do painel, como o exemplo: Sala de Estar. Cada painel criado pode ser representado por um ambiente que pode ser composto por um ou mais dispositivos.
- Em seguida, clique em “ADD” para criarmos nosso painel.
Clicando sobre eles temos acesso aos widgets do painel. Por enquanto, ainda não temos nenhum. Os diversos tipos de widgets fornecem a visualização dos dados e comandos para controlar nossos dispositivos.
Entretanto, para incluí-los em nosso painel precisamos, primeiramente, criar aliases de entidade, ou seja, nomes que identificam os dados e estão vinculados a algum dispositivo. Assim, continue com os seguintes passos:
- Dentro do painel recém criado, clique em “Enter edit mode”, cujo símbolo é um lápis no canto inferior direito.
- Clique na opção “Entity Aliases”, em seguida, clique no botão “ADD ALIAS”.
- No campo “Alias name” defina com os dados que utilizaremos do dispositivo, no caso: Controle Luz. Em seguida, no campo “Filter type” escolha a opção “Entity List”. Na guia “Type” selecione ”Device” e em “Entity List” selecione o dispositivo que criamos: ESP8266 Sala de Estar.
- Repita o passo anterior adicionando o alias Temperatura e o alias Umidade.
- Por fim, clique em “Save” para adicioná-los.
A figura seguinte ilustra resumidamente os passos descritos:
Feito isso, podemos criar nossos widgets de visualização e controle, descritos a seguir.
Criando Widgets de Visualização e Controle
Iremos criar três tipos de widgets para os respectivos aliases inseridos. Dessa forma, criaremos um botão para controlar a luz do ambiente e dois gráficos para visualizar a temperatura e umidade.
Em geral, adicionar um novo widgets consiste em três passos: escolhermos seu tipo, vinculá-lo ao alias de entidade que criamos e configurá-lo.
Primeiro, criaremos o botão de controle da luz seguindo os passos:
- Clique na opção “Add New Widget”.
- Na guia “Select widgets bundle” escolha a opção “Control widgets” e escolha o widget “Switch control”.
- Em seguida, na guia “DATA”, temos o campo “Target device” onde selecionamos o alias que criamos denominado Controle Luz.
- Na guia “ADVANCED” definiremos alguns parâmetros. No campo “Switch title” inserimos o nome do widget: Luz Sala de Estar. No campo “Convert value function” que possui uma caixa de entrada com um código em javascript, substituiremos pelo seguinte código: return {‘enabled’ : value, ‘gpio’ : 2}
- Por fim, clique em “ADD”.
Agora, realizaremos os mesmos passos para a criação dos outros dois widgets, modificando apenas os parâmetro indicados na figura a seguir:
Após a realização dos passos descritos, devemos ter um painel com o seguinte visual:
Acredite, estamos quase lá! Acabamos de concluir as configurações de nossa plataforma. Desse modo, os próximos tópicos irão descrever os componentes necessários, a montagem e o código do projeto detalhado.
Componentes do Projeto
A seguir, descrevo os componentes necessários para a execução do projeto:
Estes e outros módulos podem ser encontrados em nosso site, clicando aqui.
Montagem do Circuito
Com os componentes em mãos, faremos a montagem do nosso circuito seguindo a imagem abaixo:
De acordo com o esquema, utilizamos o pino D4 ligado ao módulo relé e o pino D2 conectado ao sensor DHT22. A seguir, apresentamos o código detalhado do nosso projeto.
Código Detalhado do Projeto
/* Projeto: Painel de Automação com ThingsBoard e ESP8266 Autor: Daniel Fiuza - AutoCore Robótica Data: 20/03/2020 Código de Domínio Público */ #include "DHTesp.h" #include <ArduinoJson.h> #include <PubSubClient.h> #include <ESP8266WiFi.h> // Configurações do Wifi #define WIFI_AP "Seu-ssid" #define WIFI_PASSWORD "Sua-senha" // Configurações do ThingsBoard // O TOKEN do dispositivo é obtido na // guia Devices -> ESP8266 Sala de Estar #define TOKEN "Acces-Token-do-Dispositivo" // Endereço do servidor ThingsBoard char thingsboardServer[] = "demo.thingsboard.io"; // Tópico onde serão publicados os dados do sensor char topic_publish[] = "v1/devices/me/telemetry"; // Instancia objeto dht para uso // do módulo DHT22 DHTesp dht; // Instancia objeto wifiClient WiFiClient wifiClient; // Instancia cliente MQTT 'client' PubSubClient client(wifiClient); // Status de conexão Wifi int status = WL_IDLE_STATUS; // Variável para controle do // intervalo de tempo unsigned long last_time; void setup() { // Inicia porta serial Serial.begin(115200); Serial.println(); // Configura GPIO 2 como saída para acionar o relé // Pino D4 NodeMCU --> GPIO 2 IDE Arduino pinMode(2, OUTPUT); // Configura GPIO 4 como entrada para o sensor DHT22 // Pino D3 NodeMCU --> GPIO 4 IDE Arduino dht.setup(4, DHTesp::DHT22); delay(10); // Função que inicia a conexão com o Access Point InitWiFi(); // Em seguida, configura a conexão MQTT client.setServer( thingsboardServer, 1883 ); // Define função on_message como retorno de chamada MQTT // Processa as mensagens recebidas do servidor client.setCallback(on_message); } void loop() { // Se o cliente MQTT não tiver conectado, executa função reconnect() if ( !client.connected() ) { reconnect(); } // Mantém a conexão MQTT aberta com o thingsboard client.loop(); // Enviar dados do sensor periodicamente // Se o intervalo de tempo for maior que 1s if ( millis() - last_time > 1000 ) { // Envia dados do sensor ao ThingsBoard sendTemperatureAndHumidity(); last_time = millis(); } } /* * Recebe os comandos do ThingsBoard, * Processa a mensagem, * Executa o comando, * Retorna o status do relé para o servidor. * * Exemplo de mensagem Json recebida: * { * "method" : "setValue", * "params" : { * "enabled": true, * "gpio" : 2 * } * } */ void on_message(const char* topic, byte* payload, unsigned int length) { // Variável que receberá a mensagem da variavel payload char message_json[length + 1]; // Copia os bytes da payload para a variavel message_json strncpy (message_json, (char*)payload, length); // Define o terminador da string com o caracter nulo '\0' // Identificando o fim da string. message_json[length] = '\0'; // Cria a variável Json data de tamanho 200 bytes StaticJsonDocument<200> data; // Desserializando a mensagem da variável message_json DeserializationError error = deserializeJson(data, message_json); // Se houver erro ao desserializar, informa. if (error) { Serial.print("Erro ao desserializar Json"); return; } // Status do gpio boolean status_gpio; // Recebe parâmetro "method" String methodName = String((const char*)data["method"]); // Recebe parâmetro "enable" boolean enabled = data["params"]["enabled"]; // Recebe parâmetro "gpio" int pin = data["params"]["gpio"]; // Verifica se o método recebido é "setValue" if(methodName.equals("setValue")){ // Se enable for true, então aciona relé // Note que o acionamento é com nível lógico 0 if(enabled){ digitalWrite(pin, LOW); // Atualiza status do pino status_gpio = true; } // Caso contrário, desliga relé else{ digitalWrite(pin, HIGH); status_gpio = false; } // Variável que recebe o tópico // Ex. tópico: v1/devices/me/rpc/request/$request_id String responseTopic = String(topic); // Substitui a palavra request por response, atualizando o tópico // Ex. tópico atualizado: v1/devices/me/rpc/response/$request_id responseTopic.replace("request", "response"); // Cria variável Json send_data StaticJsonDocument<200> send_data; // Cria mensagem Json na variável send_data send_data["method"] = "getValue"; JsonObject obj = send_data.createNestedObject("params"); obj["enabled"] = status_gpio; obj["gpio"] = pin; /* * Formato da mensagem criada: * { * "method" : "getValue", * "params" : { * "enabled" : true, * "gpio" : 2 * } * } * */ String send_payload; // Serializa a variável send_data para string send_payload serializeJson(send_data, send_payload); // Por fim, publica no tópico atualizado e mensagem criada client.publish(responseTopic.c_str(), send_payload.c_str()); } } // Inicia conexão Wifi void InitWiFi() { Serial.println("Conectando-se ao AP ..."); // Inicia conexão com Wifi WiFi.begin(WIFI_AP, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Conexão Wifi estabelecida"); } // Reconecta cliente MQTT ao ThingsBoard void reconnect() { // Se o cliente MQTT não estiver conectado, verifica conexão wifi e mqtt while (!client.connected()) { status = WiFi.status(); // Caso não esteja conectado ao wifi, inicia conexão if ( status != WL_CONNECTED) { WiFi.begin(WIFI_AP, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Connected to AP"); } Serial.print("Conectando-se ao ThingsBoard ..."); // Inicia conexão MQTT // Função connect(clientId, username, password) if ( client.connect("ESP8266 Device", TOKEN, NULL) ) { // Imprime resultado da conexão MQTT, indicando que foi estabelecida Serial.println( "[MQTT DONE]" ); // Inscreve para receber as solicitações RPC client.subscribe("v1/devices/me/rpc/request/+"); } else { // Imprime resultado da conexão MQTT, indicando que não foi estabelecida Serial.print( "[MQTT FAILED] [ rc = " ); Serial.print( client.state() ); Serial.println( " : retrying in 5 seconds]" ); // Aguarda 5 segundos antes de se reconectar delay( 5000 ); } } } /* * Envia os dados da Temperatura e Umidade * A mensagem terá o seguinte formato Json: * { * "temperature" : 28.70 * "humidity" : 87.80 * } * */ void sendTemperatureAndHumidity(){ // Recebe valor da umidade float humidity = dht.getHumidity(); // Recebe valor da temperatura float temperature = dht.getTemperature(); // Se aquisição tiver sido bem sucedida if (dht.getStatusString() == "OK"){ // Cria variável Json data StaticJsonDocument<200> data; // Cria mensagem Json na variável data data["temperature"] = temperature; data["humidity"] = humidity; // Cria string payload String payload; // Serializa a variável data para string payload serializeJson(data, payload); // Por fim, publica esta string no tópico especificado client.publish(topic_publish, payload.c_str()); // Imprime o tópico e a mensagem enviados Serial.print("Publish in topic: "); Serial.print(topic_publish); Serial.print(" , message: "); Serial.print(payload.c_str()); Serial.println(); } else { // Imprime erro caso não tenha obtido os dados do sensor. Serial.print("Erro ao obter dados do DHT"); } }
Resultado do Projeto
Como resultado, deixo o vídeo onde demonstro nosso painel de automação e realizo o controle do dispositivo conforme descrevemos neste artigo.
Então, gostou do nosso projeto? Caso haja alguma dúvida, comente abaixo. Confira mais conteúdos em nosso blog