#include <Arduino.h>
#include <LCDI2C_Multilingual.h> //Added to manage LCD
#include <NTPClient.h> //Added to connect NTP Public server
#include <WiFi.h> //Added to manage Wifi
#include <WiFiUdp.h> //Added to manage Wifi
//Wifi Access Data
const char* wifi_ssid = "Wokwi-GUEST";
const char* wifi_password = "";
#define Wifi_channel 10 // Defining the WiFi channel speeds up the connection
//PinOuts
#define echoPin 18 // attach pin GPIO18 to pin Echo of AJ-SR04M
#define trigPin 5 // attach pin GPIO5 ESP32 to pin Trig of AJ-SR04M
#define sound_speed 0.0344 //sound speed in CM/uSeg
#define buzzerPin 13 // attach pin GPIO13 to Buzzer +VE
#define powerLed 2 // attach pin GPIO02 to Led + Resistor
#define warnLed 4 // attach pin GPIO04 to Led + Resistor
#define COLS 16 // Columns of LCD
#define ROWS 2 // Rows of LCD
LCDI2C_Latin lcd = LiquidCrystal_I2C_Latin(0x27, COLS, ROWS); // LCDI2C_Generic
long duration; // Time taken for the pulse to reach the receiver
const float distanceEmpty= 180; // Max Critical Distance (180 cms), value clud change depends on of tank size
const float distanceFull= 35; // OverFull distance between sensor and minim water distance (cm). To check & Resize
const float range=distanceEmpty-distanceFull;
int demora;
char* status;
//variable to calc distance & percentage of tank
float distanceCM;
float percentage_measureCM;
float percen;
// Número de muestras para calcular la media
const int numLecturas = 30; //Cant. de lecturas antes de mostrar medición
//Variables y arrays para hacer varias lecturas de distancia
float lecturas[numLecturas]; // Array para almacenar lecturas
int lecturaActual = 0; // Lectura por la que vamos
float total = 0; // Total de las que llevamos
float media = 0; // Media de las medidas
bool primeraMedia = false; // Para saber que ya hemos calculado por lo menos una
void displayLCD(const char* tankstatus, float distanceCalc, int percentageCalc, String time)
{
Serial.println("LCD Msg: " + String(tankstatus));
Serial.println("LCD Distance cm: " + String(distanceCalc));
Serial.println("LCD Percentage %: " + String(percentageCalc));
lcd.clear(); //LCD Clear
lcd.setCursor(0, 0);
lcd.print(String(tankstatus) + String(percentageCalc)+"%-"+ String(time));
lcd.setCursor(0, 1);
lcd.print("Dist.(cm):"+ String(distanceCalc));
}
void buzzerAlert(int demora, const char* status)
{
Serial.println("Trigger Buzzer - demora: "+ String(demora)+ " / Tipo:" + String(status));
if (status=="A")
{
tone(buzzerPin,587);
delay(demora);
noTone(buzzerPin);
}
else
{ //Tipo N
tone(buzzerPin,640);
delay(1000);
noTone(buzzerPin);
}
}
void start_measure()
{
digitalWrite(trigPin, LOW); //Clears the trigPin
delayMicroseconds(2); // keep the trigger "OFF"
digitalWrite(trigPin, HIGH); // turn on the Trigger to generate pulse
delayMicroseconds(10); // keep the trigger "ON" for 10 ms to generate pulse
digitalWrite(trigPin, LOW); // Turn off the pulse trigger to stop pulse
}
void warningLed()
{
digitalWrite(warnLed, HIGH);//Power Warning Led ON
delay(1500);
digitalWrite(warnLed, LOW);//Power Warning Led OFF
}
//Data to connect NTP Server
WiFiUDP ntpUDP;
//NTPClient timeClient(ntpUDP, "in.pool.ntp.org", -10800); // UTC offset for Argentina (3 hours later)
NTPClient timeClient(ntpUDP, "in.pool.ntp.org");
void setup()
{
pinMode(trigPin, OUTPUT); //sets trigPin as an Output
pinMode(echoPin, INPUT); //sets echoPin as an Input
pinMode(powerLed, OUTPUT); //sets powerLed as an Output
pinMode(warnLed, OUTPUT); //sets warnLed as an Output
Serial.begin(115200); //starts the serial communication
Serial.println("Distance measurement using AJ-SR04M");
lcd.init();//LCD inicializing
lcd.backlight(); // Turn on the backlight
displayLCD ("Starting measurement",0,0," "); //Display Setup/Start
delay(2000);
lcd.setCursor(0,1);
lcd.print("Start in 5..."); //You can write 16 Characters per line .
delay(1000); //wait 3 sec
lcd.setCursor(0,1);
lcd.print("Start in 4..."); //You can write 16 Characters per line .
delay(1000); //wait 3 sec
lcd.setCursor(0,1);
lcd.print("Start in 3..."); //You can write 16 Characters per line .
delay(1000); //wait 3 sec
lcd.setCursor(0,1);
lcd.print("Start in 2..."); //You can write 16 Characters per line .
delay(1000); //wait 3 sec
lcd.setCursor(0,1);
lcd.print("Start in 1..."); //You can write 16 Characters per line .
delay(1000); //wait 3 sec
// Buzzer test on Setup/Start
buzzerAlert(1000,"N"); //Buzzer alert beep
digitalWrite(powerLed, HIGH); //Power Led ON
warningLed(); // Blinking Warning Led
lcd.clear(); //LCD Clear
lcd.setCursor(0,0);
lcd.print("Connecting to "); //You can write 16 Characters per line .
lcd.setCursor(1,0);
lcd.print("SSID: "+ String(wifi_ssid));
delay(2500);
WiFi.begin(wifi_ssid, wifi_password, Wifi_channel); //Initi Wifi Connection
while ( WiFi.status() != WL_CONNECTED )
{
warningLed(); // Blinking Warning Led
//lcd.setCursor(0,1);
lcd.print(".");
Serial.print ( "." );
}
Serial.println("WIFI CONNECTED");
lcd.clear(); //LCD Clear
lcd.setCursor(0,0);
lcd.print("SSID: "+ String(wifi_ssid)+" connected");
//lcd.setCursor(1,0);
//lcd.print("CONNECTED");
buzzerAlert(1500,"N"); //Buzzer alert beep
delay(2500);
Serial.println("ESP Wifi IP:"+ String(WiFi.localIP()));
Serial.println("ESP Board MAC Address: "+ String(WiFi.macAddress()));
// Inicializamos el array
for (int i = 0; i < numLecturas; i++)
{
lecturas[i] = 0;
}
timeClient.begin();//Init NTP Client
timeClient.setTimeOffset(-10800); // GMT-3
Serial.println("");
timeClient.update(); //Update NTP Datetime
}
void loop()
{
// Eliminamos la última medida
total = total - lecturas[lecturaActual];
start_measure(); // Start measure with AJ-SR04M, using trigPin
// If pulse reached the receiver echoPin
// become high Then pulseIn() returns the
// time taken by the pulse to reach the receiver
duration = pulseIn(echoPin, HIGH); //Reads the echoPin, returnd the sound wave travel time in uSeg
distanceCM = duration * sound_speed / 2;
// % Calc. value about distanceCM / distanceFull / range
percentage_measureCM = ((distanceCM-distanceFull)/range)*100;
timeClient.update(); //Update NTP Datetime
// Get TimeStamp
String time;
time = (timeClient.getFormattedTime());//Current time
String hour = time.substring(0, 2); //HH
String minute = time.substring(3, 5); //MM
String TimeStamp = hour + ":" + minute;
//Serial.println("TimeStamp: "+ hour + ":"+minute);
//Serial.println("TimeStamp: "+ TimeStamp);
Serial.println("===========================");
Serial.println("Values - " + TimeStamp);
Serial.println("===========================");
Serial.println("Tank %: " + String(percentage_measureCM));
Serial.print("Distance: " + String(distanceCM));
Serial.println(" cm");
Serial.println("===========================");
//--------------------------------------------------------------------------------------------------
if ( (primeraMedia) && (distanceCM != media ) && ( ((((distanceCM/media)-1)*100)>1) || (((((distanceCM/media)-1)*100)*-1)>1)) )
{
Serial.println("ingreso a limpiar array y datos");
Serial.println("Distance:" + String(distanceCM) );
Serial.println("media:" + String(media));
for (int i = 0; i < numLecturas; i++)
{
lecturas[i] = 0;
lecturaActual = 0; // Lectura por la que vamos
}
primeraMedia = false; //Indicamos que no se muestran mas datos hasta calcular nueva media
total =0; // Borras total
media =0; // Borramos media si el cambio fue > 4 o < 4
}
if ((!primeraMedia))
{
// Almacenamos la distancia en el array
lecturas[lecturaActual] = distanceCM;
// Añadimos la lectura al total
total = total + lecturas[lecturaActual];
// Avanzamos a la siguiente posición del array
lecturaActual = lecturaActual + 1;
Serial.println("Total : " + String(total));
Serial.println("Lectura Actual :" + String(lecturaActual));
// Calculamos la media
media = total / numLecturas;
Serial.println("Media : " + String(media));
// Comprobamos si hemos llegado al final del array
if (lecturaActual >= numLecturas)
{
primeraMedia = true;
lecturaActual = 0;
//Muestro la media calculada o recalculada en el LCD
//lcd.setCursor(0, 1);
//lcd.print(media);
//lcd.print(" cm");
if (media >= distanceEmpty)
{ //Tank Empty (LOW LIQUID)
if (percentage_measureCM > 99) // Si super el Umbral Max
{ percen = 0; // cuando es > 99, ponemos que el tanque esta vacio
}
displayLCD ("Empty! ", distanceCM, percen, TimeStamp); // display LCD Empty tank!!
buzzerAlert(5000, "A"); //Buzzer alert code
warningLed(); // Blinking Warning Led
Serial.println("Lectura :Empty - Wait 10 seg");
delay(10000); //luego de una lectura correcta esperamos 10 seg para volver a leer
}
else
{
if (media <= distanceFull)
{ //Tank Over Full
displayLCD ("Full!", distanceCM, 100, TimeStamp);
buzzerAlert(5000, "A"); //Buzzer alert code
warningLed(); // Blinking Warning Led
Serial.println("Lectura :Empty - Wait 10 seg");
delay(10000); //luego de una lectura correcta esperamos 10 seg para volver a leer
}
else
{ //Tank Normal
displayLCD ("Tank:", distanceCM, (100-percentage_measureCM), TimeStamp);
Serial.println("Lectura :OK - Wait 90 seg");
delay(90000); //luego de una lectura correcta esperamos 60 seg = 60.000 para volver a leer. Subimos a 900.000
}
}
//Espera con Delay
//delay (300000); // espera de 300000 seg = 5 min si la media fue calculada
}
}
// Agrega un DELAY en el caso de que la lectura no cambie.... para que no se ejecute nuevamente el loop
if (primeraMedia)
{ Serial.println("Calculo :" + String((((distanceCM/media)-1)*100)));
if ((((distanceCM/media)-1)*100)<1 || ((((distanceCM/media)-1)*100)>-1))
{
//Si la variacion de la distancia este entre Distancia/Media es < 1% o > -1% no hace nada, solo delay en el loop
Serial.print("distancia: " + String(distanceCM));
Serial.println (" - media: " + String(media));
//delay(10000); //demora 300000 = 5 min si la lectura vario menos de 1%
if (media >= distanceEmpty)
{ //Tank Empty (LOW LIQUID)
if (percentage_measureCM > 99) // Si super el Umbral Max
{ percen = 0; // cuando es > 99, ponemos que el tanque esta vacio
}
displayLCD ("Empty! ", distanceCM, percen, TimeStamp); // display LCD Empty tank!!
buzzerAlert(5000, "A"); //Buzzer alert code
warningLed(); // Blinking Warning Led
Serial.println("Lectura :Empty - Wait 10 seg");
delay(10000); //luego de una lectura correcta esperamos 10 seg para volver a leer
}
else
{
if (media <= distanceFull)
{ //Tank Over Full
displayLCD ("Full!", distanceCM, 100, TimeStamp);
buzzerAlert(5000, "A"); //Buzzer alert code
warningLed(); // Blinking Warning Led
Serial.println("Lectura :Empty - Wait 10 seg");
delay(10000); //luego de una lectura correcta esperamos 10 seg para volver a leer
}
else
{ //Tank Normal
displayLCD ("Tank:", distanceCM, (100-percentage_measureCM), TimeStamp);
Serial.println("Lectura :OK - Wait 90 seg");
delay(90000); //luego de una lectura correcta esperamos 60 seg = 60.000 para volver a leer. Subimos a 900.000
}
}
}
}
//--------------------------------------------------------------------------------------------------
//Delay ms to start loop again
delay(100);
}