Automação Residencial

Estação Meteorológica Residencial com ESP8266

Eletrogate 12 de julho de 2022

Introdução

Vamos continuar nossa exploração pelo mundo do IoT! Já ficou curioso para saber qual é o status do clima ao vivo do local onde você mora? Muitas pessoas usam aplicativos climáticos, escolhendo o nome da cidade para obter os dados das estações meteorológicas, mas isso não é preciso para sua localização e, nem mesmo, uma informação em tempo real. Então, trouxemos um projeto interessante para fazer uma estação meteorológica doméstica em que exibiremos informações externas como temperatura, humidade, pressão atmosférica, altitude e condições de chuva ou sol. A estação é baseada no ESP8266-12E e sensores temperatura, humidade, altitude, pressão barométrica e de chuva. Uma estação meteorológica é um projeto muito interessante que ensina muito sobre eletrônica e clima.


O que é uma Estação Meteorológica?

Uma estação meteorológica é um dispositivo que coleta dados relacionados ao clima e ao meio ambiente usando diferentes sensores. Existem dois tipos de estações meteorológicas: uma, possui sensores próprios, a outra, depende de extrair dados dos servidores de uma estação meteorológica separada. Neste tutorial, usaremos o primeiro, ou seja, vamos criar a nossa própria estação meteorológica. Os sensores da estação meteorológica podem incluir um termómetro para medir a temperatura, um barómetro para medir a pressão atmosférica, um higrómetro para medir a humidade, um sensor de chuva para medir a precipitação, um anemómetro para medir a velocidade do vento e muito mais. As estações meteorológicas também são chamadas de centros meteorológicos, estações meteorológicas pessoais, estações meteorológicas profissionais ou estações meteorológicas domésticas.


Materiais Necessários para o Projeto Estação Meteorológica Residencial com ESP8266

 Todos os materiais, com exceção da case, podem ser comprados em nossa loja

cta_cart


Descrição dos Componentes

Módulo WiFi ESP8266 IOT USB 12F

ESP8266 12F IOT é uma placa de desenvolvimento que facilita a utilização do ESP8266 12F (Nova Versão), contando com pinos expostos para conexão direta com sensores e módulos, sem precisar de adaptadores extras. Além dos pinos, ainda há conexões exclusivas para display oled e DHT11 e uma porta micro usb para programação e alimentação (5 V).

Display OLED:

O Display OLED de 0.96 polegadas é uma opção muito interessante para quem busca visualizar pouca informação mas, ainda, com muita nitidez. Isso é possível devido ao alto contraste dos displays OLED (Organic Light-Emitting Diode). Cada um dos 128×64 pixels são controlados individualmente via I2C pelo chip controlador SSD1306. O display OLED tem luz própria, logo, não há necessidade de backlight, o que intensifica seu contraste e economiza muita energia. Em caso de duvida sobre o display, consulte nosso tutorial acessando esse link.

Sensor de Umidade e Temperatura DHT11:


O DHT11 é um sensor digital de temperatura e umidade de baixo custo. Ele usa um sensor de umidade capacitivo e um termistor para medir o ar circundante e converte em um sinal digital no pino de dados. É bastante simples de usar, mas requer um tempo para coletar dados. O sinal digital é bastante fácil de ler usando qualquer microcontrolador, como o Arduino ou qualquer um da família ESP.

Sensor de Pressão Barométrica BMP280:

O BMP280 é um módulo eletrônico capaz de realizar a medição de pressão atmosférica e temperatura. Também conhecido como barômetro, é um módulo digital de alta capacidade e resolução, utilizado nas mais diversas aplicações junto a microcontroladores. Através de seu padrão de conexão por I2C, o Sensor de Pressão BMP280 aumenta a sua praticidade de utilização, além de contribuir na maior precisão da obtenção de resultados por meio de um módulo tão compacto.

Sensor de chuva:

Sensores de chuva são usados na detecção de água em níveis superiores aos que um sensor de umidade pode detectar. O sensor de chuva detecta a água que corre nas trilhas impressas de sua placa sensor. A placa do sensor atua como um resistor variável, que mudará de 100k ohms, quando molhado, para 2M ohms, quando seco. Em suma, quanto mais molhada a placa, mais corrente será conduzida. O modelo utilizado vem com uma placa de medição com um amplificador operacional LM393, que permite que a leitura seja obtida tanto em valor analógico quanto digital, com uma referência regulada através do pequeno potenciômetro (Trimpot) localizado na placa. Os valores analógicos medidos variam de 0, quando molhada, a 1023 quando seca. Caso necessário, aumente os cabos do sensor de chuva, para colocar longe da estação

