#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <base64.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
// RAIN GAUGE
#define RAIN_GAUGE_PIN 0 // Pino conectado ao pluviômetro
#define ANEMOMETER_PIN 1 // Pino conectado ao anemômetro
#define WIND_SPEED_20_PULSES 1.75 // Constante do anemômetro (m/s para 20 pulsos por segundo)
#define MM_PER_TIP 0.28 // Constante do pluviômetro (mm por pulso, ajuste conforme o modelo)
#define DEBOUNCE_TIME 100 // Tempo mínimo entre pulsos (em milissegundos)
volatile int rainPulseCount = 0; // Contador de pulsos (usar volatile para interrupções)
volatile unsigned long lastPulseTime = 0; // Timestamp do último pulso
float precipitacaoMM = 0.0; // Precipitação acumulada em mm
volatile int windPulseCount = 0; // Contador de pulsos do anemômetro
volatile unsigned long lastWindPulseTime = 0; // Timestamp do último pulso do anemômetro
float windSpeed = 0.0; // Velocidade do vento em m/s
// Função de interrupção para contar pulsos da precipitacao com debouncing
void IRAM_ATTR handleRainGauge() {
unsigned long currentTime = millis();
// Verifica se o tempo desde o último pulso é maior que o tempo de debounce
if (currentTime – lastPulseTime > DEBOUNCE_TIME) {
rainPulseCount++; // Incrementa o contador
lastPulseTime = currentTime; // Atualiza o timestamp do último pulso
}
}
// Função de interrupção para o anemômetro com debouncing
void IRAM_ATTR handleAnemometer() {
unsigned long currentTime = millis();
if (currentTime – lastWindPulseTime > DEBOUNCE_TIME) {
windPulseCount++;
lastWindPulseTime = currentTime;
}
}
// BME280
#define BME_SCK 9 // Pino SCL (Clock)
#define BME_SDA 8 // Pino SDA (Data)
#define SEALEVELPRESSURE_HPA (1013.25)
#define BME280_ADDRESS 0x76
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
int led=8; // Led azul da placa
/////////////////////////////// PARAMETROS ESSENCIAS EM CADA MÓDULO //////////////////////////////////////////////
const char* nomeServidor=“lst37”;
const char* ssid = “LSTIMELAPSES”; // Replace with your WiFi SSID
const char* password = “xisitante”; // Replace with your WiFi password
/////////////////////////////// PARAMETROS ESSENCIAS EM CADA MÓDULO //////////////////////////////////////////////
const char* webhook_url = “https://n8n.lstimelapses.com.br/webhook/4f7f52fe-d2c4-440b-8c97-d0a4639cc9db”; // Replace with your webhook URL
const char* auth_token = “your_bearer_token_or_api_key”; // Replace with your Bearer token or API key
const char* apiKeyLstimelapses = “apiKeyLstimelapses”;
const char* senhaApiKeyLstimelapses = “0527b963-4eba-46fe-924a-33ce0dd1c8cf”;
void setup() {
Serial.begin(115200);
while (!Serial); // Aguarda a porta serial abrir (útil para alguns ESP32)
pinMode(led, OUTPUT);
// Connect to WiFi
WiFi.begin(ssid, password);
Serial.print(“Connecting to WiFi…”);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(“.”);
}
Serial.println(“\nConnected to WiFi”);
// RAINGAUGE e ANEMOMETER
pinMode(RAIN_GAUGE_PIN, INPUT_PULLUP); // Configura o pino com pull-up interno
pinMode(ANEMOMETER_PIN, INPUT_PULLUP); // Configura o pino do anemômetro com pull-up interno
// Configura a interrupção no pino do pluviômetro
attachInterrupt(digitalPinToInterrupt(RAIN_GAUGE_PIN), handleRainGauge, FALLING);
attachInterrupt(digitalPinToInterrupt(ANEMOMETER_PIN), handleAnemometer, FALLING);
blinkErrorLed();
ligarLed();
// BME 280
// Inicializa a interface I2C com os pinos definidos
Wire.begin(BME_SDA, BME_SCK);
bool status = bme.begin(BME280_ADDRESS, &Wire);
//blinkOKLed();
if (!status) {
Serial.println(F(“Não foi possível encontrar um sensor BME280 válido!”));
Serial.println(F(“Verifique as conexões ou o endereço I2C (0x76 ou 0x77).”));
blinkErrorLed();
while (1) delay(10); // Loop infinito se o sensor não for encontrado
}
Serial.println(F(“BME280 inicializado com sucesso!”));
Serial.println(F(“Lendo dados do sensor…”));
delayTime = 1000;
}
void loop() {
// Desabilita interrupções para leitura segura do contador
noInterrupts();
int rainGaugeCount = rainPulseCount;
int windCount = windPulseCount;
rainPulseCount = 0; // Reseta o contador
windPulseCount = 0; // Reseta o contador do anemômetro
interrupts();
// Calcula a precipitação
precipitacaoMM = rainGaugeCount * MM_PER_TIP;
// Calcula a velocidade do vento (m/s)
// windCount é o número de pulsos em 10 segundos
float pulsesPerSecond = windCount / 10.0;
windSpeed = (pulsesPerSecond / 20.0) * WIND_SPEED_20_PULSES;
// Exibe no monitor serial
Serial.print(“Pulsos detectados: “);
Serial.println(rainGaugeCount);
Serial.print(“Precipitação (mm): “);
Serial.println(precipitacaoMM);
Serial.print(“Pulsos anemômetro: “);
Serial.println(windCount);
Serial.print(“Velocidade do vento (m/s): “);
Serial.println(windSpeed);
if (WiFi.status() == WL_CONNECTED) {
delay(2000);
HTTPClient http;
// Begin HTTP connection
http.begin(webhook_url);
http.addHeader(“Content-Type”, “application/json”);
//http.addHeader(“Authorization”, String(“Bearer “) + auth_token); // Add Bearer token; adjust for Basic or other auth
//http.addHeader(“Authorization”, “Basic ” + base64::encode(“username:password”));
http.addHeader(apiKeyLstimelapses, senhaApiKeyLstimelapses);
// Lê os valores do sensor
//float temperatura = bme.readTemperature();
float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA); // 1013.25 é a pressão atmosférica padrão ao nível do mar em hPa
// Create JSON object
StaticJsonDocument<200> doc;
doc[“operacao”] = “inserirDados”;
doc[“nomeServidor”] = nomeServidor;
doc[“dataHoraGravacao”] = “CURRENT_TIMESTAMP”;
doc[“precipitacaoMM”] = precipitacaoMM;
doc[“pressao”] = bme.readPressure() / 100.0F;
doc[“temperatura”] = bme.readTemperature();
doc[“humidade”] = bme.readHumidity();
doc[“velocidadeVento”] = windSpeed;
//doc[“altitude”] = bme.readAltitude(SEALEVELPRESSURE_HPA);
String jsonString;
serializeJson(doc, jsonString);
// Send HTTP POST request
int httpResponseCode = http.POST(jsonString);
//int httpResponseCode = http.GET();
// Check response
if (httpResponseCode > 0) {
Serial.print(“HTTP Response code: “);
Serial.println(httpResponseCode);
String response = http.getString();
Serial.println(“Response: “ + response);
//blinkOKLed();
} else {
Serial.print(“Error on sending POST: “);
Serial.println(httpResponseCode);
}
// End HTTP connection
http.end();
} else {
Serial.println(“WiFi Disconnected”);
}
blinkOKLed();
delay(60000); // Envia a cada 60s
}
void ligarLed()
{
digitalWrite(led, HIGH);
}
void blinkOKLed()
{
digitalWrite(led, HIGH);
delay(1000);
digitalWrite(led, LOW);
delay(1000);
digitalWrite(led, HIGH);
delay(1000);
}
void blinkErrorLed()
{
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
digitalWrite(led, HIGH);
delay(300);
digitalWrite(led, LOW);
delay(300);
}