Es vol mesurar a quina altura es troba el aigua de un recipient, per extrapolar després a una piscina i poder observar la pèrdua d’aigua per evaporació o altres causes. Per aquest projecte fem servir la memòria FLASH del chip ESP8266, per emmagatzemar les dades rebudes del sensor de distancia HC-SR04. Des de un navegador WEB en mode client i connectat al servidor NodeMCU, volem iniciar una sèrie de mesures d’altures indicant la data d’inici i el interval entre mesures. Les dades es guarden en format CSV i posteriorment ser exportades a una fulla de càlcul.
Placa NodeMCU que te WiFi integrat.
Sensor de ultrasons HC-SR04.
Dues resistències de 330 Ω.
IDE de Arduino.
Llibreria FS.h File System per la gestió del sistema d’arxius.
https://www.youtube.com/watch?v=eCe9A9wq4Go
https://www.esploradores.com/uso-memoria-flash-para-almacenamiento-de-datos/

El microcontrolador ESP8266 conté SPIFFS, Serial Peripheral Interface Flsh File System . SPIFFS es un sistema de fitxers lleuger en el chip de la memòria flash que incorpora el ESP8266. Per carregar els fitxers a la memòria flash es fa servir un plugin per el IDE de Arduino. SPIFFS dona accés als fitxers de la memòria flash de la mateixa manera que ho fem en el nostre ordinador, però mes simple i mes limitat. Es pot llegir, escriure, eliminar fitxers. No suporta directoris, tots els fitxers tenen que estar en el mateix nivell, en la carpeta data.
Volem mesurar les altures del aigua en un recipient, volem guardar suficients dades, per poder crear un fitxer CSV i exportar-lo a una fulla de càlcul. Les dades les guardem en la memòria FLASH del microcontrolador ESP8266.
Configurem el ESP8266 com a servidor AccesPoint. El client des d’un navegador al connectar amb el AccesPoint, rep un formulari al escriure la URL: 192.168.4.1
En el formulari tenim la data i hora actual i dos camps a emplenar, el interval entre diferents mesures i si es vol buidar la memòria FLASH o no. El formulari al enviar-lo, envia al servidor la data hora, el interval i si o no es buida la memòria i també comença a mesurar les altures, cada interval de temps. Les mesures es guarden en un fitxer de la memòria.
El client amb la URL: 192.168.4.1/altura, don la ordre al servidor de servir en el navegador la lectura del fitxer on es guarden les mesures preses.
Copiem les dades del navegador en un fitxer de text .csv. Importem el fitxer des el EXCEL o LibreOffice i ja podem fer gràfics.
El formulari ha de mostrar la data hora actual. La data hora actual es la data inicial per prendre les mesures, que es un String, la passem al tipus time_t, que son els segons que han pasat des de 1970. Amb aquest numero podem sumar-li el interval entre trets del sensor. Per guardar la data en el fitxer tenim que tornar passar de time_t a String.
Emissor Trigger, envia la ona de ultrasons.
Receptor Echo, rep la ona de tornada.

Podem saber la distancia, saben la duració de la ona de anada i tornada, aplicant la formula:
Distancia= velocitat del so * duració
Velocitat del so=340 m/s= 0.034 cm/µs
La duració es d’anada i tornada, tenim que dividir-la per 2
Distancia=(0.034 cm/µs*duració µs)/2
En el nostre codi, posem:
long duracio = pulseIn(EchoPin, HIGH);
// convertim la altura, en cm
long alturaCm = duracio * 10 / 292/ 2;
// 10/292=0.0342465
El codi esta força comentat, esperem que s’entengui.

