Estação Meteorológica IoT com TensorFlow Prevê Intensidade de Chuva com Precisão
Componentes e Materiais
| 1× Kit Estação Meteorológica DFRobot com Anemômetro/Biruta/Balde de Chuva | |
| 1× Placa NodeMCU ESP8266 Breakout Board (ESP-12E) | |
| 1× Shield DFRobot SIM808 GPS/GPRS/GSM para Arduino | |
| 1× Arduino UNO | |
| 1× Raspberry Pi 3 Model B+ | Raspberry Pi 3B+ ou 4 |
| 1× Raspberry Pi 4 Model B | Raspberry Pi 3B+ ou 4 |
| 2× Protoboard Soldável SparkFun - Mini |
Ferramentas Necessárias
- Pistola de cola quente (genérica)
Aplicativos e Serviços Online
- Arduino IDE
- TensorFlow
- Microsoft Visual Studio 2017
Sobre o Projeto
Especialmente em 2020, chuvas instantâneas, fortes e violentas causaram efeitos prejudiciais em estufas e rendimentos de colheitas no meu país. Infelizmente, hoje em dia chuvas inesperadas e excessivas ocorrem mais frequentemente e tornaram-se relativamente comuns devido às mudanças climáticas em algumas áreas. Enquanto isso, outras regiões sofrem com secas. À medida que 2020 passa, mais de trinta e cinco incidentes que causaram perda de colheitas e gado devido a chuvas fortes e violentas são registrados na minha região. Para contribuir com a solução para prevenir e evitar problemas instigados por chuvas excessivas como perda de produtividade agrícola, contemplei este projeto como um ponto de partida.
Primariamente, foquei nos efeitos de chuvas excessivas na agricultura neste projeto. No entanto, chuvas excessivas podem levar a numerosos perigos, por exemplo [1]:
- inundações, incluindo risco à vida humana
- danos a edifícios e infraestrutura
- perda de colheitas e gado
- deslizamentos de terra, que podem ameaçar a vida humana, interromper transporte e comunicações
Como mostrado nos estudos mais recentes, chuvas excessivas podem afetar a produtividade das culturas de várias formas, incluindo dano físico direto, plantio e colheita atrasados, crescimento radicular restrito, deficiência de oxigênio e perda de nutrientes. Assim, muita chuva pode ser tão perigosa quanto seca para a agricultura: "Dados das últimas três décadas sugerem que chuvas excessivas podem afetar o rendimento das culturas tanto quanto calor excessivo e seca. Em um novo estudo, uma equipe interdisciplinar da Universidade de Illinois vinculou dados de seguro de culturas, clima, solo e rendimento de milho de 1981 a 2016. O estudo descobriu que, durante alguns anos, chuvas excessivas reduziram o rendimento de milho dos EUA em até 34% em relação ao rendimento esperado. Dados sugerem que seca e calor excessivo causaram perda de rendimento de até 37% durante alguns anos [2]".
Infelizmente, sistemas de alerta precoce não são suficientes para prevenir totalmente os efeitos exacerbantes de chuvas excessivas em produtos e processos agrícolas sem dados meteorológicos locais adequados e preliminares para cada estufa ou fazenda. Portanto, na esperança de evitar os efeitos prejudiciais de chuvas excessivas na agricultura, decidi criar este projeto como uma estação meteorológica remota econômica para coletar e interpretar informações meteorológicas locais para fazer previsões mais precisas sobre a intensidade da chuva.
Após fazer algumas pesquisas sobre deep learning e redes neurais, decidi construir uma rede neural artificial (ANN) baseada no modelo de classificação para interpretar os dados meteorológicos locais acumulados para prever a intensidade da chuva de acordo com as classes dadas. Como o seguinte estudo indica, pesquisadores aplicaram diferentes modelos e tipos de redes neurais para prever não apenas chuvas mas também fenômenos meteorológicos: "Muitos experimentos usaram redes neurais para prever quantidades quantitativas de chuva em vários locais e alcances de previsão. Por exemplo, pesquisadores na Tailândia conseguiram previsões altamente precisas usando redes neurais feed-forward para prever quantidades quantitativas de chuva no alcance de previsão de uma a três horas para prever possíveis perigos de inundação. Redes neurais também foram usadas para prever fenômenos meteorológicos além dos valores de previsão tradicionais, como probabilidade/quantidade de chuva, velocidade do vento, pressão barométrica, etc. Foram usadas com muito sucesso para prever tornados. Além disso, pesquisadores na Austrália usaram com sucesso uma rede neural para identificar nevoeiro em vários alcances de previsão variando de 3 a 18 horas ao redor do Aeroporto Internacional de Canberra [3]."
Antes de construir e testar meu modelo de rede neural, coletei dados meteorológicos na minha varanda e quintal num raio de três quilômetros por mais de três meses para criar um dataset meteorológico local mostrando informações climáticas na minha vizinhança. Para conseguir obter informações meteorológicas mesmo em condições extremas, usei um Kit de Estação Meteorológica com Anemômetro, Biruta e Balde de Chuva da DFRobot com duas placas de desenvolvimento diferentes:
- NodeMCU ESP-12E (WiFi habilitado)
- Arduino Uno + Shield DFRobot SIM808 GPS/GPRS/GSM (GPRS habilitado)
Assim, pude transferir dados meteorológicos via WiFi na minha varanda ou GPRS se a distância entre meu roteador e a estação meteorológica for muito grande.
Decidi usar o Google Sheets, um programa de planilha baseado na nuvem, para reunir dados meteorológicos gerados pela estação meteorológica porque criar grandes datasets e adicionar novas informações são simples com a API do Google Sheets. Por isso, desenvolvi uma aplicação web em PHP para obter dados meteorológicos transferidos pelas placas de desenvolvimento e anexá-los a uma planilha no Google Sheets.
Após completar a coleta de dados meteorológicos por mais de três meses a cada cinco minutos, construí um modelo de rede neural artificial (ANN) com TensorFlow para fazer previsões sobre a intensidade da chuva. Teoricamente, atribuí uma classe de intensidade de chuva para cada leitura após escalar e normalizar o dataset. Então, treinei o modelo de rede neural para classificar estas classes:
- Sem Chuva
- Chuva Leve
- Chuva Moderada
- Chuva Forte
- Chuva Violenta
Então, este é meu projeto em poucas palavras 😃
Nos passos a seguir, você encontra informações mais detalhadas sobre codificação, coleta de dados meteorológicos locais e construção de um modelo de rede neural artificial (ANN) com TensorFlow.
Muito obrigado à DFRobot por patrocinar este projeto.
Produtos patrocinados pela DFRobot:
⭐ Kit Estação Meteorológica com Anemômetro/Biruta/Balde de Chuva | Inspecionar
⭐ Shield SIM808 GPS/GPRS/GSM para Arduino | Inspecionar



