Automação residencial usando MQTT

Hoje vamos criar um projeto de automação residencial usando MQTT, um protocolo de comunicação muito utilizado em projetos de IoT (Internet of Things ou Internet das Coisas).

O MQTT funciona por meio de “mensagens”: de um lado você tem um emissor (o Publisher) que vai enviar informações para um servidor (o Broker) que por sua vez vai distribuir essa mensagem para os receptores (o Subscriber).

Essa tal mensagem pode ser um simples alarme, uma informação de temperatura ou algum outro dado obtido de um sensor. Como Subscriber podemos ter aparelhos como smartphones, computadores, tablets e também placas como ESP8266, ESP32, Raspberry Pi e Arduino por exemplo.

Neste post vamos usar como Publisher um Wio Terminal (que já vimos no post anterior) e como Subscriber um módulo Wifi ESP8266 NodeMCU acoplado a um módulo relé 2 canais.

Nada impede que você faça adaptações no projeto e utilize por exemplo com módulos ESP8266 ou ESP32 nas duas pontas. O funcionamento básico é o mesmo.

Componentes do projeto de automação residencial usando MQTT

Como mencionado acima, vamos usar o seguinte material:

O Wio Terminal terá a função de enviar os comandos de ligar e desligar os relés. Ele fará a conexão na rede Wifi e ao acionarmos os botões ele vai enviar as mensagens para o Broker MQTT (mqtt.eclipseproject.iot).

Na outra ponta, teremos o ESP8266 NodeMCU “escutando” o Broker e quando receber uma nova mensagem ele vai ligar ou desligar os relés conectados nas portas D1 e D2.

O módulo relé 2 canais pode controlar até dois equipamentos como eletrodomésticos, motores, lâmpadas, etc, desde que a corrente não ultrapasse 10A.

Configuração do Wio Terminal

No Wio Terminal vamos usar os 3 botões superiores para selecionar o relé desejado (relé 1 ou 2) e para alterar o estado (ligado ou desligado):

No Wio não temos nenhuma conexão adicional de hardware então vamos direto ao programa, que vai exigir a instalação de algumas várias bibliotecas. São elas:

Faça a instalação de cada uma delas a partir da IDE do Arduino, no menu Sketch -> Incluir Biblioteca -> Gerenciar Bibliotecas. Dentro do Gerenciador de Biblioteca, procure por cada uma delas e clique em instalar.

Dúvidas na instalação da biblioteca? Confira o post Como instalar uma biblioteca na IDE Arduino.

Vamos carregar o programa abaixo no Wio Terminal. Antes de mais nada preencha as informações da sua rede Wifi (nome e senha) nas linhas 10 e 11 do programa.

//Programa: Comunicacao MQTT Wio Terminal e ESP8266 - Publisher (Wio)
//Autor: Arduino e Cia

#include <rpcWiFi.h>
#include <WiFiClient.h>
#include <TFT_eSPI.h>
#include <PubSubClient.h>

//Preencha abaixo as informacoes da sua rede Wifi
const char* ssid = "NOME_DA_REDE_WIFI";
const char* password = "SENHA_DA_REDE_WIFI";
const char* mqtt_server = "mqtt.eclipseprojects.io";  //Endereco do Broker MQTT

TFT_eSPI tft;

WiFiClient wioClient;
PubSubClient client(wioClient);

//Buffer de mensagem
char msg[50];

//Informacoes dos reles
bool rele_selecionado = 0;
bool estado_rele[2];
int cor_botao[2];
String estado[2];

