En este proyecto vas a construir un sistema de monitorización de sensores usando una placa TTGO LoRa32 SX1276 OLED que envía lecturas de temperatura, humedad y presión vía radio LoRa a un receptor ESP32 LoRa. El receptor muestra las últimas lecturas del sensor en un servidor web.
Con este proyecto aprenderás a: enviar lecturas de sensores vía radio LoRa entre dos placas ESP32, añadir capacidades de LoRa y Wi-Fi simultáneamente a tus proyectos (LoRa + servidor web en la misma placa ESP32) y usar la placa TTGO LoRa32 SX1276 OLED o placas similares para proyectos IoT.
Lectura recomendada: si es tu primer contacto con LoRa, te recomendamos leer antes la guía de introducción al TTGO LoRa32 SX1276 OLED con Arduino IDE.
Resumen del proyecto
El funcionamiento del proyecto es el siguiente:
El emisor LoRa envía lecturas del sensor BME280 vía radio LoRa cada 10 segundos. El receptor LoRa recibe las lecturas y las muestra en un servidor web. Puedes monitorizar las lecturas del sensor accediendo al servidor web. El emisor LoRa y el receptor LoRa pueden estar separados varios cientos de metros dependiendo de su ubicación. Así que puedes usar este proyecto para monitorizar sensores en tus campos o invernaderos si están un poco alejados de tu casa. El receptor LoRa ejecuta un servidor web asíncrono y los archivos de la página web se guardan en el sistema de archivos del ESP32 (LittleFS). El receptor LoRa también muestra la fecha y hora en que se recibieron las últimas lecturas. Para obtener la fecha y hora, usamos el protocolo NTP con el ESP32.
La combinación de LoRa + Wi-Fi en la misma placa abre un abanico enorme de posibilidades: el emisor puede estar a kilómetros de distancia en el campo, mientras que el receptor actúa como puente entre el mundo LoRa y el mundo internet, poniendo los datos a disposición de cualquier dispositivo conectado a tu red local.
Componentes necesarios
Para este proyecto usaremos los siguientes componentes: dos placas TTGO LoRa32 SX1276 OLED (cada una es una placa de desarrollo ESP32 con chip LoRa y OLED integrado), un sensor BME280 de temperatura, humedad y presión, cables jumper y una protoboard. También necesitarás una antena para cada placa LoRa.
Puedes modificar este proyecto para usar cualquier otro sensor.
Preparar Arduino IDE
Para programar las placas TTGO LoRa32 SX1276 OLED usaremos Arduino IDE. Para subir archivos al sistema de archivos del ESP32, usaremos el plugin ESP32 LittleFS filesystem uploader.
Así que antes de continuar, necesitas instalar las placas ESP32 y el plugin del sistema de archivos en tu Arduino IDE.
Instalar las librerías necesarias
Para este proyecto, necesitas instalar varias librerías:
Librerías LoRa, BME280, OLED y servidor web: la librería arduino-LoRa de Sandeep Mistry, las librerías Adafruit_SSD1306 y Adafruit_GFX para el OLED, las librerías Adafruit_BME280 y Adafruit Unified Sensor para el BME280, y las librerías ESPAsyncWebServer (by ESP32Async) y AsyncTCP (by ESP32Async) para el servidor web.
Todas estas se pueden instalar a través del Gestor de Librerías de Arduino. Ve a Programa > Incluir Librería > Gestionar Librerías y busca el nombre de cada librería.
Librería NTPClient
Cada vez que el receptor LoRa capta un nuevo mensaje LoRa, solicitará la fecha y hora de un servidor NTP para que sepamos cuándo se recibió el último paquete. Para eso usaremos la libería NTPClient bifurcada por Taranais.
Importante: NO estamos usando la librería NTPClient por defecto. Para seguir este tutorial necesitas instalar la librería que recomendamos usando los siguientes pasos:
Descarga la librería NTP Client. Deberías tener un archivo
.zipen tu carpeta de Descargas. En tu Arduino IDE, ve a Programa > Incluir Librería > Añadir librería .ZIP…. Selecciona el archivo.ZIPde la librería que acabas de descargar. La librería se instalará después de unos segundos.
Emisor LoRa
El emisor LoRa está conectado a un sensor BME280 y envía lecturas de temperatura, humedad y presión cada 10 segundos. Puedes cambiar este periodo de tiempo más tarde en el código.
Circuito del emisor LoRa
El BME280 que estamos usando se comunica con el ESP32 usando protocolo de comunicación I2C. Cablea el sensor según el siguiente esquema:
VIN del BME280 a 3,3 V del ESP32. GND del BME280 a GND del ESP32. SCL del BME280 a GPIO 13. SDA del BME280 a GPIO 21.
Código del emisor LoRa
El siguiente código lee temperatura, humedad y presión del sensor BME280 y envía las lecturas vía radio LoRa. Copia el siguiente código en tu Arduino IDE:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Detalles completos del proyecto en https://RandomNerdTutorials.com/esp32-lora-sensor-web-server/
*/
//Librerías para LoRa
#include <SPI.h>
#include <LoRa.h>
//Librerías para la pantalla OLED
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Librerías para el BME280
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
//define los pines usados por el módulo transceptor LoRa
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 para Asia
//866E6 para Europa
//915E6 para Norteamérica
#define BAND 866E6
//Pines de la OLED
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128 // Ancho de la pantalla OLED, en píxeles
#define SCREEN_HEIGHT 64 // Alto de la pantalla OLED, en píxeles
//Definición del BME280
#define SDA 21
#define SCL 13
TwoWire I2Cone = TwoWire(1);
Adafruit_BME280 bme;
//Contador de paquetes
int readingID = 0;
int counter = 0;
String LoRaMessage = "";
float temperature = 0;
float humidity = 0;
float pressure = 0;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
//Inicia la pantalla OLED
void startOLED(){
//reset de la pantalla OLED por software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//inicia la OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Dirección 0x3C para 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // No continuar, bucle infinito
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.print("LORA SENDER");
}
//Inicia el módulo LoRa
void startLoRA(){
//Pines SPI LoRa
SPI.begin(SCK, MISO, MOSI, SS);
//configura el módulo transceptor LoRa
LoRa.setPins(SS, RST, DIO0);
while (!LoRa.begin(BAND) && counter < 10) {
Serial.print(".");
counter++;
delay(500);
}
if (counter == 10) {
// Incrementa readingID en cada nueva lectura
readingID++;
Serial.println("Starting LoRa failed!");
}
Serial.println("LoRa Initialization OK!");
display.setCursor(0,10);
display.clearDisplay();
display.print("LoRa Initializing OK!");
display.display();
delay(2000);
}
void startBME(){
I2Cone.begin(SDA, SCL, 100000);
bool status1 = bme.begin(0x76, &I2Cone);
if (!status1) {
Serial.println("Could not find a valid BME280_1 sensor, check wiring!");
while (1);
}
}
void getReadings(){
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100.0F;
}
void sendReadings() {
LoRaMessage = String(readingID) + "/" + String(temperature) + "&" + String(humidity) + "#" + String(pressure);
//Envía el paquete LoRa al receptor
LoRa.beginPacket();
LoRa.print(LoRaMessage);
LoRa.endPacket();
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.print("LoRa packet sent!");
display.setCursor(0,20);
display.print("Temperature:");
display.setCursor(72,20);
display.print(temperature);
display.setCursor(0,30);
display.print("Humidity:");
display.setCursor(54,30);
display.print(humidity);
display.setCursor(0,40);
display.print("Pressure:");
display.setCursor(54,40);
display.print(pressure);
display.setCursor(0,50);
display.print("Reading ID:");
display.setCursor(66,50);
display.print(readingID);
display.display();
Serial.print("Sending packet: ");
Serial.println(readingID);
readingID++;
}
void setup() {
//inicia el Monitor Serie
Serial.begin(115200);
startOLED();
startBME();
startLoRA();
}
void loop() {
getReadings();
sendReadings();
delay(10000);
}
Cómo funciona el código del emisor paso a paso
Empieza incluyendo las librerías necesarias para LoRa, pantalla OLED y sensor BME280.
Se definen los pines usados por el módulo transceptor LoRa. Estamos usando la placa TTGO LoRa32 SX1266 OLED V1.0 y estos son los pines usados por el chip LoRa. Si estás usando otra placa LoRa, comprueba los pines usados por el chip transceptor LoRa.
Se selecciona la frecuencia LoRa: 866E6 para Europa, 433E6 para Asia o 915E6 para Norteamérica. Se definen los pines de la OLED. Se define el tamaño de la OLED (128 x 64 píxeles). Se definen los pines usados por el sensor BME280.
Se crea una instancia I2C para el sensor BME280 y un objeto bme. Se crean algunas variables para almacenar el mensaje LoRa, temperatura, humedad, presión y el ID de lectura. Se crea un objeto display para la pantalla OLED.
La función setup()
En el setup(), llamamos a varias funciones que fueron creadas antes en el código para inicializar la pantalla OLED, el BME280 y el módulo transceptor LoRa.
La función loop()
En el loop(), llamamos a las funciones getReadings() y sendReadings(). Estas funciones son responsables de obtener lecturas del sensor BME280 y enviar esas lecturas vía LoRa, respectivamente.
La función getReadings()
Obtener lecturas del sensor es tan simple como usar los métodos readTemperature(), readHumidity() y readPressure() en el objeto bme.
La función sendReadings()
Para enviar las lecturas vía LoRa, concatenamos todas las lecturas en una única variable LoRaMessage. Fíjate en que cada lectura está separada por un carácter especial, para que el receptor pueda identificar fácilmente cada valor. Después, se envía el paquete usando LoRa.beginPacket(), LoRa.print() y LoRa.endPacket().
Cada vez que enviamos un paquete LoRa, incrementamos la variable readingID para que tengamos una idea de cuántos paquetes se enviaron. Puedes borrar esta variable si quieres. El loop() se repite cada 10000 milisegundos (10 segundos), así que se envían nuevas lecturas del sensor cada 10 segundos.
Probar el emisor LoRa
Sube el código a tu placa emisora ESP32 LoRa. Ve a Herramientas > Puerto y selecciona el puerto COM al que está conectada. Después, ve a Herramientas > Placa y selecciona la placa que estás usando. En nuestro caso, es la TTGO LoRa32-OLED V1. Finalmente, pulsa el botón de subir.
Abre el Monitor Serie a 115200 baudios. Deberías obtener algo similar a lo descrito. La OLED de tu placa debería estar mostrando las últimas lecturas del sensor. Tu emisor LoRa está listo.
Receptor LoRa
El receptor LoRa recibe los paquetes LoRa entrantes y muestra las lecturas recibidas en un servidor web asíncrono. Además de las lecturas del sensor, también mostramos la última vez que se recibieron esas lecturas y el RSSI (indicador de intensidad de señal recibida).
La página web contiene una imagen de fondo y estilos para hacer la página más atractiva. Hay varias formas de mostrar imágenes en un servidor web del ESP32. Guardaremos la imagen en el sistema de archivos del ESP32 (LittleFS). También guardaremos el archivo HTML en LittleFS.
Organizar tus archivos
Para construir el servidor web necesitas tres archivos diferentes: el sketch de Arduino, el archivo HTML y la imagen. El archivo HTML y la imagen deberían guardarse dentro de una carpeta llamada data dentro de la carpeta del sketch de Arduino.
Crear el archivo HTML
Crea un archivo index.html con el siguiente contenido:
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<title>ESP32 (LoRa + Server)</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
header {
margin: 0;
padding-top: 5vh;
padding-bottom: 5vh;
overflow: hidden;
background-image: url(winter);
background-size: cover;
color: white;
}
h2 {
font-size: 2.0rem;
}
p { font-size: 1.2rem; }
.units { font-size: 1.2rem; }
.readings { font-size: 2.0rem; }
</style>
</head>
<body>
<header>
<h2>ESP32 (LoRa + Server)</h2>
<p><strong>Last received packet:<br/><span id="timestamp">%TIMESTAMP%</span></strong></p>
<p>LoRa RSSI: <span id="rssi">%RSSI%</span></p>
</header>
<main>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i> Temperature: <span id="temperature" class="readings">%TEMPERATURE%</span>
<sup>°C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i> Humidity: <span id="humidity" class="readings">%HUMIDITY%</span>
<sup>%</sup>
</p>
<p>
<i class="fas fa-angle-double-down" style="color:#e8c14d;"></i> Pressure: <span id="pressure" class="readings">%PRESSURE%</span>
<sup>hpa</sup>
</p>
</main>
<script>
setInterval(updateValues, 10000, "temperature");
setInterval(updateValues, 10000, "humidity");
setInterval(updateValues, 10000, "pressure");
setInterval(updateValues, 10000, "rssi");
setInterval(updateValues, 10000, "timestamp");
function updateValues(value) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById(value).innerHTML = this.responseText;
}
};
xhttp.open("GET", "/" + value, true);
xhttp.send();
}
</script>
</body>
</html>
También hemos incluido los estilos CSS en el archivo HTML, así como algo de JavaScript que es responsable de actualizar las lecturas del sensor automáticamente.
Algo importante a tener en cuenta son los placeholders. Los placeholders van entre signos %: %TIMESTAMP%, %TEMPERATURE%, %HUMIDITY%, %PRESSURE% y %RSSI%. Estos placeholders serán reemplazados por los valores reales por el código de Arduino.
Los estilos se añaden entre las etiquetas <style> y </style>. La imagen de fondo se especifica con background-image: url(winter.jpg). Si quieres una imagen diferente para tu fondo, solo necesitas modificar esa línea para incluir el nombre de tu imagen.
El JavaScript va entre las etiquetas <script> y </script>. No explicaremos en detalle cómo funciona el HTML y CSS, pero un buen lugar para aprender es la web de W3Schools.
Sketch de Arduino del receptor LoRa
Copia el siguiente código en tu Arduino IDE. Después, necesitas escribir tus credenciales de red (SSID y contraseña) para que funcione:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Detalles completos del proyecto en https://RandomNerdTutorials.com/esp32-lora-sensor-web-server/
*/
// Importa la librería Wi-Fi
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <LittleFS.h>
//Librerías para LoRa
#include <SPI.h>
#include <LoRa.h>
//Librerías para la pantalla OLED
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Librerías para obtener la hora de un servidor NTP
#include <NTPClient.h>
#include <WiFiUdp.h>
//define los pines usados por el módulo transceptor LoRa
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 para Asia
//866E6 para Europa
//915E6 para Norteamérica
#define BAND 866E6
//Pines de la OLED
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128 // Ancho de la pantalla OLED, en píxeles
#define SCREEN_HEIGHT 64 // Alto de la pantalla OLED, en píxeles
// Reemplaza con las credenciales de tu red
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Define el cliente NTP para obtener la hora
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables para guardar la fecha y la hora
String formattedDate;
String day;
String hour;
String timestamp;
// Inicializa variables para obtener y guardar los datos LoRa
int rssi;
String loRaMessage;
String temperature;
String humidity;
String pressure;
String readingID;
// Crea el objeto AsyncWebServer en el puerto 80
AsyncWebServer server(80);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
// Reemplaza el placeholder con los valores del sensor
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return temperature;
}
else if(var == "HUMIDITY"){
return humidity;
}
else if(var == "PRESSURE"){
return pressure;
}
else if(var == "TIMESTAMP"){
return timestamp;
}
else if (var == "RRSI"){
return String(rssi);
}
return String();
}
//Inicia la pantalla OLED
void startOLED(){
//reset de la pantalla OLED por software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//inicia la OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Dirección 0x3C para 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // No continuar, bucle infinito
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.print("LORA SENDER");
}
//Inicia el módulo LoRa
void startLoRA(){
int counter;
//Pines SPI LoRa
SPI.begin(SCK, MISO, MOSI, SS);
//configura el módulo transceptor LoRa
LoRa.setPins(SS, RST, DIO0);
while (!LoRa.begin(BAND) && counter < 10) {
Serial.print(".");
counter++;
delay(500);
}
if (counter == 10) {
// Incrementa readingID en cada nueva lectura
Serial.println("Starting LoRa failed!");
}
Serial.println("LoRa Initialization OK!");
display.setCursor(0,10);
display.clearDisplay();
display.print("LoRa Initializing OK!");
display.display();
delay(2000);
}
void connectWiFi(){
// Conecta a la red Wi-Fi con SSID y contraseña
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Imprime la dirección IP local e inicia el servidor web
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
display.setCursor(0,20);
display.print("Access web server at: ");
display.setCursor(0,30);
display.print(WiFi.localIP());
display.display();
}
// Lee el paquete LoRa y obtiene las lecturas del sensor
void getLoRaData() {
Serial.print("Lora packet received: ");
// Lee el paquete
while (LoRa.available()) {
String LoRaData = LoRa.readString();
// Formato de LoRaData: readingID/temperature&humidity#pressure
// Ejemplo de String: 1/27.43&65.4#95.34
Serial.print(LoRaData);
// Obtiene readingID, temperatura y humedad
int pos1 = LoRaData.indexOf('/');
int pos2 = LoRaData.indexOf('&');
int pos3 = LoRaData.indexOf('#');
readingID = LoRaData.substring(0, pos1);
temperature = LoRaData.substring(pos1 +1, pos2);
humidity = LoRaData.substring(pos2+1, pos3);
pressure = LoRaData.substring(pos3+1, LoRaData.length());
}
// Obtiene el RSSI
rssi = LoRa.packetRssi();
Serial.print(" with RSSI ");
Serial.println(rssi);
}
// Función para obtener la fecha y hora del NTPClient
void getTimeStamp() {
while(!timeClient.update()) {
timeClient.forceUpdate();
}
// formattedDate viene con el siguiente formato:
// 2018-05-28T16:00:13Z
// Necesitamos extraer la fecha y la hora
formattedDate = timeClient.getFormattedDate();
Serial.println(formattedDate);
// Extrae la fecha
int splitT = formattedDate.indexOf("T");
day = formattedDate.substring(0, splitT);
Serial.println(day);
// Extrae la hora
hour = formattedDate.substring(splitT+1, formattedDate.length()-1);
Serial.println(hour);
timestamp = day + " " + hour;
}
void setup() {
// Inicia el Monitor Serie
Serial.begin(115200);
startOLED();
startLoRA();
connectWiFi();
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
// Ruta para la raíz / página web
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", String(), false, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", temperature.c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", humidity.c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", pressure.c_str());
});
server.on("/timestamp", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", timestamp.c_str());
});
server.on("/rssi", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", String(rssi).c_str());
});
server.on("/winter", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/winter.jpg", "image/jpg");
});
// Inicia el servidor
server.begin();
// Inicia un NTPClient para obtener la hora
timeClient.begin();
// Establece el offset de tiempo en segundos para ajustar a tu zona horaria, por ejemplo:
// GMT +1 = 3600
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0
timeClient.setTimeOffset(0);
}
void loop() {
// Comprueba si hay paquetes LoRa disponibles
int packetSize = LoRa.parsePacket();
if (packetSize) {
getLoRaData();
getTimeStamp();
}
}
Cómo funciona el código del receptor paso a paso
Empieza incluyendo las librerías necesarias. Necesitas librerías para: construir el servidor web asíncrono, acceder al sistema de archivos del ESP32 (LittleFS), comunicarte con el chip LoRa, controlar la pantalla OLED y obtener fecha y hora de un servidor NTP.
Se definen los pines usados por el módulo transceptor LoRa. Si estás usando otra placa LoRa, comprueba los pines usados por el chip transceptor LoRa. Se define la frecuencia LoRa. Se configuran los pines de la OLED.
Se introducen las credenciales de red en las variables correspondientes para que el ESP32 pueda conectarse a tu red local.
Se define un cliente NTP para obtener fecha y hora. Se crean variables para guardar la fecha y la hora. Se crean más variables para almacenar las lecturas del sensor recibidas vía radio LoRa. Se crea un objeto AsyncWebServer llamado server en el puerto 80. Se crea un objeto display para la pantalla OLED.
La función processor()
La función processor() es lo que asignará valores a los placeholders que hemos creado en el archivo HTML. Acepta como argumento el placeholder y debería devolver un String que reemplazará ese placeholder. Por ejemplo, si encuentra el placeholder TEMPERATURE, devolverá la variable String temperature.
La función setup()
En el setup(), se inicializa la pantalla OLED, la comunicación LoRa y se conecta a Wi-Fi. También se inicializa LittleFS.
Async Web Server
La libería ESPAsyncWebServer nos permite configurar las rutas donde el servidor estará escuchando peticiones HTTP entrantes. Por ejemplo, cuando se recibe una petición en la ruta /, enviamos el archivo index.html que está guardado en el LittleFS del ESP32.
Como mencionamos antes, añadimos un poco de JavaScript al archivo HTML que es responsable de actualizar la página web cada 10 segundos. Cuando eso ocurre, hace una petición en las URLs /temperature, /humidity, /pressure, /timestamp, /rssi. Así que necesitamos manejar qué ocurre cuando recibimos esas peticiones. Simplemente necesitamos enviar las variables de temperatura, humedad, presión, timestamp y rssi. Las variables deberían enviarse en formato char, por eso usamos el método .c_str().
Como incluimos una imagen en la página web, recibiremos una petición “pidiendo” la imagen. Así que necesitamos enviar la imagen que está guardada en el LittleFS del ESP32. Finalmente, se inicia el servidor web.
NTPClient
Aún en el setup(), se crea un cliente NTP para obtener la hora de internet. La hora se devuelve en formato GMT, así que si necesitas ajustarla a tu zona horaria, puedes usar el método setTimeOffset().
La función loop()
En el loop(), escuchamos paquetes LoRa entrantes. Si hay un nuevo paquete LoRa disponible, llamamos a las funciones getLoRaData() y getTimeStamp(). La función getLoRaData() recibe el mensaje LoRa y lo divide para obtener las diferentes lecturas. La función getTimeStamp() obtiene la hora y fecha de internet en el momento en que recibimos el paquete.
Subir el código y los archivos
Después de insertar tus credenciales de red, guarda tu sketch. Después, en tu Arduino IDE ve a Programa > Mostrar carpeta del sketch, y crea una carpeta llamada data. Dentro de esa carpeta, deberías tener el archivo HTML y el archivo de imagen.
Después de asegurarte de que tienes todos los archivos necesarios en los directorios correctos, necesitas subir los archivos al sistema de archivos LittleFS del ESP32. Pulsa [Ctrl] + [Shift] + [P] en Windows o [⌘] + [Shift] + [P] en macOS para abrir la paleta de comandos. Busca el comando Upload LittleFS to Pico/ESP8266/ESP32 y púlsalo.
Si no tienes esta opción, es porque no instalaste el plugin de carga de sistema de archivos.
Importante: asegúrate de que el Monitor Serie esté cerrado antes de subir al sistema de archivos. De lo contrario, la subida fallará.
Después de unos segundos, los archivos deberían subirse con éxito a LittleFS. Ahora, sube el sketch a tu placa. Abre el Monitor Serie a 115200 baudios. Deberías obtener la dirección IP del ESP32, y deberías empezar a recibir paquetes LoRa del emisor. También deberías obtener la dirección IP mostrada en la OLED.
Demostración
Abre un navegador y escribe la dirección IP del ESP32. Deberías ver el servidor web con las últimas lecturas del sensor.
Con estas placas pudimos conseguir una comunicación LoRa estable de hasta 180 metros (590 pies) en campo abierto. Esto significa que podemos tener el emisor y el receptor a 180 metros de distancia y seguir siendo capaces de obtener y comprobar las lecturas en el servidor web.
Obtener una comunicación estable a una distancia de 180 metros con placas de tan bajo coste y sin ninguna personalización adicional es realmente impresionante. Sin embargo, en un proyecto anterior usando un chip transceptor LoRa RFM95 SX1276 con una antena casera, obtuvimos mejores resultados: más de 250 metros con muchos obstáculos en medio. El rango de comunicación realmente dependerá de tu entorno, la placa LoRa que estés usando y muchas otras variables.
Conclusión: lo que has aprendido
Puedes llevar este proyecto más lejos y construir un sistema de monitorización fuera de la red añadiendo paneles solares y deep sleep a tu emisor LoRa. Los siguientes artículos podrían ayudarte a hacerlo: Deep Sleep en el ESP32 con Arduino IDE y fuentes de despertar y Alimentar el ESP32 con paneles solares.
Este proyecto es la combinación perfecta de dos tecnologías complementarias: LoRa para el largo alcance y bajo consumo y Wi-Fi para la conectividad a internet y la interfaz web. Mientras que LoRa cubre los kilómetros de distancia entre el sensor y tu casa, el Wi-Fi del receptor te permite consultar los datos desde cualquier dispositivo de tu red local, creando un sistema completo de telemetría con una arquitectura elegante y eficiente.
La arquitectura emisor + receptor + servidor web es directamente reutilizable en decenas de escenarios: monitorización agrícola en campos remotos, control de sensores en naves industriales, seguimiento de estaciones meteorológicas en montaña, o cualquier aplicación donde los sensores estén lejos de la infraestructura de red. Añade paneles solares y deep sleep, y tendrás un sistema autónomo que funciona durante meses sin intervención humana.
LoRa es la tecnología que finalmente hace viable el IoT rural y agrícola, y combinada con la potencia del ESP32 y la comodidad de un servidor web, te da un sistema de monitorización profesional con un coste total de hardware de menos de 50 euros. Las posibilidades son enormes.
Descubre más desde CIBERED
Suscríbete y recibe las últimas entradas en tu correo electrónico.
