/*==================================================================================================
* File: Test esp bme280+ Viento incluye wifi + Thingspeak + Luxometro + GUVA + lux
* Fecha: 15 de enero de 2024
* Autor: Joseba Barriola D.
* Nota: Programa maestro de estacion metereologica a correr en ESP32 Maestro
* Incluye lectura de Humedad, temperatura, P. Atmosferica, Luminancia
* y direccion de viento, Indice UV, Lluvia
* Inclusión de Hora y fecha
BME280 en I2C Conectados SCK->GPIO22, SDI ->GPIO21
BH1750 en I2C Conectados SCK->GPIO22, SDI ->GPIO21
* Se incluye velocidad del viento, lluvia y veleta
* Viento se conecto en pin 14, Veleta pin 35 y Lluvia en pin 25
* Incluyo medicion de luz: BH1758, conectado en I2C
* La variable Lux se multiplico * 2 para asemejarse a la lectura del luxometro digital
* **** Elimino las variables de viento que no uso y se reordeno para Thingspeak, incuir Photosensor
*/
// ================================== Libreria ===========================================//
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Time.h>
Adafruit_BME280 bme; // I2C
#include <ESP32Time.h>
#include <ThingSpeak.h>
#include <BH1750.h>
BH1750 lightMeter(0x23);
//=================== Pin assignment definitions ==========================================
const byte WSPEED = 14; // Anemometro
const byte RAIN = 25; // Veleta
#define WDIR 35 // **************verificar cual corresponde a a0*******
float UV = 34;
float sensorVoltage;
float sensorValue;
float PhotoSensor;
const byte PIRANOMETRO = 33;
//========================= Declaracion de variables y constantes ==================================
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -7200;
const int daylightOffset_sec = -7200;
unsigned long delayTime;
unsigned long channelID = 2203194;
const char* WriteAPIKey ="NLP4XWWNKMMPZHMQ";
WiFiClient cliente;
String Direccion;
int vin = 0;
String windDir = "";
float angle = 0;
// ============================ viento =========================================================
long lastSecond; //The millis counter to see when a second rolls by
byte seconds; //When it hits 60, increase the current minute
byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data
byte minutes; //Keeps track of where we are in various arrays of data
byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data
long lastWindCheck = 0;
volatile long lastWindIRQ = 0;
volatile byte windClicks = 0;
byte windspdavg[120]; //120 bytes to keep track of 2 minute average
volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain
//These are all the weather values that wunderground expects:
float windspeedmph = 0; // [mph instantaneous wind speed]
float windspdmph_avg2m = 0; // [mph 2 minute average wind speed mph]
float rainin = 0; // [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min
volatile float dailyrainin = 0; // [rain inches so far today in local time]
// volatiles are subject to modification by IRQs
volatile unsigned long raintime, rainlast, raininterval, rain;
//========================= Variables for wifi server setup =============================
char* ssid = "UNIMET-Estudiantes"; // WiFi Router
char* pass = ""; // WiFi Router password
// ====================================== Conexion del wifi =====================================
WiFiServer server(80);
//}//============================= Funcion fecha hora ==========================================
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, " %B %d %Y %H:%M:%S");
}//======================================== Viento ===============================================
//Interrupt routines (these are called by the hardware interrupts, not by the main code)
void rainIRQ()
{
raintime = millis(); // grab current time
raininterval = raintime - rainlast; // calculate interval between this and last event
if (raininterval > 10) // ignore switch-bounce glitches less than 10mS after initial edge
{
dailyrainin += 0.011; //Each dump is 0.011" of water
rainHour[minutes] += 0.011; //Increase this minute's amount of rain
rainlast = raintime; // set up for next event
}
}
void wspeedIRQ()
{
if (millis() - lastWindIRQ > 10) // Ignore switch-bounce glitches less than 10ms (142MPH max reading) after the reed switch closes
{
lastWindIRQ = millis(); //Grab the current time
windClicks++; //There is 1.492MPH for each click per second.
}
}
void setup() {
Serial.begin(115200);
Wire.begin(); // Luxometro **** No se si hace falta *****
lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE); //Luxometro
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("CONNECTED");
pinMode(WSPEED, INPUT); // input from wind meters windspeed sensor ****** 1 ****
pinMode(RAIN, INPUT); // input from wind meters rain gauge sensor ****** 3 ****
seconds = 0;
lastSecond = millis();
attachInterrupt(digitalPinToInterrupt(RAIN), rainIRQ, FALLING);
attachInterrupt(digitalPinToInterrupt(WSPEED), wspeedIRQ, FALLING);
interrupts();
if (!bme.begin()) {
Serial.println(F("No se encuentra un sensor BME280 valido!"));
while (1) delay(10);
}
Serial.println("-- Default Test --");
delayTime = 100;
Serial.println();
Serial.println(F("BME280 test"));
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime(); //******* debo verificar si esta redundante
ThingSpeak.begin(cliente);
delay(1000);
}
void loop()
{
delay(1000);
medicion();
get_wind_direction();
ThingSpeak.writeFields(channelID,WriteAPIKey);
//lectura uv
sensorValue=analogRead(34);
PhotoSensor=analogRead(PIRANOMETRO);
sensorVoltage = sensorValue/1024*3.3;
UV=sensorVoltage;
/*Imprimimos una frase indicando el envío, y agregamos un retardo de 10 segundos*/
Serial.println("Datos enviados a ThingSpeak!");
delay(5000); //****************** 2 *************** era 10000
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Se ha perdido la conexión WiFi");
WiFi.begin(ssid, pass);
delay(5000);
}
//========================================= Viento =============================================
if(millis() - lastSecond >= 1000)
{
lastSecond += 1000;
if(++seconds_2m > 119) seconds_2m = 0;
float currentSpeed = get_wind_speed();
windspeedmph = currentSpeed; //update global variable for windspeed when using the printWeather() function
windspdavg[seconds_2m] = (int)currentSpeed;
if(++seconds > 59)
{
seconds = 0;
if(++minutes > 59) minutes = 0;
if(++minutes_10m > 9) minutes_10m = 0;
rainHour[minutes] = 0; //Zero out this minute's rainfall amount
}
printWeather();
}
delay(100);
}
void medicion(){
float temperatura= bme.readTemperature();
float humedad = bme.readHumidity();
float presion = bme.readPressure() / 100.0F;
float lux = lightMeter.readLightLevel();
float lux2 = lux*2;
ThingSpeak.setField(1,temperatura);
ThingSpeak.setField(2,humedad);
ThingSpeak.setField(3,windspeedmph);
ThingSpeak.setField(4,windDir); //************************************************
ThingSpeak.setField(5,rainin);
ThingSpeak.setField(6,UV);
ThingSpeak.setField(7,lux2);
ThingSpeak.setField(8,PhotoSensor);
}
//Calculates each of the variables that wunderground is expecting
void calcWeather()
{
rainin = 0;
for(int i = 0 ; i < 60 ; i++)
rainin += rainHour[i];
}
//Returns the instataneous wind speed
float get_wind_speed()
{
float deltaTime = millis() - lastWindCheck; //750ms
deltaTime /= 1000.0; //Covert to seconds
float windSpeed = (float)windClicks / deltaTime; //3 / 0.750s = 4
windClicks = 0; //Reset and start watching for new wind
lastWindCheck = millis();
windSpeed *= 1.492; //4 * 1.492 = 5.968MPH
return(windSpeed);
}
void get_wind_direction()
{
vin = analogRead(WDIR);
if (vin < 150) windDir="202.5"; // SSW
else if (vin < 300) windDir = "180"; // S
else if (vin < 400) windDir = "247.5"; // WSW
else if (vin < 600) windDir = "225"; // SW
else if (vin < 900) windDir = "292.5"; // WNW
else if (vin < 1100) windDir = "270"; // W
else if (vin < 1500) windDir = "112.5"; // ESE
else if (vin < 1700) windDir = "135"; // SE
else if (vin < 2250) windDir = "337.5"; // NNW
else if (vin < 2350) windDir = "315"; // NW
else if (vin < 2700) windDir = "67.5"; // ENE
else if (vin < 3000) windDir = "90"; // E
else if (vin < 3200) windDir = "22.5"; // NNE
else if (vin < 3400) windDir = "45"; // NE
else if (vin < 4000) windDir = "0"; // N
else windDir = "0";
}
void printWeather()
{
calcWeather(); //Go calc all the various sensors
printLocalTime();
Serial.println();
Serial.print("windspeedmph= ");
Serial.print(windspeedmph, 1);
Serial.print(" / winddir= ");
Serial.print(windDir);
Serial.print(" / rainin= ");
Serial.print(rainin, 2);
Serial.print(", dailyrainin= ");
Serial.println(dailyrainin, 2);
Serial.print("Temperatura = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
Serial.print("Presion = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Humedad = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
// luxometro
float lux = lightMeter.readLightLevel();
float lux2 = lux*2;
Serial.print("Light: ");
Serial.print(lux2);
Serial.println(" lx");
// UV
Serial.print("sensor reading = ");
Serial.print(sensorValue);
Serial.print(" sensor voltage = ");
Serial.print(sensorVoltage);
Serial.print(" V ");
Serial.println(PhotoSensor);
Serial.println(" ");
}