Case para o circuito (Opcional):

A case para armazenar o circuito, além de proteger contra o sol e chuva, serve para pendurar na parede. A case pode ser impressa em ABS, PLA ou PETG.

Arquivos para impressão (.stl):

Arquivos editáveis (.ipt):


Circuito

Na imagem do circuito, foi utilizada a placa ESP8266 NodeMCU. Mas, no projeto real, utilizamos o Módulo WiFi ESP8266 IOT USB 12F. No circuito, utilizamos um divisor de tensão com dois resistores de 4.7 Kohms para reduzir a tensão.

Conexões:

> SDA do display e BMP280 – GPIO 2 ou pino D4
> SCL do display e BMP280 – GPIO 14 ou pino D5
> SENSOR CHUVA – Pino A0
> SENSOR HUMIDADE – GPIO 5 ou pino D1


Código

Para compilar o código da estação meteorológica, são necessárias as seguintes bibliotecas:

BMP280.h – Para o sensor BMP280, disponível em:  Github
DHTesp.h – Para o sensor DHT11, disponível em:  Github
SSD1306.h – Para o Display OLED, disponível em:  Github
images.h – Para gerar as imagens no display, biblioteca disponível logo a baixo

O programa da estação lê todos os sensores e, em seguida, imprime no display OLED, seguindo uma sequencia pré-definida.

Código principal:

/**
 * @file Estacao_metereologica.ino
 * Modificado por: Saulo Aislan
 * @brief Firmware responsável captar dados dos sensores e exibir no display OLED.
 * @version 0.1
 * 
 * @copyright Copyright (c) 2022
 * 
*/
#include <Wire.h>
#include "BMP280.h"
#include "DHTesp.h"
#include "SSD1306.h"
#include "images.h"

#define SDA    2
#define SCL   14
#define RST   26 // Não usado
#define DISPLAY_ADDR 0x3c // Endereco do I2c do display
#define BMP280_ADDR 0x76 // Endereco do I2c do BMP280
#define P0 1013.25 // Pressão ao nível do mar
#define PIN_SENSOR_CHUVA A0
#define PIN_SENSOR_HUMIDADE 5 // DHT11
#define DELAYINLOOP 2000
#define TRANSITION_DUARTION 3000

BMP280 bmp;
DHTesp dht;

SSD1306  display(DISPLAY_ADDR, SDA, SCL, RST);

typedef void (*Demo)(void);

long timeSinceLastModeSwitch = 0;
int demoMode = 0;
double temperatura, alti, pressao;          
float humidade;

/* Prototipo da funcao */
void drawSun();
void drawCloud();
void getdados();
bool estaChovendo();
void printCloud();
void printTemp();
void printHumi();
void printPressao();
void printAltitude();

// Vetor com os endereco das funcoes
Demo demos[] = {printCloud, printTemp, printPressao, printAltitude, printHumi};
int demoLength = (sizeof(demos) / sizeof(Demo));

/**
 * @brief Setup
 */
void setup()
{
  Serial.begin(115200);
  pinMode(PIN_SENSOR_CHUVA, INPUT);
  dht.setup(PIN_SENSOR_HUMIDADE, DHTesp::DHT11);
  
  if(!bmp.begin(SDA, SCL))
  {
    Serial.println("BMP init failed!");
    while(1);
  }
  else Serial.println("BMP init success!");
  
  bmp.setOversampling(4); // Resolução das medidas

  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_16);
  display.display();
}

/**
 * @brief Desenha no Display um sol
 */
void drawSun()
{
  display.clear();
  display.drawXbm(41, 0, SUN_WIDTH, SUN_HEIGHT, sun_icon);
  display.display();
}

/**
 * @brief Desenha no Display uma nuvem chuvosa
 */
void drawCloud()
{
  display.clear();
  display.drawXbm(41, 0, CLOUD_WIDTH, CLOUD_HEIGHT, cloud_rain_icon);
  display.display();
}

/**
 * @brief Chama a funcao para verificar o clima e chama a
 * funcao para imprime o status
 */
void printCloud()
{
  display.setFont(ArialMT_Plain_16);
  display.clear();
  
  if(estaChovendo())
  {
    drawCloud();
    display.drawString(23, 48, "Chovendo...");
  }
  else
  {
    drawSun();
    display.drawString(23, 47, "Sem Chuva...");
  }
  
  display.display();        // update the display
}

/**
 * @brief Imprime a temperatura no display
 */
