Este artigo apresenta o projeto de uma mini estação meteorológica utilizando um Arduino UNO, capaz de realizar medição de luminosidade, temperatura, umidade, índice UV, pressão atmosférica e material particulado, além de se comunicar com a internet através de um módulo wi-fi ESP8266 ESP-01 utilizando a plataforma ThingSpeak.
Neste artigo são abordados:
- Montagem do hardware: conexão dos sensores e módulo de comunicação ESP8266 com o Arduino UNO;
- Desenvolvimento do firmware para leitura dos sensores e postagem dos dados no Thingspeak;
- Publicação e consulta dos dados através do Thingspeak.
Esse projeto foi desenvolvido por Igor Fonseca Albuquerque, e apresentado no Genuino Day – Santos, SP, em 02 de abril de 2016.
Motivação
A Baixada Santista é uma das principais atrações turísticas do estado de São Paulo, atraindo milhares de visitantes às suas praias todos os anos. São comuns as notícias de engarrafamentos quilométricos rumo à região em feriados prolongados e nos finais de semana ensolarados do verão. Conhecidas pelo elevado número de dias nublados, em virtude da proximidade à Serra do Mar, as cidades litorâneas veem sua população se multiplicar em qualquer sinal de dias de sol e calor.
A região abriga ainda um dos maiores portos do país, o qual realiza o escoamento de boa parte da produção de grãos das regiões sudeste e centro-oeste do Brasil, além do transporte e armazenamento de produtos químicos, combustíveis e conteiners. O transporte da soja, em particular, é uma das atividades que mais trazem transtornos à população dos bairros próximos aos terminais portuários, devido às emissões de materiais particulados e aos odores exalados pela fermentação dos grãos.
Nos últimos anos, notícias envolvendo incêndios de grandes proporções na área portuária têm sido frequentes na mídia, divulgando negativamente a imagem da região, com potencial de dano para a saúde da população e de impactos ao meio ambiente.
Todas essas características relacionadas ao clima e qualidade do ar da região serviram de motivação para o desenvolvimento da plataforma aberta de monitoramento do clima apresentada nesse trabalho.
Montagem do hardware
Nesse projeto foi proposto um sistema capaz de coletar dados ambientais de diversos sensores, processar as variáveis medidas e disponibilizá-las publicamente na internet para acesso remoto.
Foram selecionados sensores capazes de realizar a medição de pressão atmosférica, temperatura, umidade relativa do ar, luminosidade, índice UV e material particulado.
Os seguintes componentes foram especificados para o projeto:
- Arduino UNO: placa de microcontrolador baseado no ATmega328P, com 14 pinos de entrada/saída digital, 6 entradas analógicas, conexão USB (Figura 4);
- Sensor de luminosidade: módulo baseado em um LDR (light dependent resistor). Apresenta uma saída analógica proporcional à intensidade luminosa do ambiente, sendo que a sua resistência cai quando a intensidade luminosa aumenta (Figura 5);
- Sensor de intensidade UV: mede a intensidade do sinal luminoso na faixa de 200 a 400 nm, gerando um sinal analógico que pode ser usado para o cálculo de índice UV (Figura 6);
- Sensor de pressão atmosférica (BMP085): sensor de pressão atmosférica baseado no chip BMP085, para pressão entre 300 e 1100 hPa. Comunicação com microcontrolador através protocolo I2C (Figura 7);
- Sensor de temperatura e umidade (DHT-22): permite a leitura de temperaturas entre -40 a +80 °C e umidade entre 0 a 100%. Comunicação com o Arduino através de sinal digital (Figura 8);
- Sensor de material particulado: indica a concentração de material particulado de 1.0 a 2.5 μm (Figura 9);
- Módulo wi-fi (ESP8266 ESP-01): módulo wi-fi capaz de realizar a interface do microcontrolador, através de comunicação serial, com uma rede 802.11b/g/n (Figura 10).
Podem ser utilizados diferentes modelos de sensores, de diferentes fabricantes, desde que respeitados os tipos de sinais trocados entre o controlador (Arduino) e os sensores.
Para facilitar a montagem do protótipo, foi utilizado um protoshield (Figura 11), simplificando assim a interligação dos componentes.
As figuras abaixo ilustram a interligação entre os componentes e uma foto do circuito com todos os sensores conectados.
Desenvolvimento do firmware
O código utilizado foi desenvolvido utilizando-se o Arduino IDE 1.0.5. A figura abaixo apresenta um diagrama de blocos do programa que foi desenvolvido.
Após a inicialização dos sensores e da conexão com o módulo wi-fi, na etapa de setup, o Arduino entra em um loop infinito no qual realizada a leitura dos sensores, tratamento e transmissão dos dados.
Leitura dos sensores e tratamento dos dados
O projeto utiliza sensores analógicos (de luminosidade e UV) e digitais (de umidade, temperatura, pressão e material particulado).
O valor medido nos sensores analógicos deve ser processado para convertê-los para a unidade desejada. O trecho de código abaixo apresenta como é feita a leitura e conversão dos valores lidos de luminosidade e índice UV.
//leitura do sensor de luminosidade float luminance = analogRead(luminancePin); //leitura do sensor UV float uv = analogRead(uvPin); uv = uv * 0.0049; //converter para V uv = uv * 307; //converter para mW/m² uv = uv/200; //índice UV
A transmissão dos dados entre o sensor de temperatura e umidade DHT22 e o Arduino é realizada através de um protocolo de comunicação digital próprio, utilizando-se a biblioteca existente para Arduino.
//leitura do sensor de temperatura e umidade int chk = DHT.read22(DHT22_PIN); float humidity = DHT.humidity; float temperature = DHT.temperature;
A leitura do sensor de pressão é realizada através de protocolo I2C, no qual o Arduino solicita os dados ao sensor e aguarda a chegada de um evento (que pode contar os dados de pressão ou temperatura do sensor).
//leitura do sensor de pressão
sensors_event_t event;
bmp.getEvent(&event);
float pressure = 0;
if (event.pressure)
{
pressure = event.pressure;
}
Para realizar a leitura da concentração de material particulado é utilizada uma das entradas digitais do Arduino. O sensor é composto por um laser e um fotodetector. Na ausência de material particulado, o laser incide diretamente sobre o detector, levando a saída do sensor para nível lógico alto. A passagem de material particulado faz com que o feixe seja obstruído, levando a saída para zero (Figura 15).
A estimativa da concentração de material particulado é feita verificando-se a porcentagem do tempo no qual a entrada digital do Arduino fica em nível lógico baixo, conforme representado abaixo.
O trecho de código abaixo ilustra a rotina de estimativa da concentração de material particulado. No exemplo abaixo o controlador calcula o tempo em que a entrada digital ficou em nível lógico baixo durante um período de amostragem de 30 segundos, e calcula a porcentagem de tempo para a qual permaneceu nesse estado.
//medição do material particulado
duration = pulseIn(dustPin, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
//ciclo de amostragem de 30 segundos
if ((millis() - starttime) >= sampletime_ms) //se o sample time == 30s
{
ratio = lowpulseoccupancy/(sampletime_ms*10.0); // porcentagem (de 0 a 100%)
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // dados do datasheet
lowpulseoccupancy = 0;
}
Conexão com wi-fi
A conexão com um roteador específico é realizada durante o setup() do Arduino. Para isso, deve ser informado o SSID e a senha para conexão da rede.
#define SSID "xxxxx" #define PASS "xxxxx"
Durante a conexão, o módulo wi-fi é colocado no modo station e solicitado para se conectar com o roteador informado. O módulo deverá permanecer conectado indefinidamente.
boolean connectWiFi(){
Serial.println("Conectando wi-fi...");
String cmd ="AT+CWMODE=1";
monitor.println(cmd);
delay(2000);
monitor.flush(); //clear buffer
cmd="AT+CWJAP=\"";
cmd+=SSID;
cmd+="\",\"";
cmd+=PASS;
cmd+="\"";
monitor.println(cmd);
delay(5000);
if(monitor.find("OK")){
Serial.println("Conectado com sucesso!");
return true;
}else{
Serial.println("Falha na conexao!");
return false;
}
Serial.println();
}
Envio dos dados para o Thingspeak
O Thingspeak é uma plataforma de armazenamento de dados na nuvem, ideal para desenvolvimento de dispositivos IoT. Os dados são acessíveis através do site ThingSpeak, por qualquer dispositivo com acesso à internet, podendo ser categorizados como dados públicos ou privados.
Os dados enviados pelos dispositivos são organizados em canais, cada um capaz de armazenar os dados históricos de até 8 variáveis medidas, que podem ser consultados ou exportados em formato CSV. É possível ajustar os gráficos de visualização de cada variável, configurando-se título dos gráficos, escala de tempo e tratamento dos dados (cálculo dos valores médios, medianos ou somados).
Após a conexão do módulo ESP8266 ao roteador, deve-se abrir uma conexão http com o ThingSpeak (através do IP 184.106.153.149), informar a quantidade de bytes da mensagem que será transmitida e na sequência enviar os dados através de uma instrução GET. Na mensagem enviada deve ser apresentada a chave (API key) do canal (channel) que armazenará os dados, juntamente com os valores medidos para cada campo (field1, field2, …, field8). O trecho de código abaixo ilustra como é feito o envio dos dados lidos para um canal do ThingSpeak.
#define IP "184.106.153.149" // thingspeak.com
String GET = "GET /update?key=xxxxx&field1=";
void updateSensors(String luminanceStr, String humidityStr, String temperatureStr, String uvStr, String dustStr, String pressureStr, String temperature1Str) {
String cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += IP;
cmd += "\",80";
monitor.println(cmd);
delay(2000);
cmd = GET;
cmd += luminanceStr;
cmd += "&field2=";
cmd += humidityStr;
cmd += "&field3=";
cmd += temperatureStr;
cmd += "&field4=";
cmd += uvStr;
cmd += "&field5=";
cmd += dustStr;
cmd += "&field6=";
cmd += pressureStr;
cmd += "&field7=";
cmd += temperature1Str;
cmd += "\r\n";
delay(1000);
int strsize = cmd.length();
monitor.println("AT+CIPSEND=" + String(strsize));
delay(2000);
monitor.print(cmd);
if(monitor.find("OK")){
Serial.println("Dados transmitidos com sucesso");
}else{
Serial.println("Falha na transmissao");
}
}
A figura abaixo ilustra os gráficos que podem ser obtidos da estação através do ThingSpeak, o qual teve seus dados definidos como públicos.
Código completo
#include<stdlib.h>
#include <SoftwareSerial.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#define SSID "xxxxx"
#define PASS "xxxxx"
#define IP "184.106.153.149" // thingspeak.com
#define DHT22_PIN 2
String GET = "GET /update?key=xxxxx&field1=";
SoftwareSerial monitor(10, 11); // Definição de canal serial para módulo ESP8266 (RX, TX)
dht DHT;
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
//Definição de variáveis
int luminancePin = A0;
int uvPin = A1;
int dustPin = 8;
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;
unsigned long delay_time = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
//setup
void setup()
{
//iniciar canais seriais
Serial.begin(9600);
monitor.begin(9600);
Serial.println("Inicializando...");
//configurar pinos
pinMode(dustPin, INPUT);
//initicializar o sensor de pressão
Serial.println("Detectando sensor de pressao BMP085...");
if(!bmp.begin())
{
/* Se ocorrer um problema na detecção do BMP085, verificar suas conexões */
Serial.println("O BMP085 não foi detectado. Verifique suas ligações ou o I2C ADDR!");
while(1);
}
Serial.println("BMP085 detectado!");
//comunicação com o módulo wifi
monitor.flush();
monitor.println("AT");
delay(2000);
if(monitor.find("OK")){
Serial.println("Comunicacao com modulo ESP8266: OK");
}
else {
Serial.println("Erro no modulo ESP8266");
}
//conectar com roteador
connectWiFi();
Serial.print("Amostrando (");
Serial.print(sampletime_ms/1000);
Serial.println("s)...");
//inicializar timer
starttime = millis();
}
void loop(){
//medição do material particulado
duration = pulseIn(dustPin, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
//ciclo de amostragem de 30 segundos
if ((millis() - starttime) >= sampletime_ms) //se oe sample time == 30s
{
ratio = lowpulseoccupancy/(sampletime_ms*10.0); // porcentagem (de 0 a 100%)
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // dados do datasheet
lowpulseoccupancy = 0;
//leitura dos sensores
char buffer[10];
//luminosidade
float luminance = analogRead(luminancePin);
//UV
float uv = analogRead(uvPin);
uv = uv * 0.0049; //converter para V
uv = uv * 307; //converter para mW/m²
uv = uv/200; //índice UV
//temperatura e umidade
int chk = DHT.read22(DHT22_PIN);
float humidity = DHT.humidity;
float temperature = DHT.temperature;
//pressão e temperatura
sensors_event_t event;
bmp.getEvent(&event);
float pressure = 0;
float temperature1 = 0;
if (event.pressure)
{
pressure = event.pressure;
bmp.getTemperature(&temperature1);
}
//conversão dos dados lidos para strings
String luminanceStr = dtostrf(luminance, 4, 1, buffer);
luminanceStr.replace(" ","");
String uvStr = dtostrf(uv, 4, 1, buffer);
uvStr.replace(" ","");
String humidityStr = dtostrf(humidity, 4, 1, buffer);
humidityStr.replace(" ","");
String temperatureStr = dtostrf(temperature, 4, 1, buffer);
temperatureStr.replace(" ","");
String dustStr = dtostrf(concentration, 4, 1, buffer);
dustStr.replace(" ","");
String pressureStr = dtostrf(pressure, 4, 1, buffer);
pressureStr.replace(" ","");
String temperature1Str = dtostrf(temperature1, 4, 1, buffer);
temperature1Str.replace(" ","");
//enviar dados dos sensores para o thingspeak
updateSensors(luminanceStr, humidityStr, temperatureStr, uvStr, dustStr, pressureStr, temperature1Str);
//esperar até próximo ciclo de amostragem
Serial.print("Esperar ");
Serial.print(delay_time/1000);
Serial.println("s para proxima amostragem");
Serial.println();
delay(delay_time);
//iniciar novo ciclo de amostragem
Serial.println();
Serial.print("Amostrando (");
Serial.print(sampletime_ms/1000);
Serial.println("s)...");
starttime = millis();
}
}
//Função para envio dos dados dos sensores para o thingspeak
void updateSensors(String luminanceStr, String humidityStr, String temperatureStr, String uvStr, String dustStr, String pressureStr, String temperature1Str) {
String cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += IP;
cmd += "\",80";
monitor.println(cmd);
delay(2000);
cmd = GET;
cmd += luminanceStr;
cmd += "&field2=";
cmd += humidityStr;
cmd += "&field3=";
cmd += temperatureStr;
cmd += "&field4=";
cmd += uvStr;
cmd += "&field5=";
cmd += dustStr;
cmd += "&field6=";
cmd += pressureStr;
cmd += "&field7=";
cmd += temperature1Str;
cmd += "\r\n";
delay(1000);
int strsize = cmd.length();
monitor.println("AT+CIPSEND=" + String(strsize));
delay(2000);
monitor.print(cmd);
if(monitor.find("OK")){
Serial.println("Dados transmitidos com sucesso");
}else{
Serial.println("Falha na transmissao");
}
}
void sendDebug(String cmd){
Serial.print("SEND: ");
Serial.println(cmd);
monitor.println(cmd);
}
boolean connectWiFi(){
Serial.println("Conectando wi-fi...");
String cmd ="AT+CWMODE=1";
monitor.println(cmd);
delay(2000);
monitor.flush(); //clear buffer
cmd="AT+CWJAP=\"";
cmd+=SSID;
cmd+="\",\"";
cmd+=PASS;
cmd+="\"";
monitor.println(cmd);
delay(5000);
if(monitor.find("OK")){
Serial.println("Conectado com sucesso!");
return true;
}else{
Serial.println("Falha na conexao!");
return false;
}
Serial.println();
}
Referências
- Sensor de luminosidade: https://www.seeedstudio.com/wiki/Grove_-_Luminance_Sensor
- Sensor de intensidade UV: https://www.seeedstudio.com/wiki/Grove_-_UV_Sensor
- Sensor de pressão barométrica: https://www.filipeflop.com/pd-6b919-sensor-de-pressao-e-temperatura-bmp180.html?ct=&p=1&s=1
- DHT-22: https://www.filipeflop.com/pd-137442-sensor-de-umidade-e-temperatura-am2302-dht22.html?ct=&p=1&s=1
- Sensor de material particulado: https://www.seeedstudio.com/wiki/Grove_-_Dust_Sensor























Boa tarde Igor. É impressão minha ou no esquema das ligações dos fios, não há nenhum conectado a um terra do arduino!! (GND)?
Gostaria de saber onde você comprou o sensor de material articulado, UV e luminosidade. Poderia me passar os links?
Boa Tarde Igor, tudo bem?
Em um outro momento, tinha criado minha estação metereológica e agora estava procurando alguma atualização para meu projeto, foi quando encontrei seu projeto, e achei muito legal. Então fiquei com uma duvida, é possível alocar os dados obtidos em algum outro local, ou nuvem?
Para o meu projeto pensei em criar um app, para poder monitorar a estação em tempo real
Olá Igor, outras versões do ESP8266 daria certo?
Boa noite Igor na linha 11 codigo eu coloco o que por favor amigo me esclarece ai porfavor. Sobre a linha 9 #define IP qual eu uso corretamente
Boa noite sobre esse projeto como eu faço para configurar o ESP8266 para enviar ao Thingspeak. Qual o procedimento faz alguma mudança no codigo?
Bom dia. No meu caso, o ESP8266 funciona apenas como um modem: ele recebe comandos do Arduino através de uma porta/serial, e devolver as respostas.
É possível fazer algum semelhante removendo o Arduino, ou seja, o próprio ESP8266 realizaria a leitura dos sensores, processaria e enviaria para o Thingspeak. Porém, com o ESP8266-01, é um pouco difícil de fazer isso. Recomendo tentar com alguma placa baseada no ESP8266, como a NodeMCU, por exemplo.
Igor projeto maravilhoso
só senti falta de não poder visualizar os dados também em display o que vc acha de implementar
É uma boa ideia. Estou trabalhando em outros projetos, porém em breve pretendo publicar uma nova versão da estação, com direito a display e outros sensores (anemômetro, por exemplo).
Igor, parabens pelo projeto! vc ja implementou o codigo do anemometro?
Boa noite Igor!
Parabéns pelo projeto!
Estou cursando automação industrial e escolhi fazer uma estação meteorológica para meu trabalho semestral, no momento não é necessário eu montar a estação, só preciso apenas conceituar o projeto (funcionamento, onde liga o que, como é feita a coleta de dados, configuração), resumindo um passo a passo descrito do projeto.
É possível vc passar essas informações.
Desde já agradeço.
Obrigado! 🙂
Acredito que as informações que você precisa se encontram no tutorial.
Fico a disposição caso surjam dúvidas, ok?
Bom dia.
Qual o valor dos resistores mostrados na sua montagem ?
Obrigado
Bom dia,
Para o divisor de tensão (do sinal para o RX do ESP8266) utilizei dois resistores de 10k. Para a conexão entre o pino CH_PD do ESP8266 e o 3V3, utilizei um resistor de 1k.
Para o DHT11 eu coloquei um resistor de 4.7k.
Espero ter ajudado.
Igor bom dia! Eu ja comprei tudo mais eu nao estou conseguindo fazer o upload do codigo está dando erro no DHT. Ja fiz o procedimento mais mesmo assim da erro. Quando eu faço o download eu tenho que renomeiar so essa biblioteca?
Boa noite,
A linha 9 é o IP do ThingSpeak. Não é necessário alterar esse valor.
Na linha 11, substitua o xxxxx pela chave de escrita do seu canal. Você pode encontrar ela na configuração do seu canal (na aba Chaves). É um código (com número e letras) de 16 caracteres.
Espero ter ajudado.