Introdução
Na primeira parte, coletamos dados da API Visual Crossing Weather e treinamos um modelo para identificar a ocorrência de chuva. Agora, na segunda parte, vamos escrever o código para realizar a leitura dos sensores DHT11 e BMP180 e depois aplicar o modelo previamente treinado para fazer as previsões com base nos dados lidos.
Conexões dos Sensores
- Sensor de temperatura e umidade DHT11:
- Pino de dados: Conectado ao pino 15.
- VCC: Conectado ao 3.3V.
- GND: Conectado ao GND.
- Sensor de pressão barométrica BMP180:
- SDA: Conectado ao pino 8.
- SCL: Conectado ao pino 9.
- VCC: Conectado ao 3.3V.
- GND: Conectado ao GND.
Implementação Código para Leitura do Sensor DHT11
Primeiro, acesse o gerenciador de bibliotecas no Arduino IDE, busque por “dht sensor library” e instale.
Com o sensor DHT11, faremos a leitura da temperatura e umidade, além de calcular a sensação térmica com base nesses valores. Para entender melhor a formulação utilizada no cálculo da sensação térmica acesse: https://www.todamateria.com.br/sensacao-termica/
Grave o código abaixo na sua placa Franzininho WIFI:
#include <DHT.h>
#define DHTPIN 15 // Pino digital conectado ao sensor DHT
#define DHTTYPE DHT11 // Tipo de sensor DHT
DHT dht(DHTPIN, DHTTYPE);
float sensacao_termica(float temperatura, float umidade){
float sensacao = temperatura -((0.55-0.0055*umidade)*(temperatura-14.5));
return sensacao;
}
void setup() {
Serial.begin(115200);
Serial.println(F("Inicializando DHT..."));
dht.begin();
}
void loop() {
// Ler a temperatura e a umidade
float t = dht.readTemperature();
float u = dht.readHumidity();
//calcular sensao termica
float s = sensacao_termica(t, u);
// Obter o timestamp atual em milissegundos
unsigned long timestamp = millis();
Serial.print(timestamp);
Serial.print(",");
Serial.print(t);
Serial.print(",");
Serial.print(s);
Serial.print(",");
Serial.println(u);
delay(10000);
}
Neste código, a biblioteca #include <DHT.h> é incluída para facilitar o uso do sensor DHT11. A inicialização do sensor ocorre no setup() com a função dht.begin(), enquanto no loop() são utilizadas as funções dht.readTemperature() e dht.readHumidity() para obter as leituras de temperatura e umidade. Além disso, foi criada uma função para calcular a sensação térmica com base nesses valores. O código também registra o timestamp atual utilizando a função millis(). O resultado pode ser visto na imagem abaixo.
Implementação do Código para Leitura BMP180
Inicialmente, instale a biblioteca “Adafruit_BMP085” e a “Adafruit BMP085 Unified”:
Em seguida, grave o código abaixo. Nesse código, foi incluída a leitura da pressão atmosférica ao nível do mar. No setup(), a inicialização do sensor BMP180 é feita com bmp.begin(), garantindo que, se o sensor não for corretamente inicializado, o programa fique preso em um while. No loop(), a pressão é lida usando bmp.readSealevelPressure(), que retorna o valor em Pa. Como a API de dados utiliza a pressão em milibares (mb), o valor lido é dividido por 100.
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
#define DHTPIN 15 // Pino digital conectado ao sensor DHT
#define DHTTYPE DHT11 // Tipo de sensor DHT
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp; //Adafruit_BMP085 (I2C)
float sensacao_termica(float temperatura, float umidade){
float sensacao = temperatura -((0.55-0.0055*umidade)*(temperatura-14.5));
return sensacao;
}
void setup() {
Serial.begin(115200);
Serial.println(F("Inicializando DHT..."));
dht.begin();
if (!bmp.begin()) {
Serial.println("Nao foi possivel iniciar bmp, verifique os jumpers");
while (1) {}
}
}
void loop() {
// Leitura da temperatura e umidade
float t = dht.readTemperature();
float u = dht.readHumidity();
// Calcula sensacao termica
float s = sensacao_termica(t, u);
// Leitura pressao em mb
float p = (bmp.readSealevelPressure())/100.0;
// Obter o timestamp atual em milissegundos
unsigned long timestamp = millis();
// Imprime Serial
Serial.print(timestamp);
Serial.print(",");
Serial.print(t);
Serial.print(",");
Serial.print(s);
Serial.print(",");
Serial.print(u);
Serial.print(",");
Serial.println(p);
delay(10000);
}
O resultado pode ser visto na imagem abaixo.
Implementação Código utilizando o modelo de ML
Grave o código abaixo em sua placa.
#include <clima_inferencing.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
static bool debug_nn = true; // true para conseguir visualizar as features geradas
#define DHTPIN 15 // Pino digital conectado ao sensor DHT
#define DHTTYPE DHT11 // Tipo de sensor DHT
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp; //Adafruit_BMP085 (I2C)
float sensacao_termica(float temperatura, float umidade){
float sensacao = temperatura -((0.55-0.0055*umidade)*(temperatura-14.5));
return sensacao;
}
void setup() {
Serial.begin(115200);
Serial.println(F("Inicializando DHT..."));
dht.begin();
if (!bmp.begin()) {
Serial.println("Nao foi possivel iniciar bmp, verifique os jumpers");
while (1) {}
}
if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 5) {
ei_printf("ERRO!)\n");
return;
}
}
void loop() {
float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 5) {
ei_printf("\nInicia em 60 segundos...\n");
delay(60000);
// Captura o timestamp
buffer[ix + 0] = (float)millis();
// Leitura da temperatura e umidade
float t = dht.readTemperature();
float u = dht.readHumidity();
// Calcula sensacao termica
float s = sensacao_termica(t, u);
// Leitura pressao em mb
float p = (bmp.readSealevelPressure())/100.0;
// Preencher o buffer
buffer[ix + 1] = t;
buffer[ix + 2] = s;
buffer[ix + 3] = u;
buffer[ix + 4] = p;
// Transformar o buffer bruto em um sinal para classificar
signal_t signal;
int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
if (err != 0) {
ei_printf("Falha ao criar sinal do buffer (%d)\n", err);
return;
}
// Roda classificador
ei_impulse_result_t result = { 0 };
err = run_classifier(&signal, &result, debug_nn);
if (err != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", err);
return;
}
// Predicoes
ei_printf("Predictions ");
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
result.timing.dsp, result.timing.classification, result.timing.anomaly);
ei_printf(": \n");
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf("%s: %.3f\n", result.classification[ix].label, result.classification[ix].value);
}
}
}
O funcionamento deste código segue os seguintes passos:
- Na primeira parte, você realizou o download da biblioteca com o modelo pré-treinado. Inicialmente, inclua essa biblioteca no seu código. O nome da biblioteca será algo como #include <clima_inferencing.h>.
- É feito a configuração dos Sensores
- No loop será capturado as leituras dos sensores e colocado os valores no buffer. Em seguida, é convertido esses dados brutos em um sinal que o modelo de ML pode interpretar.
- Depois que o sinal estiver pronto, o classificador será executado para fazer previsões com base nas features geradas.
- As previsões resultantes serão exibidas no monitor serial.
O resultado pode ser visto na imagem abaixo. No dia em que realizei o teste, o clima estava favorável, com céu limpo. O algoritmo indicou uma probabilidade de 99% de que não estava chovendo e apenas 0% de chance de chuva.
No entanto, a título de teste, considerando que não estava chovendo no dia em que realizei o teste, selecionei algumas linhas do arquivo rain_teste.csv e atribuí um random para os valores das variáveis de temperatura, sensação térmica, umidade e pressão.