Passo 1: Montando o kit da estação meteorológica com anemômetro, biruta e balde de chuva
Este kit de estação meteorológica inclui anemômetro, biruta, balde de chuva e uma placa sensora para enviar dados meteorológicos via protocolo de comunicação serial. Assim, é fácil de usar com placas de desenvolvimento para coletar dados meteorológicos locais.
Ele gera 37 bytes por segundo, incluindo o final CR/LF.
c000s000g000t086r000p000h53b10020
Parser de Dados:
- c000 : direção do ar, graus
- s000 : velocidade do ar (média), 0.1 milhas por hora
- g000 : velocidade do ar (máxima), 0.1 milhas por hora
- t086 : temperatura, Fahrenheit
- r000 : chuva (1 hora), 0.01 polegadas
- p000 : chuva (24 horas), 0.01 polegadas
- h53 : umidade, % (00% = 100)
- b10020 : atmosfera, 0.1 hPa
⭐ Primeiro, prenda o anemômetro e a biruta na ponte usando parafusos e porcas.
⭐ Conecte a biruta ao anemômetro usando o cabo telefônico RJ11 e aperte sob a ponte.


⭐ Então, monte o bastão de aço inoxidável na ponte com parafusos.

⭐ Instale a junta do balde de chuva sob o balde com parafusos.

⭐ Por fim, coloque o balde de chuva no bastão de aço inoxidável usando parafusos e porcas.

⭐ Agora, está pronto para coletar dados meteorológicos mesmo em condições extremas. No entanto, a placa sensora (conversora) não é à prova d'água, então adicionei uma caixa plástica à estação meteorológica para proteger a placa sensora e o shield SIM808 ao ar livre.
Passo 2: Coletando dados meteorológicos no Google Sheets
Para poder enviar informações para uma planilha no Google Sheets, você precisa criar uma nova aplicação no Google Developer Console e obter credenciais de verificação para utilizar a API do Google Sheets. Se você é novato em criar aplicações com o Google Developer Console, siga as instruções abaixo.
⭐ Acesse o Google Developer Console e clique no botão 'NOVO PROJETO'. Insira o nome do projeto como Remote Weather Station (Estação Meteorológica Remota).

⭐ Vá em APIs & Services e clique na biblioteca de API para habilitar a Google Sheets API.


Passo 2.1: Obtendo credenciais para usar a API do Google Sheets
⭐ Abra o painel do projeto e clique no botão Credenciais. Então, preencha o formulário como mostrado abaixo para criar a conta de serviço e chave.



⭐ Clique no botão CREATE CREDENTIALS e configure a tela de consentimento para poder criar um OAuth client ID.


⭐ Então, crie um novo OAuth client ID chamado Client sob Desktop app (tipo de aplicação).

⭐ Após criar o OAuth client ID (Client), baixe as credenciais (ID e Secret) e nomeie o arquivo como credentials.json.


Passo 2.2: Criando uma planilha no Google Sheets
⭐ Acesse o Google Sheets e selecione Pessoal.

⭐ Crie uma planilha Em branco e nomeie-a Remote Weather Station.
⭐ Então, defina os nomes das colunas como a primeira linha:
- WD (Direção do Vento)
- Av_WS (Velocidade Média do Vento)
- Mx_WS (Velocidade Máxima do Vento)
- 1h_RF (Chuva 1h)
- 24h_RF (Chuva 24h)
- Tem (Temperatura)
- Hum (Umidade)
- b_PR (Pressão Barométrica)
⭐ Se necessário, modifique um gráfico para inspecionar os dados coletados, como fiz.

