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.
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.
Todos os materiais, com exceção da case, podem ser comprados em nossa loja
O 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).
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.
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.
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.
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
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):
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
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.
/** * @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.
#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 };
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!
Algumas referências utilizadas no artigo:
Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!
|
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.
Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!