/*
* Es vol mesurar els milimetres de aigua que perd la piscina per evaporació
* Fem servir http per visualitzar les dades
* Placa NodeMCU, sensor ultasonic HC-SR04
* magazamatge de dades en format CSV per exportar a un full de calcul
* SPIFFS Serial Peripheral Interface Flash File System
*/
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
//llibreria file system per gestionar els fitxers en memoria FLASH
#include <FS.h>
#include <TimeLib.h>
#define EchoPin D0
#define TriggerPin D1
#define LedPin D4
///// variables globals ///////
//temps (ms) del procesador encès
static unsigned long tempsMicroActiu;
File fitxer;
int interval;
long alturaCm;
String dataHora;
String iniciar = "no";
//el objecte time_t guarda els segons de la data actual a 1970
time_t tempsSegons;
const char *ssid_AP = "AlturaAP";
const char *password_AP = "12345678";
ESP8266WebServer server(80);
//guardem la pagina web en memoria flach
//formulari amb la data actual
//checkBox per formatajar la flash
//interval de lectures
//data inicial es: Sat Jan 30 2021 11:14:38 GMT+0100 (hora estándar de Europa central)
//la formatejem a 30/01/2021 11:14
static const char INDEX_HTML[] PROGMEM = R"(
<html>
<body>
<form action='/formulari'>
Data: <input type='datetime-local' name='dateTime' id='idData'><br>
Formatear memoria Flash: <input type='checkbox' name='format' value='si'><br>
Interval de Mesures (s): <input type="number" name="interval" min="10" step="10" value="30"><br><br>
<input type="submit" value="Enviar">
</form>
<script>
var dataActual = new Date();
var yyyy = dataActual.getFullYear();
var mm = dataActual.getMonth()+1; if(mm<10) {mm='0'+mm};
var dd = dataActual.getDate(); if(dd<10) {dd='0'+dd};
var hh = dataActual.getHours(); if(hh<10) {hh='0'+hh};
var mn = dataActual.getMinutes(); if(mn<10) {mn='0'+mn};
var dataActualFormat = dd+'-'+mm+'-'+yyyy+'H'+hh+'-'+mn;
document.getElementById('idData').value = dataActualFormat;
</script>
</body>
</html>
)";
//El servidor agafa la data actual que envia el formulari en mode GET
//converteix el String dataActual a time_t i el retorna
time_t convertirStringATime(String dataActual){
//String dataActual = server.arg("dateTime");
// el format de dataActual es: dd+'-'+mm+'-'+yyyy+'H'+hh+'-'+mn;
tmElements_t tm;
tm.Year = dataActual.substring(6,10).toInt()-1970;
tm.Month = dataActual.substring(3,5).toInt(); //6 ????
tm.Day = dataActual.substring(0,2).toInt();
tm.Hour = dataActual.substring(11,13).toInt();
tm.Minute = dataActual.substring(14,16).toInt();
time_t tempsSegons=makeTime(tm);
Serial.print("Temps segons->: ");
Serial.println(String(tempsSegons));//1612092824
return tempsSegons;
}
//converteix el tipus time_t a String i el retorna
String convertirTimeAString(time_t temps){
String dd = day(temps)<10? String("0")+String(day(temps)):String(day(temps)); //26
String mm = month(temps)<11? String("0")+String(month(temps)):String (month(temps)); //06
String yyyy=String(year(temps));
String hh = hour(temps)<10? String("0")+String(hour(temps)):String(hour(temps)); //23
String mn = minute(temps)<10? String("0")+String(minute(temps)):String(minute(temps)); //54
String dataHora = (dd+"/"+mm+"/"+yyyy+";"+hh+":"+mn+";"); //26/06/2018;23:54;
Serial.print("Data Hora->: ");
Serial.println(dataHora);
return dataHora;
}
//Funció per formatejar la memoria flash SPIFFS
void format_SPIFFS(){
if (server.arg("format") == "si"){
Serial.println("Formateix iniciat...");
digitalWrite(LedPin, LOW);
SPIFFS.format();
Serial.println("Formateix finalizat!");
digitalWrite(LedPin, HIGH);
}
}
//llegeix el fitxer global
void llegir_SPIFFS(){
fitxer = SPIFFS.open("/altura.txt", "r");
server.streamFile(fitxer, "text/plain");
fitxer.close();
}
long obtenirAltura() {
digitalWrite(LedPin, LOW);
//per generar un tret net posem a LOW 4us
digitalWrite(TriggerPin, LOW);
delayMicroseconds(4);
//generamos Trigger (tret) de 10us
digitalWrite(TriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(TriggerPin, LOW);
//mesurem el temps entre trets, en microsegons
long duracio = pulseIn(EchoPin, HIGH);
//convertim la altura, en cm
//alturaCm=(velocitat so * duracio)/2
// velocitat del so = 0.034cm/microseg
// 10/292=0.03424
long alturaCm = duracio * 10 / 292/ 2;
Serial.print("Altura: ");
Serial.println(alturaCm);
digitalWrite(LedPin, HIGH);
return alturaCm;
}
void setup() {
Serial.begin(115200);
pinMode(LedPin, OUTPUT);
digitalWrite(LedPin, HIGH);
pinMode(TriggerPin, OUTPUT);
pinMode(EchoPin, INPUT);
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid_AP, password_AP);
Serial.println("WiFi inicializada.");
Serial.print("La adreça del AccesPoint es IP: ");
Serial.println(WiFi.softAPIP());
Serial.println();
SPIFFS.begin();
//el servidor envia el formulari si el GET es "/"
server.on("/", []() {
server.send_P(200, "text/html", INDEX_HTML);
});
//Si s'envia el formulari, el servidor inicia el proces
server.on("/formulari", [](){
//envia el texte inicialitzat
server.send(200, "text/plain", "Inicializat!");
//posa la variable global iniciar a si
iniciar = "si";
//obté el inteval de lectures enviat del formulari
interval = server.arg("interval").toInt();
Serial.print("interval: ");
Serial.println(interval);
//comença a contar el temps en que el micro esta actiu
tempsMicroActiu = millis();
//obtenim la variable global dataHora del formulari
String dataForm=server.arg("dateTime");
Serial.print("Data hora formulari: ");
Serial.println(dataForm);
//la converim al tipus time_t i el guardem com a variable global
tempsSegons= convertirStringATime(dataForm);
//la converim String a time_t i el guardem com a variable global
//dataHora=convertirTimeAString(tempsSegons); NO ES NECESARI, PODEM FER SERVIR EL ARGUMENT DEL FORMULARI
dataHora=dataForm;
//formateja si en el formulari se clicat formateix, altrament res
format_SPIFFS();
//Si el fitxer altura.txt no existeix el crea de nou i afegeix al final
fitxer = SPIFFS.open("/altura.txt", "a+");
//escriu la capçalera del fitxer
fitxer.println("data;Hora;Altura (cm)");
fitxer.close();
});
//si el GET es /altura llegeix el fitxer altura.txt
server.on("/altura", [](){
llegir_SPIFFS();
});
server.begin();
Serial.println("Servidor inicializat.");
}
void loop() {
server.handleClient();
//Cada interval s'executa
if (iniciar == "si" && abs(millis()-tempsMicroActiu) > interval*1000) {
tempsSegons = tempsSegons + interval;
dataHora=convertirTimeAString(tempsSegons);
alturaCm=obtenirAltura();
fitxer = SPIFFS.open("/altura.txt", "a+");
fitxer.print(dataHora);
fitxer.println(alturaCm);
fitxer.close();
tempsMicroActiu = millis();
}
//Si porta 15 minuts sense incializarse ho fa automáticament
if (iniciar == "no" && millis()> 900*1000){
iniciar="si";
tempsSegons = 0;
interval = 60;
fitxer = SPIFFS.open("/altura.txt", "a+");
fitxer.println("Data;Hora;Altura (cm)");
fitxer.close();
}
}
Obrir el monitor serial a 115200 baudis on es mostra la adreça del servidor que sempre es:
192.168.4.1/