void setup_wifi()
{
  delay(10);

  tft.setTextColor(TFT_BLUE);
  tft.setTextSize(1);
  tft.setCursor((320 - tft.textWidth("arduinoecia.com.br")) / 2, 225);
  tft.print("arduinoecia.com.br");

  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.setCursor((320 - tft.textWidth("Conectando Wi-Fi..")) / 2, 120);
  tft.print("Conectando Wi-Fi..");

  Serial.println();
  Serial.print("Conectando em ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi conectado!");

  tft.fillRect(0, 0, 320, 200, TFT_BLACK);
  tft.setCursor((320 - tft.textWidth("Conectado!")) / 2, 140);
  tft.print("Conectado!");
  tft.setCursor((320 - tft.textWidth("192.168.0.190")) / 2, 180);
  tft.print(WiFi.localIP());

  Serial.println("Endereco IP: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length)
{
  //Rotina para tratamento de mensagem recebidas
  Serial.print("Mensagem recebida [");
  Serial.print(topic);
  Serial.print("] ");
  char buff_p[length];
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    buff_p[i] = (char)payload[i];
  }

  //Mostra informacoes no Serial Monitor
  Serial.println();
  buff_p[length] = '\0';
  String msg_p = String(buff_p);
  tft.fillScreen(TFT_BLACK);
  tft.setCursor((320 - tft.textWidth("Mensagem MQTT")) / 2, 90);
  tft.print("Mensagem MQTT: " );
  tft.setCursor((320 - tft.textWidth(msg_p)) / 2, 120);
  tft.print(msg_p);
}

void reconnect()
{
  //Loop de reconexao
  while (!client.connected())
  {
    Serial.print("Tentando conexao ao broker MQTT...");
    String clientId = "Wio_Terminal";
    clientId += String(random(0xffff), HEX);
    //Tentativa de conexao
    if (client.connect(clientId.c_str()))
    {
      Serial.println("conectado");
      //Publica mensagem de teste
      //client.publish("ArduinoeCia_Wio", "Wio Terminal conectado!");
    } else
    {
      Serial.print("falhou, rc=");
      Serial.print(client.state());
      Serial.println(" tentando novamente em 5 segundos");
      delay(5000);
    }
  }
}

void setup()
{
  //Inicializa o display
  tft.begin();
  tft.fillScreen(TFT_BLACK);
  tft.setRotation(3);

  //Definicoes botoes
  pinMode(WIO_KEY_A, INPUT_PULLUP);
  pinMode(WIO_KEY_B, INPUT_PULLUP);
  pinMode(WIO_KEY_C, INPUT_PULLUP);

  //Informacoes iniciais no Serial Monitor
  Serial.begin(115200);
  Serial.println();
  setup_wifi();
  client.setServer(mqtt_server, 1883); // Connect the MQTT Server
  client.setCallback(callback);

  //Estado inicial dos relés - ambos desligados
  estado_rele[0] = 0;
  estado_rele[1] = 0;

  //Desenho inicial botoes
  desenha_botoes();
}

void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (digitalRead(WIO_KEY_A) == LOW)
  {
    while (digitalRead(WIO_KEY_A) == LOW)
    {
      delay(50);
    }
    Serial.println("Botao 3 pressionado");
    rele_selecionado = !rele_selecionado;
    Serial.print("Rele selecionado: ");
    Serial.println(rele_selecionado);
    desenha_botoes();
    if (rele_selecionado == 0)
    {
      tft.fillCircle(30, 35, 10, TFT_WHITE);
    }
    if (rele_selecionado == 1)
    {
      tft.fillCircle(30, 88, 10, TFT_WHITE);
    }

  }
  else if (digitalRead(WIO_KEY_B) == LOW)
  {
    //Ligar rele
    estado_rele[rele_selecionado] = 0;
    desenha_botoes();
    String comando = "D";
    String envio = comando + rele_selecionado;
    envio.toCharArray(msg, 10);
    Serial.print("String a ser enviada: ");
    Serial.println(msg);
    client.publish("ArduinoeCia_Wio", msg);
  }
  else if (digitalRead(WIO_KEY_C) == LOW)
  {
    estado_rele[rele_selecionado] = 1;
    desenha_botoes();
    String comando = "L";
    String envio = comando + rele_selecionado;
    envio.toCharArray(msg, 10);
    Serial.print("String a ser enviada: ");
    Serial.println(msg);
    client.publish("ArduinoeCia_Wio", msg);
  }
  delay(200);
}

void desenha_botoes()
{
  for (int i = 0; i <= 1; i++)
  {
    if (estado_rele[i] == 0)
    {
      cor_botao[i] = 0xF800; //vermelho
      estado[i] = "DESLIGADO";
    }
    else if (estado_rele[i] == 1)
    {
      cor_botao[i] = 0x07E0; //verde
      estado[i] = "LIGADO";
    }
  }

  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(4);

  //Desenha botao 1
  tft.fillRoundRect(10, 10, 300, 50, 5, cor_botao[0]);
  tft.fillCircle(30, 35, 10, cor_botao[0]);
  tft.setCursor((320 - tft.textWidth(estado[0])) / 2, 21);
  tft.print(estado[0]);

  //Desenha botao 2
  tft.fillRoundRect(10, 65, 300, 50, 5, cor_botao[1]);
  tft.fillCircle(30, 88, 10, cor_botao[1]);
  tft.setCursor((320 - tft.textWidth(estado[1])) / 2, 76);
  tft.print(estado[1]);

  //Desenha a marcacao no botão selecionado
  if (rele_selecionado == 0)
  {
    tft.fillCircle(30, 35, 10, TFT_WHITE);
  }
  if (rele_selecionado == 1)
  {
    tft.fillCircle(30, 88, 10, TFT_WHITE);
  }
}

