Painel de Automação com ThingsBoard e ESP8266

ThingsBoard
Font Size

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.


Figura 1 – Arquitetura do ThingsBoard

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:

  1. Funcionamento do Sistema
  2. Adicionando Dispositivo na Plataforma
  3. Desenvolvendo Painel de Controle no ThingsBoard
  4. 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:

Figura 2 – Comunicação entre dispositivos e usuário do ThingsBoard

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:

  1. Na página principal, clique em “Devices”.
  2. Em seguida, clique em Add new item, de símbolo “+” e, depois, em “Add new device”.
  3. 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.
  4. Por último, clique em “ADD”.

Os passos descritos podem ser acompanhados na imagem a seguir:


Figura 3 – Adicionando novo dispositivo na plataforma ThingsBoard

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:

  1.  Na página principal, clique em “Dashboards”.
  2. Em seguida, clique em Add new dashboard, de símbolo “+” e, depois, em “Create new dashboard”.
  3. 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. 
  4. 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:

  1. Dentro do painel recém criado, clique em “Enter edit mode”, cujo símbolo é um lápis no canto inferior direito.
  2. Clique na opção “Entity Aliases”, em seguida, clique no botão “ADD ALIAS”.
  3. 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.
  4. Repita o passo anterior adicionando o alias Temperatura e o alias Umidade.
  5. Por fim, clique em “Save” para adicioná-los.

A figura seguinte ilustra resumidamente os passos descritos:


Figura 4 – Configurando Painel no ThingsBoard


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:

  1. Clique na opção “Add New Widget”.
  2. Na guia “Select widgets bundle” escolha a opção “Control widgets” e escolha o widget “Switch control”.
  3. Em seguida, na guia “DATA”, temos o campo “Target device” onde selecionamos o alias que criamos denominado Controle Luz. 
  4. 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}
  5. 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:


Figura 5 – Adicionando Widgets no Painel

Após a realização dos passos descritos, devemos ter um painel com o seguinte visual:


Figura 6 – Visualização Final do Painel

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:

  1. NodeMCU
  2. Módulo Relé 1 Canal Optoacoplado
  3. Sensor de Umidade e Temperatura DHT22
  4. Alguns Jumpers

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:


Figura 7 – Esquema de ligação no NodeMCU

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.

https://youtu.be/L52UaUezk-U

Então, gostou do nosso projeto? Caso haja alguma dúvida, comente abaixo. Confira mais conteúdos em nosso blog

Posts relacionados

Movimento Maker para Solução de Problemas

por autocore
5 anos ago

Luz automática com o Contador Johnson CD4017

por Oderlando Silva
3 anos ago

Conhecendo o Circuito Integrado LM324N

por Luan Fernandes
3 anos ago
Sair da versão mobile