Passo 3: Desenvolvendo uma aplicação web em PHP para anexar dados meteorológicos à planilha
Esta aplicação web PHP é para obter dados meteorológicos transferidos pelas placas de desenvolvimento (ESP8266 e SIM808) via requisição HTTP GET e anexar esses dados a uma planilha dada (por ID) no Google Sheets com credenciais e token verificados.
A aplicação web requer a Google Client Library for PHP para anexar dados meteorológicos a uma planilha dada no Google Sheets.
⭐ Primeiro, crie uma pasta chamada remote_weather_station no seu servidor e instale a Google Client Library for PHP nela.
A pasta remote_weather_station deve incluir estes quatro arquivos além da Google Client Library para funcionar:
- index.php
- account_verification_token.php
- credentials.json (Passo 2.1)
- token.json (Passo 3.1)
Neste passo, discutirei os dois primeiros arquivos - index.php e account_verification_token.php:
💻 index.php
⭐ Obtenha dados meteorológicos locais da estação meteorológica via requisição GET:
// Wind Direction (wd), Average Wind Speed (a_ws), Max Wind Speed (m_ws), 1hr Rainfall (1_rf), 24hr Rainfall (24_rf), Temperature (tem), Humidity (hum), Barometric Pressure (b_pr).
$variables_from_module;
if(isset($_GET['wd']) && isset($_GET['a_ws']) && isset($_GET['m_ws']) && isset($_GET['1_rf']) && isset($_GET['24_rf']) && isset($_GET['tem']) && isset($_GET['hum']) && isset($_GET['b_pr'])){
$variables_from_module = [
"wd" => (int)$_GET['wd'],
"a_ws" => (float)$_GET['a_ws'],
"m_ws" => (float)$_GET['m_ws'],
"1_rf" => (float)$_GET['1_rf'],
"24_rf" => (float)$_GET['24_rf'],
"tem" => (float)$_GET['tem'],
"hum" => (int)$_GET['hum'],
"b_pr" => (float)$_GET['b_pr']
];
}else{
$variables_from_module = [
"wd" => "err",
"a_ws" => "err",
"m_ws" => "err",
"1_rf" => "err",
"24_rf" => "err",
"tem" => "err",
"hum" => "err",
"b_pr" => "err"
];
}
⭐ Conecte ao aplicativo do Google Developer Console chamado Remote Weather Station usando o arquivo credentials.json (Passo 2.1).
$client = new Google_Client();
$client->setApplicationName('Remote Weather Station'); // Insira o nome da sua aplicação.
$client->setScopes('https://www.googleapis.com/auth/spreadsheets');
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
⭐ Carregue token autorizado anteriormente de um arquivo (token.json), se existir.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
print("Token Found!");
}
⭐ Se não há token anterior ou expirou, solicite autorização do usuário e defina o código de verificação para criar o arquivo token.json com a função file_put_contents().
if ($client->isAccessTokenExpired()) {
// Atualize o token se possível, senão busque um novo.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Solicite autorização do usuário.
$authUrl = $client->createAuthUrl();
...
// Defina o código de verificação para criar o token.json.
$authCode = trim($GLOBALS['account_verification_token']);
...
// Verifique se houve erro e o account_verification_token foi inserido.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}else{
print("Successful! Refresh the page.");
}
}
// Salve o token em um arquivo.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
⭐ Insira o ID da planilha e intervalo para anexar descobertas recentes da estação meteorológica à planilha.
https://docs.google.com/spreadsheets/d/spreadsheetId/edit#gid=0
// Insira seu spreadsheetId:
$spreadsheetId = '';
// Insira o intervalo (a primeira linha) sob o qual novos valores serão anexados (8 linhas):
$range = 'A1:H1';
// Anexe descobertas recentes da estação meteorológica à planilha.
$values = [
[$variables_from_module["wd"], $variables_from_module["a_ws"], $variables_from_module["m_ws"], $variables_from_module["1_rf"], $variables_from_module["24_rf"], $variables_from_module["tem"], $variables_from_module["hum"], $variables_from_module["b_pr"]]
];
$body = new Google_Service_Sheets_ValueRange([
'values' => $values
]);
$params = [
'valueInputOption' => "RAW"
];
...
$result = $service->spreadsheets_values->append($spreadsheetId, $range, $body, $params);
printf("
%d cells appended.", $result->getUpdates()->getUpdatedCells());
💻 account_verification_token.php
⭐ Após autorizar a aplicação web pelo AuthUrl criado, insira o código de verificação dado para definir um token de acesso.
$account_verification_token = ""; // Insira o código de verificação após autorização.


Passo 3.1: Configurando a aplicação web no Raspberry Pi (ou qualquer servidor)
Após criar a aplicação web PHP, decidi rodá-la no meu Raspberry Pi, mas você pode rodar a aplicação em qualquer servidor desde que seja um servidor PHP.
Se quiser usar Raspberry Pi mas não sabe como configurar um servidor web LAMP no Raspberry Pi, pode consultar este tutorial.
⭐ Primeiro, mova a pasta da aplicação (remote_weather_station) para o servidor apache (/var/www/html) usando o terminal já que o servidor apache é um local protegido.
sudo mv /home/pi/Downloads/remote_weather_station /var/www/html/

⭐ A aplicação web lança um erro quando aberta pela primeira vez devido ao código de verificação ausente. Para obter o código de verificação, acesse o link de autorização gerado pela aplicação.

⭐ Então, clique em Go to Remote Weather Station (unsafe).

⭐ Conceda à aplicação as permissões necessárias.

⭐ Agora, copie o código de verificação e cole no account_verification_token.php.

⭐ Volte para a aplicação web. Deve exibir a mensagem de confirmação: Successful! Refresh the page.

⭐ Após atualizar a página, a aplicação web usa o código de verificação para obter um token de acesso e salva o token de acesso em um arquivo chamado token.json. Assim, não lança erro novamente.

⭐ Para testar se a aplicação web PHP está anexando novos dados à planilha dada com precisão:
https://localhost/remote_weather_station/?wd=12&a_ws=8&m_ws=11&1_rf=14&24_rf=84&tem=24&hum=32&b_pr=57


Passo 4: Lendo e enviando dados meteorológicos com ESP8266 (WiFi)
Para coletar dados meteorológicos na minha varanda, usei uma placa de desenvolvimento NodeMCU ESP-12E (ESP8266) com a estação meteorológica.
Programei para enviar dados meteorológicos para a aplicação web PHP a cada cinco minutos.

⭐ Inclua bibliotecas necessárias e defina configurações WiFi.
#include
#include
#include
#include
#include
// Defina suas configurações WiFi.
const char *ssid = "";
const char *password = "";
⭐ Defina configurações da estação meteorológica e pinos de conexão serial - D6, D5.
// Defina configurações da estação meteorológica:
char databuffer[35];
double temp;
int transferring = 0;
// Defina os pinos de conexão serial - RX e TX.
SoftwareSerial Serial_1(D6, D5); // (Rx, Tx)
⭐ Na função getBuffer(), obtenha dados da estação meteorológica.
void getBuffer(){
int index;
for (index = 0; index < 35; index++){
if(Serial_1.available()){
databuffer[index] = Serial_1.read();
if (databuffer[0] != 'c'){
index = -1;
}
} else {
index--;
}
}
}
⭐ Depure os dados meteorológicos e crie o link.
String weather_data = "wd=" + String(WindDirection()) + "&a_ws=" + String(WindSpeedAverage()) + "&m_ws=" + String(WindSpeedMax()) + "&1_rf=" + String(RainfallOneHour()) + "&24_rf=" + String(RainfallOneDay()) + "&tem=" + String(Temperature()) + "&hum=" + String(Humidity()) + "&b_pr=" + String(BarPressure());
String server = "https://192.168.1.24/remote_weather_station/?";
...
int WindDirection(){ return transCharToInt(databuffer,1,3); } // Direção do Vento (graus)
float WindSpeedAverage(){ temp = 0.44704 * transCharToInt(databuffer,5,7); return temp; } // Velocidade Média do Ar (1 minuto)
float WindSpeedMax(){ temp = 0.44704 * transCharToInt(databuffer,9,11); return temp; } // Velocidade Máxima do Ar (5 minutos)
float Temperature(){ temp = (transCharToInt(databuffer,13,15) - 32.00) * 5.00 / 9.00; return temp; } // Temperatura ("C")
float RainfallOneHour(){ temp = transCharToInt(databuffer,17,19) * 25.40 * 0.01; return temp; } // Chuva (1 hora)
float RainfallOneDay(){ temp = transCharToInt(databuffer,21,23) * 25.40 * 0.01; return temp; } // Chuva (24 horas)
int Humidity(){ return transCharToInt(databuffer,25,26); } // Umidade (%)
float BarPressure(){ temp = transCharToInt(databuffer,28,32); return temp / 10.00; } // Pressão Barométrica (hPA)
⭐ Envie pacotes de dados a cada 5 minutos para Raspberry Pi (ou qualquer servidor).
transferring++; Serial.println("Time => " + String(transferring) + "s / " + String(int(5*60)) + "s\n\n");
if(transferring == 5*60){
// Crie o objeto HTTP para fazer uma requisição ao servidor.
HTTPClient http;
http.begin(server + weather_data);
int httpCode = http.GET();
String payload = http.getString();
Serial.println("Data Send...\nHTTP Code => " + String(httpCode) + "\nServer Response => " + payload + "\n\n");
http.end();
transferring = 0;
}
// Espere 1 segundo...
delay(1000);

⭐ Após fazer upload do código para a placa de desenvolvimento NodeMCU ESP-12E (ESP8266), ele exibe dados meteorológicos a cada segundo no monitor serial e envia pacotes de dados a cada cinco minutos (300 segundos) para a aplicação web PHP.
Connection is successful!
...
Weather Data => wd=0&a_ws=0.00&m_ws=0.00&1_rf=0.00&24_rf=0.00&tem=21.67&hum=29&b_pr=1016.70
Buffer => c000s000g000t071r000p000h29b10167*3
Time => 299s / 300s
Weather Data => wd=0&a_ws=0.00&m_ws=0.00&1_rf=0.00&24_rf=0.00&tem=21.67&hum=29&b_pr=1016.70
Buffer => c000s000g000t071r000p000h29b10167*3
Time => 300s / 300s
...
⭐ Então, mostra a resposta do servidor.
...
Data Send...
HTTP Code => 200
Server Response => Token Found!
8 cells appended.
...


Passo 4.1: Lendo e enviando dados meteorológicos com SIM808 (GPRS)
Para coletar dados meteorológicos no meu quintal, usei um shield SIM808 para Arduino Uno se a distância entre a estação meteorológica e meu roteador for muito grande.
A maior parte do código é a mesma e coberta no passo anterior, exceto as partes abaixo.

⭐ Inclua bibliotecas necessárias e defina o objeto sim808.
Para Shield SIM808 GPS/GPRS/GSM | Download
#include
#include
// Defina o sim808.
DFRobot_SIM808 sim808(&Serial);
⭐ Inicialize o módulo SIM808 e continue se estiver funcionando corretamente.
//******** Inicialize módulo sim808 *************
while(!sim808.init()) {
delay(1000);
Serial.print("Sim808 init error\r\n");
}
delay(2000);
// Continue se o Módulo SIM808 estiver funcionando corretamente.
Serial.println("Sim808 init success");
delay(5000);
⭐ Envie pacotes de dados a cada 5 minutos para o servidor estabelecendo uma conexão TCP para fazer uma requisição GET.
transferring++; Serial.println("Time => " + String(transferring) + "s / " + String(int(5*60)) + "s\n\n");
if(transferring == 5*60){
//*********** Attempt DHCP *******************
while(!sim808.join(F("cmnet"))) {
Serial.println("Sim808 join network error!");
delay(2000);
}
//************ Successful DHCP ***************
delay(5000);
Serial.println("Successful DHCP");
//*********** Establish a TCP connection ************
if(!sim808.connect(TCP,"192.168.1.24", 80)) { // Altere com seu servidor.
Serial.println("Connection Error");
}else{
Serial.println("Connection OK");
}
delay(2000);
...
⭐ Após criar a string da linha, converta de string para array char para fazer uma requisição HTTP GET com o SIM808.
...
String line = "GET /remote_weather_station/?" + weather_data_1 + weather_data_2 + weather_data_3 + " HTTP/1.0\r\n\r\n";
Serial.println(line);
char buffer[512];
// Converta a linha de string para array char para fazer requisição HTTP GET com SIM808.
char web_hook[110];
String_to_Char(line, 110, web_hook);
sim808.send(web_hook, sizeof(web_hook)-1);
while (true) {
int ret = sim808.recv(buffer, sizeof(buffer)-1);
if (ret <= 0){
Serial.println("Fetch Over...");
break;
}
...

⭐ Após fazer upload do código para o shield SIM808, ele exibe dados meteorológicos a cada segundo no monitor serial e envia pacotes de dados a cada cinco minutos (300 segundos) para a aplicação web PHP.


Passo 4.2: Criando o dataset meteorológico por mais de três meses
Após terminar a codificação, comecei a reunir dados meteorológicos no Google Sheets a cada cinco minutos por mais de três meses para construir meu modelo de rede neural e fazer previsões sobre a intensidade da chuva.
Dados Meteorológicos Coletados:
- Direção do Vento (graus)
- Velocidade Média do Vento (m/s)
- Velocidade Máxima do Vento (m/s)
- Chuva de Uma Hora (mm)
- Chuva de 24 Horas (mm)
- Temperatura (°C)
- Umidade (%)
- Pressão Barométrica (hPa)
Então, baixei a planilha como Remote Weather Station.csv, consistindo de 32219 linhas como meu dataset meteorológico local preliminar. Ainda estou coletando dados meteorológicos para melhorar meu dataset e modelo :)


Passo 5: Construindo uma Rede Neural Artificial (ANN) com TensorFlow
Quando completei a coleta do meu dataset meteorológico local preliminar, comecei a trabalhar no meu modelo de rede neural artificial (ANN) para fazer previsões sobre a intensidade da chuva.
Decidi criar meu modelo de rede neural com TensorFlow em Python. Então, primeiro, segui os passos abaixo para obter melhor compreensão dos dados meteorológicos:
- Visualização de Dados
- Escalonamento de Dados (Normalização)
- Pré-processamento de Dados
- Divisão de Dados
Após aplicar estes passos, decidi usar meu modelo de rede neural para classificar diferentes classes de intensidade de chuva teoricamente atribuídas como labels (saídas) para cada entrada (linha). Criei minhas classes de acordo com a taxa de precipitação, que depende do tempo considerado.
As seguintes categorias são usadas para classificar intensidade de chuva pela taxa de precipitação:
- Chuva leve — quando a taxa de precipitação é < 2.5 mm por hora
- Chuva moderada — quando a taxa de precipitação está entre 2.5 mm e 7.6 mm por hora
- Chuva forte — quando a taxa de precipitação está entre 7.6 mm e 50 mm por hora
- Chuva violenta — quando a taxa de precipitação é > 50 mm por hora
De acordo com as taxas de precipitação (chuva), pré-processei os dados meteorológicos para atribuir uma destas cinco classes para cada entrada como seu label:
- 0 (Nenhuma)
- 1 (Chuva Leve)
- 2 (Chuva Moderada)
- 3 (Chuva Forte)
- 4 (Chuva Violenta)
Após escalar (normalizar) e pré-processar os dados meteorológicos, obtive sete variáveis de entrada e um label para cada leitura, classificadas com as cinco classes mencionadas. Então, construí um modelo de rede neural artificial com TensorFlow para obter os melhores resultados e previsões possíveis com meu dataset preliminar.
Camadas:
- 7 [Entrada]
- 16 [Oculta]
- 32 [Oculta]
- 64 [Oculta]
- 128 [Oculta]
- 5 [Saída]


Para executar todos os passos acima, criei uma classe chamada Weather_Station em Python após incluir as bibliotecas necessárias:
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
Subsequentemente, discutirei a codificação em Python para cada passo mencionado acima.
Também, você pode baixar IoT_weather_station_neural_network.py para inspecionar a codificação.


Passo 5.1: Visualizando e escalando (normalizando) os dados meteorológicos
Antes de mergulhar na construção de um modelo, é importante entender os dados meteorológicos para passar dados apropriadamente formatados ao modelo.
Então, neste passo, mostrarei como visualizar dados meteorológicos e escalar (normalizar) em Python.
⭐ Primeiro, leia os dados meteorológicos de Remote Weather Station.csv.
csv_path = "E:\PYTHON\Remote Weather Station.csv"
df = pd.read_csv(csv_path)
⭐ Na função graphics(), visualize as colunas solicitadas do dataset meteorológico usando a biblioteca Matplotlib.
def graphics(self, column_1, column_2, xlabel, ylabel):
# Mostre colunas solicitadas do dataset:
plt.style.use("dark_background")
plt.gcf().canvas.set_window_title('IoT Weather Station')
plt.hist2d(self.df[column_1], self.df[column_2])
plt.colorbar()
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.title(xlabel)
plt.show()
⭐ Na função data_visualization(), inspecione todas as colunas antes de escalar dados meteorológicos para construir um modelo com dados apropriadamente formatados.
def data_visualization(self):
# Inspecione colunas solicitadas para construir um modelo com dados apropriadamente formatados:
self.graphics('WD', '1h_RF', 'Wind Direction (deg)', 'One-Hour Rainfall (mm)')
self.graphics('Av_WS', '1h_RF', 'Average Wind Speed (m/s)', 'One-Hour Rainfall (mm)')
self.graphics('Mx_WS', '1h_RF', 'Maximum Wind Speed (m/s)', 'One-Hour Rainfall (mm)')
self.graphics('24h_RF', '1h_RF', '24-Hour Rainfall (mm)', 'One-Hour Rainfall (mm)')
self.graphics('Tem', '1h_RF', 'Temperature (°C)', 'One-Hour Rainfall (mm)')
self.graphics('Hum', '1h_RF', 'Humidity (%)', 'One-Hour Rainfall (mm)')
self.graphics('b_PR', '1h_RF', 'Barometric Pressure (hPA)', 'One-Hour Rainfall (mm)')




Após visualizar dados meteorológicos, escalei (normalizei) cada coluna para formatá-la adequadamente.
Normalmente, cada linha (leitura) parecia assim antes de escalar:
- 315, 0.45, 0, 0.51, 0.51, 22.78, 65, 1005.5
⭐ Na função scale_data():
⭐ A direção do vento em unidades de graus e ângulos não são boas entradas para o modelo. 360° e 0° devem estar próximos um do outro e transicionar suavemente. A direção não deve importar se o vento não estiver soprando. Assim, converta as colunas de direção e velocidade do vento para um vetor de vento para interpretá-las facilmente com um modelo de rede neural.
def scale_data(self):
# Direção e Velocidade do Vento:
wv = self.df.pop('Av_WS')
max_wv = self.df.pop('Mx_WS')
# Converter para radianos.
wd_rad = self.df.pop('WD')*np.pi / 180
# Calcule os componentes x e y do vento.
self.df['scaled_WX'] = wv*np.cos(wd_rad)
self.df['scaled_WY'] = wv*np.sin(wd_rad)
# Calcule os componentes máximos x e y do vento.
self.df['scaled_max_WX'] = max_wv*np.cos(wd_rad)
self.df['scaled_max_WY'] = max_wv*np.sin(wd_rad)
...
⭐ Para as colunas restantes exceto 1h_RF, divida-as pelos valores médios de leitura para escalar (normalizar) e formatar.
...
# Temperatura:
tem = self.df.pop('Tem')
self.df['scaled_Tem'] = tem / 25
# Umidade:
hum = self.df.pop('Hum')
self.df['scaled_Hum'] = hum / 70
# Pressão Barométrica:
bPR = self.df.pop('b_PR')
self.df["scaled_bPR"] = bPR / 1013
# Chuva de 24 Horas (Aprox.)
rain_24 = self.df.pop('24h_RF')
self.df['scaled_24h_RF'] = rain_24 / 24
Após completar o escalonamento (normalização), extraí estas novas colunas do dataset meteorológico:
- scaled_WX
- scaled_WY
- scaled_max_WX
- scaled_max_WY
- scaled_Tem
- scaled_Hum
- scaled_bPR
- scaled_24h_RF
Passo 5.2: Treinando o modelo (ANN) nas classes de intensidade de chuva
Antes de construir e treinar um modelo de rede neural em TensorFlow, precisei criar o array de entrada e o array de label pré-processando o dataset meteorológico escalado e normalizado.
⭐ Na função create_input_and_label():
⭐ Primeiro, anexe cada elemento de entrada como array NumPy ao array de entrada e converta para array NumPy usando a função asarray().
⭐ Cada elemento de entrada inclui sete variáveis [shape=(7, )]:
- [scaled_WX, scaled_WY, scaled_max_WX, scaled_max_WY, scaled_Tem, scaled_Hum, scaled_bPR]
def create_input_and_label(self):
n = len(self.df)
# Crie o array de entrada usando as variáveis escaladas:
for i in range(n):
self.input.append(np.array([self.df['scaled_WX'][i], self.df['scaled_WY'][i], self.df['scaled_max_WX'][i], self.df['scaled_max_WY'][i], self.df['scaled_Tem'][i], self.df['scaled_Hum'][i], self.df['scaled_bPR'][i]]))
self.input = np.asarray(self.input)
...
⭐ Então, avalie a taxa aproximada de chuva (precipitação) para cada leitura (linha).
approx_RF_rate = (1h_RF + scaled_24h_RF) * 100
⭐ De acordo com a taxa de chuva, atribua uma classe [0-4] para cada elemento de entrada e anexe-as ao array de label.
...
for i in range(n):
_class = 0
# Avalie a taxa aproximada de chuva:
approx_RF_rate = (self.df['1h_RF'][i] + self.df['scaled_24h_RF'][i]) * 100
// Como labels, atribua classes de intensidade de chuva de acordo com a taxa aproximada de chuva (mm):
if approx_RF_rate == 0:
_class = 0
elif approx_RF_rate < 2.5:
_class = 1
elif 2.5 < approx_RF_rate and approx_RF_rate < 7.6:
_class = 2
elif 7.6 < approx_RF_rate and approx_RF_rate < 50:
_class = 3
else:
_class = 4
self.label.append(_class)
self.label = np.asarray(self.label)
Após pré-processar os dados meteorológicos escalados para criar arrays de entrada e label, dividi-os como dados de treino (60%) e teste (40%):
def split_data(self):
n = len(self.df)
// (60%, 40%) - (treino, teste)
self.train_input = self.input[0:int(n*0.6)]
self.test_input = self.input[int(n*0.6):]
self.train_label = self.label[0:int(n*0.6)]
self.test_label = self.label[int(n*0.6):]
Então, construí meu modelo de rede neural artificial (ANN) usando Keras e o treinei com o dataset de treino por dezenove épocas.
Você pode consultar estes tutoriais para aprender sobre funções de ativação, funções de perda, épocas, etc.
def build_and_train_model(self):
// Construa a rede neural:
self.model = keras.Sequential([
keras.Input(shape=(7,)),
keras.layers.Dense(16, activation='relu'),
keras.layers.Dense(32, activation='relu'),
keras.layers.Dense(64, activation='relu'),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(5, activation='softmax')
])
// Compile:
self.model.compile(optimizer='adam', loss="sparse_categorical_crossentropy", metrics=['accuracy'])
// Treine:
self.model.fit(self.train_input, self.train_label, epochs=19)
...
Após treinar com o dataset de treino preliminar, a precisão do modelo está entre 0.83 e 0.85.

Passo 5.3: Avaliando o modelo e fazendo previsões sobre a intensidade da chuva
Após construir e treinar meu modelo de rede neural artificial, testei sua precisão usando o dataset de teste preliminar.
Por enquanto, a precisão avaliada do modelo está entre 0.72 e 0.73 devido a dataset de teste inadequado fazendo overfit no modelo. No entanto, ainda estou coletando dados meteorológicos para melhorar a precisão do modelo.
...
// Teste a precisão:
print("\n\nModel Evaluation:")
test_loss, test_acc = self.model.evaluate(self.test_input, self.test_label)
print("Evaluated Accuracy: ", test_acc)
Então, usei meu modelo de rede neural para fazer previsões sobre a intensidade da chuva com um array de previsão dado consistindo de leituras da estação meteorológica após o treino do modelo. Como ponto de partida, o modelo funciona bem :)
O modelo prevê possibilidades de labels para cada elemento de entrada como um array de 5 números. Eles representam a "confiança" do modelo que o elemento de entrada dado corresponde a cada uma das cinco diferentes classes de intensidade de chuva [0-4].
⭐ Na função make_prediction(), faça uma previsão para cada elemento de entrada em um array dado e obtenha o label mais preciso [0-4] usando a função argmax() para exibir seu nome de classe.
def make_prediction(self, pre_array):
print("\n\nModel Predictions:\n")
prediction = self.model.predict(pre_array)
for i in range(len(pre_array)):
print("Prediction => ", self.class_names[np.argmax(prediction[i])])
Entradas de Previsão:
- [0, 0, 0.31819805, 0.31819805, 0.6988, 0.81498571, 0.99349753]
- [0, -0, 0, -0, 0.8444, 1, 0.96835143]
- [0, 0, 0.45, 0, 0.87577, 0.95857143, 1.00128332]
- [-0, -0, -0, -0, 0.8224, 1.05714286, 0.99279368]
Saídas de Previsão:
- 0 [Nenhuma]
- 3 [Chuva Forte]
- 4 [Chuva Violenta]
- 4 [Chuva Violenta]

Conexões e Ajustes (ESP8266)
// Conexões
// NodeMCU ESP-12E (ESP8266) :
// Estação Meteorológica
// VV --------------------------- 5V
// D5 --------------------------- RX
// D6 --------------------------- TX
// G --------------------------- GND
Conectei a placa sensora (conversora) ao NodeMCU ESP-12E (ESP8266) e os prendi a uma caixa plástica enquanto coletava dados meteorológicos na minha varanda.

Conexões e Ajustes (SIM808)
// Conexões
// Arduino Uno:
// SIM808 GPS/GPRS/GSM Shield para Arduino
// D0 --------------------------- RX
// D1 --------------------------- TX
// D12 --------------------------- POWER
// Estação Meteorológica
// 5V --------------------------- 5V
// D5 --------------------------- RX
// D6 --------------------------- TX
// GND --------------------------- GND
⭐ Nota: Pinos D0, D1, D12 são ocupados pelo Shield SIM808 GPS/GPRS/GSM.
⭐ Conecte uma bateria externa (7-23V) para o módulo SIM808 funcionar corretamente.
⭐ Anexe a antena GPS e a antena GSM ao shield SIM808.
⭐ Insira um cartão SIM no slot SIM no shield SIM808.
⭐ Antes de fazer upload do código, defina a chave de função no shield para None (1).
⭐ Faça upload do código.
⭐ Então, defina a chave de função para Arduino (3).
⭐ Pressione o botão Boot no shield até ver o LED indicador Net piscando a cada 1 segundo e espere o cartão SIM registrar a rede - o LED indicador Net piscará lentamente a cada 3 segundos.
⭐ Clique aqui para obter mais informações sobre o Shield SIM808 GSM/GPS/GPRS.
Após configurar o shield SIM808 com Arduino Uno, conectei a placa sensora (conversora) a ele.

Coloquei todos os componentes em uma caixa plástica para coletar dados meteorológicos ao ar livre, mesmo em condições extremas, já que a placa sensora não é à prova d'água.

Então, prendi a caixa plástica à estação meteorológica.

Vídeos e Conclusão
Após completar a codificação e montar a estação meteorológica, reuni dados meteorológicos locais por mais de três meses a cada cinco minutos para construir meu modelo de rede neural com sucesso.
Ainda estou coletando dados meteorológicos na minha varanda e quintal para melhorar meu modelo de rede neural e sua precisão :)