void printTemp()
{
  display.setFont(ArialMT_Plain_16);
  display.clear();
  display.drawString(18, 0, "Temperatura");
  display.setFont(ArialMT_Plain_24);
  if (temperatura < 0)
   display.drawString(15, 20, "-"+(String)temperatura+"  C" );
  else
   display.drawString(15, 20, " "+(String)temperatura+"  C");
   
  display.drawRect(89, 25, 5, 5); // Simbolo ( ° )
  display.display();
}

/**
 * @brief Imprime a humidade no Display
 */
void printHumi()
{
  display.setFont(ArialMT_Plain_16);
  display.clear();
  display.drawString(25, 0, "Humidade");
  display.setFont(ArialMT_Plain_24);
  display.drawString(15, 20, " "+(String)humidade+" %");
  display.display();
}

/**
 * @brief Imprime a pressão no Display
 */
void printPressao()
{
  display.setFont(ArialMT_Plain_10);
  display.clear();
  display.drawString(18, 5, "Pressão");
  display.drawString(60, 5, "Atmosférica");
  display.setFont(ArialMT_Plain_24);
  display.drawString(5, 20, (String)pressao+" hPa" );
  display.display();
}

/**
 * @brief Imprime a altitude no Display
 */
void printAltitude()
{
  Serial.println(alti);
  display.setFont(ArialMT_Plain_16);
  display.clear();
  display.drawString(37, 0, "Altitude");
  display.setFont(ArialMT_Plain_24);
  display.drawString(15, 20, (String)alti+" m" );
  display.display();        // update the display
}

/**
 * @brief Ler os sensores, armazena os dados nas variaveis e imprime na serial
 */
void getdados()
{
  char result = bmp.startMeasurment();
  double tempBMP;

  Serial.print("\n\n---------- Dados ----------\n");
  
  if(result!=0)
  {
    delay(result);
    result = bmp.getTemperatureAndPressure(tempBMP,pressao);
    
      if(result!=0)
      {
        alti = bmp.altitude(pressao,P0);
      }
      else
      {
        Serial.println("Error.");
      }
  }
  else
  {
    Serial.println("Error.");
  }

  humidade = dht.getHumidity();
  if (isnan(humidade))
  {
    Serial.println("Failed to read from DHT sensor!");
    humidade = 0;
  }
  else
  {
    Serial.print("Humidade: ");
    Serial.println(humidade);
  }

  float tempDHT = dht.getTemperature();
  
  if (isnan(tempDHT))
  { 
    Serial.println("Failed to read from DHT sensor!");
    tempDHT = 0;
    temperatura = tempBMP;
  }
  else
  {
    temperatura = (tempBMP + tempDHT) / 2; // Calcula uma temperatura media entre os dois sensores
  }

  Serial.print("Temperatura sensor DHT11: ");
  Serial.println(tempDHT);        
  Serial.print("Temperatura sensor BMP280:");
  Serial.print(tempBMP,2);
  Serial.println(" °C");
  Serial.print("Pressão: ");
  Serial.print(pressao,2);
  Serial.println(" hPa");
  Serial.print("Altitude: ");
  Serial.print(alti,2);
  Serial.println(" m");
  Serial.print("Sensor de Chuva: ");
  Serial.print(analogRead(PIN_SENSOR_CHUVA)); 
  Serial.println("  ");
  
  estaChovendo();
}

/**
 * @brief Verifica se esta chovendo, lendo o sinal analogico do sensor
 * @return bool Se esta chovendo ou nao
 */
bool estaChovendo()
{
  if (analogRead(PIN_SENSOR_CHUVA) > 900)
  {
    Serial.println("Não está chovendo...");
    return false;
  }
  else
  {
    Serial.println("Chovendo!!!");
    return true;
  }
}

/**
 * @brief Loop
 */
void loop()
{ 
  getdados();
  
  display.clear();   // Limpar o display
  demos[demoMode]();  // Vetor com os endereco das funcoes
  display.display();   // Atualiza o display com a nova tela

  if (millis() - timeSinceLastModeSwitch > TRANSITION_DUARTION)
  {
    demoMode = (demoMode + 1) % demoLength;
    timeSinceLastModeSwitch = millis();
  }

  delay(DELAYINLOOP);
}

Biblioteca que contém o código para gerar a imagens do display OLED.  Em caso de duvida sobre o display consulte o nosso tutorial acessando esse link.

Código da biblioteca images.h:

#define CLOUD_WIDTH 48
#define CLOUD_HEIGHT 48
#define SUN_WIDTH 48
#define SUN_HEIGHT 48