Ao acionar os botões, o Wio vai enviar informações para um tópico chamado ArduinoeCia_Wio. Essas informações serão lidas pelo ESP: o comando L0 liga o relé 1 e D0 desliga. L1 e D1 tem a mesma função, mas controlando o relé 2.

Para facilitar o acompanhamento e verificar eventuais erros, são enviadas informações de depuração para o Serial Monitor.

Configuração do ESP8266

Para configuração da IDE do Arduino com o ESP8266 NodeMCU, recomendo a leitura do post Como usar o NodeMCU ESP8266. O link vai direto para a parte de instalação do ESP na IDE.

Com a IDE configurada, siga o esquema de conexão abaixo para ligação do módulo relé 2 canais no NodeMCU.

O primeiro relé (pino IN1 do módulo) será acionado pela porta D1 do NodeMCU, e o segundo relé pela porta D2:

A alimentação do módulo relé será feita pelos pinos Vin e GND do NodeMCU.

Carregue o programa abaixo na placa, alterando nas linhas 8 e 9 as informações do nome e senha da rede Wifi, da mesma forma que fizemos com o programa do Wio Terminal.

//Programa: Comunicacao MQTT Wio Terminal e ESP8266 - Subscriber (ESP8266)
//Autor: Arduino e Cia

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//Preencha abaixo as informacoes da sua rede Wifi
const char* ssid = "NOME_DA_REDE_WIFI";
const char* password = "SENHA_DA_REDE_WIFI";
const char* mqtt_server = "mqtt.eclipseprojects.io"; //Endereco do Broker MQTT

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE	(50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

void setup_wifi()
{
  delay(10);
  Serial.println();
  Serial.print("Conectando a ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi conectado");
  Serial.println("Endereco IP: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensagem recebida [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  //Verifica se L0 ou D0 foram recebidos e altera o estado do rele 1
  if ((char)payload[0] == 'L' and (char)payload[1] == '0') {
    Serial.println("Caracteres recebidos corretamente! Ligando rele 1");
    digitalWrite(5, LOW);
  } else if ((char)payload[0] == 'D' and (char)payload[1] == '0') 
  {
    digitalWrite(5, HIGH);
  }

  //Verifica se L1 ou D1 foram recebidos e altera o estado do rele 2
  if ((char)payload[0] == 'L' and (char)payload[1] == '1')
  {
    Serial.println("Caracteres recebidos corretamente! Ligando rele 2");
    digitalWrite(4, LOW);
  } else if ((char)payload[0] == 'D' and (char)payload[1] == '1') 
  {
    digitalWrite(4, HIGH);
  }
}

void reconnect()
{
  //Loop de reconexao
  while (!client.connected()) {
    Serial.print("Tentando conexao MQTT...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      //Conectado, envia mensagem de teste
      //client.publish("", "Hello World!");

      //Subscribe no topico ArduinoeCia_Wio
      client.subscribe("ArduinoeCia_Wio");
    } else {
      Serial.print("falhou, rc=");
      Serial.print(client.state());
      Serial.println(" tentando novamente em 5 segundos");
      delay(5000);
    }
  }
}

void setup()
{
  Serial.begin(115200);

  //Portas dos reles
  pinMode(5, OUTPUT); //Rele 1 na porta D1 - GPIO5
  pinMode(4, OUTPUT); //Rele 2 na porta D2 - GPIO4

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  //Desliga os reles na inicializacao
  digitalWrite(5, HIGH);
  digitalWrite(4, HIGH);
}

void loop() 
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
  }
}

O que esse programa faz é se conectar no broker MQTT e “assinar” o tópico ArduinoeCia_Wio (aquele que foi criado pelo programa do Wio Terminal). Ao fazer isso, o ESP8266 aguarda as mensagens L0, D0, L1 e D1 e aciona as portas do relé 1 (D1 – GPIO5) ou do relé 2 (D2 – GPIO4).

Da mesma maneira que no Wio, você pode acompanhar o processo de recebimento de mensagem usando o Serial Monitor.

Também é possível usar um aplicativo como o MyMQTT no smartphone, assinar o tópico ArduinoeCia_Wio e verificar se as mensagens estão sendo enviadas corretamente.

Gostou? Confira outros posts sobre IoT aqui mesmo no Arduino e Cia!

5/5 - (1 voto)

Related posts

Relógio com NodeMCU ESP8266 usando NTP

by Arduino e Cia
7 anos ago

Use o Blynk e ESP8266 para mostrar temperatura e umidade na tela do celular

by Arduino e Cia
3 anos ago

Digispark com DHT11 e Display LCD 16×2 I2C

by Arduino e Cia
7 anos ago
Sair da versão mobile