Connectar-se a la WiFi de nom AlturaAP amb al contrasenya 12345678. Una vegada estem en la mateixa xarxa, des del navegador, escrivim la url 192.168.4.1, el servidor respon amb el següent formulari:

Emplenem els camps, interval i format. Enviem el formulari. Si mirem que es el que enviem. Enviem la url, on en el comando GET hi ha la data, el format i el interval. El servidor al rebre les dades del formulari, inicia les mesures i le guarda en el fitxer altura.txt de la memòria FLASH.


Per llegir el fitxer guardat en memòria FLASH i obtenir les mesures d’altura, escrivim en el navegador la url:
192.168.4.1/altura
El servidor respon amb la llista de data - altura, separat en “;”, per poder exportar en format CVS.

Copiem del navegador la llista en un fitxer de text en extensió .cvs i el guardem en el nostre ordinador, anomenat nivells.csv.

Obrim el EXCEL o el CALC de OpenOffice, en el nostre cas fem servir el EXCEL. En el menú “datos” anem a “Desde el texto/CSV” i busquem el nostre fitxer guardat en el pas anterior, nivells.csv. Emergeix una nova finestra amb les dades i nomes tenim que carregar a la nostra fulla de càlcul. Cliquem el botó “CARGAR”.

En la fulla de càlcul seleccionem la llista amb les dades i en el menú “Insertar”, en el apartat de gràfics, escollim el tipus de gràfic que mes ens agrada.


El mar.
Havaneres.
Lloret antic.
Lloret avui.
De cala Morisca a Sa Carabera.
De Sa Carabera a Treumal.
Lloret en kayak.
Vígilancia remota.
Caixa-tpv.
Cambrer-app.
Client webApp.
Relats del banc del si no fos
Històries d'ahir
Vídeos antics de Lloret
El caiac
Contes de l'avi.
Control d’accés amb contrasenya.
Orgue de llums.
Comparativa de editors Arduino.
Projecte bon Nadal.
Control de la qualitat del aire interior (CO2) amb semàfor LED.
NodeMCU-ThingSpeak
ThingSpeak.
NodeMCU com AccessPoint.
Control de la llum de casa per web.
Control de un led per el mòbil.
Sistema de fitxers en ESP8266.
Altura del nivell d'aigua.
Avis d’alarma a Telegram.
Control de la intensitat de llum de un LED per Internet.
Magatzematge de temperatura i humitat en Thinger.
Publicar temperatura i humitat en Google Sheets.
ESP8266 i Firebase.
La bàscula. ESP8266 NodeMCU amb cèl·lula de càrrega.
ESP32-CAM
ESP32-CAM captura fotos per ser vistes en la WEB.
Pujar fotos a un servidor FTP amb ESP32-CAM.
MicroPython en ESP8266.
Visual Estudio Code per Arduino.
Classificador d’imatges.
Instal·lar i configurar Apache en Ubuntu.
Accés a un servidor Linux remotament.
Client i Servidor FTP.
Màquina virtual UBUNTU.
WindowsXP en Virtualbox.
Multisim, simulador de circuits electrònics.
Proteus, simulador de circuits electrònics.
MySQL. Instal·lació.
MySQL. Aplicacions.
Netbeans Maven MySQL.
Java+Netbeans+Maven+EclipseLink+Mysql
Aplicació d’escriptori JavaFX
App JavaFX amb SceneBuilder
App Java-Swing









Noves tecnologies WEB Arduino Domótica MycroPython NodeMCU IoT Java ESP8266 Lora C++ Programació Server-Client