const unsigned char cloud_rain_icon [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x3F, 0x7E, 0x1F, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0x33, 0x00, 0x00, 0xE0, 0xEF, 0x01, 0x31, 0x00, 
  0x00, 0xF0, 0x80, 0x03, 0x22, 0x00, 0x00, 0x78, 0x80, 0x7F, 0x60, 0x00, 
  0x00, 0x38, 0x00, 0xFF, 0xE0, 0x03, 0x00, 0x1C, 0x00, 0xC7, 0xE0, 0x03, 
  0x00, 0x1C, 0x00, 0x80, 0x21, 0x07, 0x00, 0x1C, 0x00, 0x80, 0x01, 0x06, 
  0x00, 0x1C, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x1F, 0x00, 0x80, 0x1F, 0x06, 
  0x80, 0x3F, 0x00, 0x00, 0x18, 0x03, 0xC0, 0x3F, 0x00, 0x00, 0xB0, 0x03, 
  0xC0, 0x01, 0x00, 0x00, 0x70, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x01, 
  0xE0, 0x00, 0x00, 0x00, 0xE0, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x03, 
  0xE0, 0x00, 0x20, 0x00, 0x00, 0x03, 0xE0, 0x01, 0x31, 0x00, 0x80, 0x03, 
  0xC0, 0x83, 0x7F, 0x01, 0xEC, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0x00, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xE0, 0x00, 0xB0, 0x06, 0x00, 
  0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x06, 0x40, 0x10, 0x00, 0x00, 
  0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x63, 0xC0, 0x00, 0x00, 
  0x00, 0x83, 0x23, 0x60, 0x00, 0x00, 0x00, 0x80, 0x01, 0x62, 0x00, 0x00, 
  0x00, 0x80, 0x00, 0x63, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 
  0x00, 0x06, 0x80, 0x11, 0x00, 0x00, 0x00, 0x07, 0x08, 0x18, 0x00, 0x00, 
  0x00, 0x03, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x62, 0x04, 0x0C, 0x00, 0x00, 
  0x00, 0x30, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x00, 
  0x00, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x00, 0x00, 
  0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const unsigned char sun_icon [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x04, 0x80, 0x01, 0x20, 0x00, 
  0x00, 0x0E, 0x80, 0x01, 0x70, 0x00, 0x00, 0x1C, 0x80, 0x01, 0x38, 0x00, 
  0x00, 0x38, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 
  0x00, 0x60, 0xC0, 0x01, 0x06, 0x00, 0x00, 0x40, 0xF8, 0x1F, 0x02, 0x00, 
  0x00, 0x00, 0x7C, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x70, 0x00, 0x00, 
  0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x80, 0x03, 0xC0, 0x01, 0x00, 
  0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 
  0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0xF0, 0xC7, 0x00, 0x00, 0xF3, 0x0F, 
  0xF0, 0xCF, 0x00, 0x00, 0xE3, 0x0F, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 
  0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 
  0x00, 0x80, 0x03, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 
  0x00, 0x00, 0x0E, 0x70, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3E, 0x00, 0x00, 
  0x00, 0x40, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0x60, 0x80, 0x03, 0x07, 0x00, 
  0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1C, 0x00, 
  0x00, 0x1C, 0x80, 0x01, 0x38, 0x00, 0x00, 0x0E, 0x80, 0x01, 0x70, 0x00, 
  0x00, 0x04, 0x80, 0x01, 0x20, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 
};

Conclusão

Nesse tutorial, vimos uma aplicação simples e interessante em que utilizamos sensores de fácil implementação, mas com um resultado impressionante. Você pode modificar o projeto para o seu contexto, adicionando ou retirando sensores, usando outra case ou usando display OLED para mostrar outras mensagens. Se precisar de um alerta sobre a chuva, acrescente um Buzzer e aumente os cabos do sensor de chuva para colocar longe da estação. Use a imaginação. Para mais materiais como esse, continue acompanhando as postagens semanais do blog e não deixe de visitar nossa loja. Lá, você encontra todos os componentes necessários para desenvolver esse e muitos outros projetos! Que a força esteja com vocês e até mais!


Sobre o Autor


Saulo Aislan

Graduando em Tecnologia em Telemática pelo IFPB – Campus de Campina Grande – PB. Tenho experiência com os microcontroladores da família Arduino, ESP8266, ESP32, STM32 e microprocessador Raspberry Pi. Tenho projetos na áreas de IoTs voltada para a indústria 4.0, agroindústria e indústria aeroespacial civil utilizando LoRa, Bluetooth, ZigBee e Wi-Fi. Atualmente estudando e desenvolvendo em FreeRTOS para sistemas em tempo real com ESP32 e LoRaWan para Smart City e compartilhando alguns projetos no blog da Eletrogate.


Eletrogate

12 de julho de 2022

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!

Eletrogate Robô

Assine nossa newsletter e
receba  10% OFF  na sua
primeira compra!