Discussões Adicionais
☔ 💧 Como precisamos de datasets meteorológicos locais para obter previsões mais precisas sobre fenômenos meteorológicos, estações meteorológicas econômicas habilitadas para NN como esta podem ser colocadas em fazendas e estufas para evitar os efeitos prejudiciais de chuvas excessivas na agricultura.
☔ 💧 Como sistemas de alerta precoce trabalhando com redes neurais, podemos usá-los simultaneamente para criar um enxame de estações meteorológicas se comunicando e alimentando umas às outras para prever a intensidade da chuva precisamente em áreas locais.
☔ 💧 Também podemos utilizar essa informação para avaliar:
- recursos hídricos vitais
- agricultura
- produtividade de culturas
- ecossistemas
- hidrologia


Referências
[1] Extreme weather - heavy rainfall, NIWA, NIWA
[2] University of Illinois at Urbana-Champaign, News Bureau. "Excessive rainfall as damaging to corn yield as extreme heat, drought." ScienceDaily. ScienceDaily, 30 April 2019. ScienceDaily.
[3] Andrew Culclasure, Using Neural Networks to Provide Local Weather Forecasts, Georgia Southern University, Spring 2013, Digital Commons.
Código
O projeto inclui múltiplos arquivos de código:
- IoT_weather_station_neural_network.py - Código Python completo com TensorFlow/Keras
- ESP12E_remote_weather_station.ino - Sketch Arduino para NodeMCU ESP8266 (WiFi)
- SIM808_remote_weather_station.ino - Sketch Arduino para Arduino Uno + SIM808 (GPRS)
- index.php - Aplicação web PHP para Google Sheets API
- account_verification_token.php - Token de verificação da conta
Peças Personalizadas e Caixas
remote_weather_station_OobOCQNPSW.csv (Dataset de exemplo)
Esquemáticos
Processo de manufatura
- Estação Meteorológica Solar DIY com Raspberry Pi
- Construindo Estação Meteorológica Externa com Raspberry Pi 2 e ADS‑WS1
- Construa Estação Meteorológica Raspberry Pi que Envia Dados Diários por Email
- Tutorial IoT Iniciante: Streaming de Dados de Temperatura de um Raspberry Pi
- Monitoramento Remoto do Tempo com Raspberry Pi 3 e PubNub
- Integre sua Estação Meteorológica ao CWOP: Guia Prático
- Construindo IoT com Java ME 8 no Raspberry Pi: Parte 1 – Integração de Sensores GPIO
- Conecte Raspberry Pi 3 a Sensor DHT11 e Envie Dados para Nuvem ThingsIo.ai
- Enviando Dados do IMU Adafruit 10DOF do Raspberry Pi 2 ao Azure Event Hubs com Windows 10 IoT Core
- Estação Meteorológica Avançada v2.0: Monitoramento em Tempo Real de Temperatura, Pressão, Umidade e Altitude