As seguintes linhas no código foram modificadas:
float t = random(162, 171+ 1)/10.0;
float u = random(849, 922+ 1)/10.0;
float s = random(162, 171+ 1)/10.0;
float p = random(101250, 101530 + 1)/100.0;
// Preencher o buffer
buffer[ix + 1] = t;
buffer[ix + 2] = s;
buffer[ix + 3] = u;
buffer[ix + 4] = p;
E após gravar o código novamente, obtive os seguintes resultados:
O modelo apresentou uma probabilidade de 50% para chuva e 50% para ausência de chuva. Isso mostra que ele está eficaz em identificar a ausência de precipitação, mas ainda precisa ser aprimorado na detecção de condições de chuva.
Código disponível
O projeto juntamente com a biblioteca treinada na parte 1 pode ser encontrado em: https://github.com/Graziele-Rodrigues/TinyML_FranzininhoWifi/tree/main/clima/predicao
Conclusão
Esse projeto mostra que é possível identificar a presença de chuva utilizando sensores em conjunto com técnicas de machine learning. A aplicação de um projeto como esse pode ser benéfica na agricultura, por exemplo, onde previsões precisas de chuva podem auxiliar no planejamento de irrigação e colheitas. Embora nosso modelo tenha apresentado uma alta taxa de acerto na identificação da ausência de chuva, os testes simulando diferentes condições climáticas revelaram uma probabilidade de 50% tanto para a ocorrência de chuva quanto para sua ausência. Isso indica que, apesar do modelo ser eficiente em detectar a ausência de precipitação, ainda há espaço para melhorias na precisão das previsões de chuva. Para aumentar a eficácia do sistema, é possível expandir a abordagem para incluir outros fatores climáticos, como a velocidade do vento. A API utilizada na primeira parte do projeto oferece uma variedade de dados que podem ser explorados para otimizar ainda mais as previsões. Assim, fica o desafio de aprimorar o modelo.






