La tecnología de comunicación de larga distancia ha revolucionado la forma en que monitoreamos y controlamos dispositivos en tiempo real. En este artículo, exploraremos cómo el sensor ESP32 LoRa puede ser monitoreado a través de un servidor web, permitiéndonos mantenernos conectados a nuestros datos incluso a largas distancias. ¡Descubre cómo esta innovadora tecnología está avanzando en el mundo de la comunicación remota!
En este proyecto, construirá un sistema de monitoreo de sensores utilizando una placa OLED TTGO LoRa32 SX1276 que envía valores de temperatura, humedad y presión a través de radio LoRa a un receptor ESP32 LoRa. El receptor muestra los últimos valores de los sensores en un servidor web.
Con este proyecto aprenderás a:
- Enviar valores de sensores vía radio LoRa entre dos tarjetas ESP32;
- Agregue capacidades LoRa y Wi-Fi a sus proyectos al mismo tiempo (servidor web LoRa + en la misma placa ESP32).
- Utilice la placa OLED TTGO LoRa32 SX1276 o placas de desarrollo similares para proyectos de IoT.
Recomendaciones de literatura: Placa OLED TTGO LoRa32 SX1276: Primeros pasos con Arduino IDE
Mira el vídeo de demostración
Mire la demostración en video para ver lo que creará en este tutorial.
Descripción del proyecto
La siguiente imagen muestra una descripción general de alto nivel del proyecto que crearemos en este tutorial.
- El transmisor LoRa envía los valores del sensor BME280 a través de radio LoRa cada 10 segundos;
- El receptor LoRa recibe los valores medidos y los muestra en un servidor web;
- Puede monitorear los valores del sensor accediendo al servidor web.
- El transmisor LoRa y el receptor Lora pueden estar separados por varios cientos de metros dependiendo de su ubicación. Entonces, con este proyecto puedes monitorear las lecturas de los sensores de tus campos o invernaderos cuando están a cierta distancia de tu casa.
- El receptor LoRa ejecuta un servidor web asíncrono y los archivos de la página web se almacenan en el sistema de archivos ESP32 (LittleFS).
- El receptor LoRa también muestra la fecha y hora de los últimos valores medidos. Para recuperar la fecha y la hora utilizamos el protocolo de tiempo de red con el ESP32.
Para una introducción a la comunicación LoRa: Qué es LoRa, frecuencias LoRa, aplicaciones LoRa y más, lea nuestra Introducción a ESP32 con LoRa usando el IDE de Arduino.
Piezas requeridas
Para este proyecto utilizamos los siguientes componentes:
- Placa OLED TTGO LoRa32 SX1276 (2x): Esta es una placa de desarrollo ESP32 con un chip LoRa y un OLED integrado. Puedes usar placas similares o usar un chip ESP32 + LoRa + OLED por separado.
- Sensor de temperatura, humedad y presión BME280. Debería poder modificar este proyecto para utilizar cualquier otro sensor.
También necesitarás algunos Cables de puente y un tablero de circuitos.
Puedes utilizar los enlaces anteriores o ir directamente MakerAdvisor.com/tools ¡Para encontrar todas las piezas para tus proyectos al mejor precio!
Preparando el IDE de Arduino
Para programar las placas OLED TTGO LoRa32 SX1276 utilizamos Arduino IDE. Para cargar archivos al sistema de archivos ESP32, utilizamos el complemento ESP32 LittleFS File System Uploader.
Antes de continuar, debe instalar las placas ESP32 y el complemento de carga del sistema de archivos ESP32. en su IDE de Arduino.
Instalación de bibliotecas
Este proyecto requiere que instales varias bibliotecas.
Bibliotecas LoRa, BME280 y OLED
Las siguientes bibliotecas se pueden instalar a través de Arduino Library Manager. Ir a Bosquejo > incluir biblioteca> Administrar bibliotecas y busque el nombre de la biblioteca.
- Biblioteca LoRa: Biblioteca Arduino LoRa de Sandeep Mistry
- Bibliotecas OLED: Biblioteca Adafruit_SSD1306 Y Biblioteca Adafruit_GFX
- Bibliotecas BME280: Biblioteca Adafruit_BME280 Y Biblioteca de sensores unificada de Adafruit
Bibliotecas de servidor web asíncrono
Para crear el servidor web asíncrono, también necesita instalar las siguientes bibliotecas:
- ESPAsyncWebServer Biblioteca (Descarga la biblioteca ESPAsyncWebServer)
- TCP asíncrono Biblioteca (Descargar la biblioteca AsyncTCP)
Estas bibliotecas no se pueden instalar a través del administrador de bibliotecas. Por lo tanto, debe descomprimir las bibliotecas y moverlas a la carpeta de bibliotecas de instalación del IDE de Arduino.
Alternativamente puedes Bosquejo > incluir biblioteca > Agregar biblioteca .ZIP… y seleccione las bibliotecas que acaba de descargar.
Biblioteca NTPClient
Cada vez que el receptor LoRa recibe un nuevo mensaje LoRa, solicita la fecha y hora a un servidor NTP para que sepamos cuándo se recibió el último paquete.
Eso es lo que usamos Biblioteca NTPClient bifurcada por TaranaisSiga los siguientes pasos para instalar esta biblioteca en su IDE de Arduino:
IMPORTANTE: No utilizamos la biblioteca NTPClient estándar. Para seguir este tutorial necesitas instalar la biblioteca. Recomendamos los siguientes pasos.
- Haga clic aquí para descargar la biblioteca del cliente NTP. Deberías tener una carpeta .zip en tu Descargas
- Vaya a su IDE de Arduino Bosquejo > incluir biblioteca > Agregar biblioteca ZIP…
- Seleccione el archivo ZIP de la biblioteca que acaba de descargar.
- La biblioteca se instalará después de unos segundos.
Transmisor LoRa
El transmisor LoRa está conectado a un sensor BME280 y envía valores de temperatura, humedad y presión cada 10 segundos. Puede cambiar este período más adelante en el código.
Recomendaciones de literatura: ESP32 con sensor BME280 usando Arduino IDE (Presión, Temperatura, Humedad)
Circuito transmisor LoRa
El BME280 que utilizamos se comunica con el ESP32 mediante el protocolo de comunicación I2C. Conecte el sensor como se muestra en el siguiente diagrama de cableado:
BME280 | ESP32 |
Número de chasis | 3,3 V |
Dimensiones | Dimensiones |
SCL | GPIO 13 |
ASD | GPIO21 |
Código de remitente LoRa
El siguiente código lee la temperatura, la humedad y la presión del sensor BME280 y envía las lecturas a través de radio LoRa.
Copie el siguiente código en su IDE de Arduino.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-lora-sensor-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
//Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Libraries for BME280
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6
//OLED pins
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
//BME280 definition
#define SDA 21
#define SCL 13
TwoWire I2Cone = TwoWire(1);
Adafruit_BME280 bme;
//packet counter
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);
//Initialize OLED display
void startOLED(){
//reset OLED display via software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//initialize OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.print("LORA SENDER");
}
//Initialize LoRa module
void startLoRA(){
//SPI LoRa pins
SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);
while (!LoRa.begin(BAND) && counter < 10) {
Serial.print(".");
counter++;
delay(500);
}
if (counter == 10) {
// Increment readingID on every new reading
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);
//Send LoRa packet to receiver
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() {
//initialize Serial Monitor
Serial.begin(115200);
startOLED();
startBME();
startLoRA();
}
void loop() {
getReadings();
sendReadings();
delay(10000);
}
Cómo funciona el código
Comience integrando las bibliotecas necesarias para LoRa, pantalla OLED y sensor BME280.
//Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Libraries for BME280
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
Defina los pines utilizados por el módulo transceptor LoRa. Usamos esos Placa OLED TTGO LoRa32 SX1276 V1.0 y estos son los pines que utiliza el chip LoRa:
//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
Nota: Si utiliza otra placa LoRa, verifique los pines utilizados por el chip transceptor LoRa.
Seleccione la frecuencia LoRa:
#define BAND 866E6
Defina los pines OLED.
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
Defina el tamaño de OLED.
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Defina los pines utilizados por el sensor BME280.
//BME280 definition
#define SDA 21
#define SCL 13
Cree una instancia I2C para el sensor BME280 y una bme Objeto.
TwoWire I2Cone = TwoWire(1);
Adafruit_BME280 bme;
Cree algunas variables para almacenar el mensaje LoRa, temperatura, humedad, presión e ID de lectura.
int readingID = 0;
int counter = 0;
String LoRaMessage = "";
float temperature = 0;
float humidity = 0;
float pressure = 0;
Crear un… Anuncio Objeto para la pantalla OLED.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
configuración()
En el configuración()Llamamos a varias funciones creadas previamente en el código para inicializar la pantalla OLED, el BME280 y el módulo transceptor LoRa.
void setup() {
Serial.begin(115200);
startOLED();
startBME();
startLoRA();
}
Cinta()
En el Cinta()Nosotros los llamamos obtener lecturas() Y enviar lecturas() Funciones que también se crearon previamente. Estas funciones se encargan de obtener lecturas del sensor BME280 y enviar estas lecturas vía LoRa.
void loop() {
getReadings();
sendReadings();
delay(10000);
}
obtener lecturas()
Recuperar los valores de los sensores es muy sencillo: leer temperatura(), leerhumedad()Y leer imprimir() métodos en el bme Objeto:
void getReadings(){
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100.0F;
}
enviar lecturas()
Para enviar las lecturas vía LoRa, concatenamos todas las lecturas en una sola variable. LoRaMensaje:
void sendReadings() {
LoRaMessage = String(readingID) + "/" + String(temperature) + "&" + String(humidity) + "#" + String(pressure);
Tenga en cuenta que cada lectura está separada por un carácter especial para que el destinatario pueda identificar fácilmente cada valor.
Luego envíe el paquete de la siguiente manera:
LoRa.beginPacket();
LoRa.print(LoRaMessage);
LoRa.endPacket();
Cada vez que enviamos un paquete LoRa incrementamos el Leer identificación Variable para que tengamos una idea de cuántos paquetes se enviaron. Puede eliminar esta variable si lo desea.
readingID++;
El Cinta() se repite cada 10000 milisegundos (10 segundos). Esto significa que se envían nuevos valores del sensor cada 10 segundos. Puede cambiar este tiempo de retraso si es necesario.
delay(10000);
Probando el transmisor LoRa
Sube el código a tu placa transmisora ESP32 LoRa.
Ir a Herramientas > Puerto y seleccione el puerto COM al que está conectado. Luego ve a Herramientas > tablón y selecciona la placa que estás utilizando. En nuestro caso se trata del TTGO LoRa32-OLED V1.
Finalmente, presione el botón cargar.
Abra el monitor serie con una velocidad de baudios de 115200. Debería obtener aproximadamente el resultado que se muestra a continuación.
La pantalla OLED de su placa debería mostrar las últimas lecturas del sensor.
Su transmisor LoRa está listo. Ahora pasemos al receptor LoRa.
receptor LoRa
El receptor LoRa recibe paquetes LoRa entrantes y muestra las mediciones recibidas en un servidor web asíncrono. Además de los valores del sensor, también mostramos la hora en que se recibieron por última vez estos valores y el RSSI (indicador de intensidad de la señal recibida).
La siguiente imagen muestra el servidor web que crearemos.
Como puedes ver, incluye una imagen de fondo y estilos para hacer más atractivo el sitio web. Hay varias formas de mostrar imágenes en un servidor web ESP32. Guardamos la imagen en el sistema de archivos ESP32 (LittleFS). También almacenamos el archivo HTML en LittleFS.
Organiza tus archivos
Para crear el servidor web necesitarás tres archivos diferentes: el boceto de Arduino, el archivo HTML y la imagen. El archivo HTML y la imagen deben estar en una carpeta llamada Datos en la carpeta de bocetos de Arduino como se muestra a continuación.
Creando el archivo HTML
Crea uno Pagina principal Archivo con el siguiente contenido o Descargue todos los archivos del proyecto aquí:
<!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 integramos los estilos CSS en el archivo HTML, así como algo de JavaScript que se encarga de actualizar automáticamente los valores del sensor.
Algo importante a tener en cuenta son los marcadores de posición. Los marcadores de posición están en el medio. % Firmar: % MARCA DE TIEMPO %, %TEMPERATURA%, %HUMEDAD%, %PRESIÓN% Y %RSSI%.
Estos marcadores de posición luego se reemplazan con los valores reales mediante el código Arduino.
Los estilos están entre los
<style>
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
header {
margin: 0;
padding-top: 10vh;
padding-bottom: 5vh;
overflow: hidden;
width: 100%;
background-image: url(winter.jpg);
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>
Si desea una imagen diferente para su fondo, solo necesita cambiar la siguiente línea para insertar el nombre de su imagen. En nuestro caso se llama invierno.jpg.
background-image: url(winter.jpg);
El JavaScript va entre el
<script>
setInterval(updateValues("temperature"), 5000);
setInterval(updateValues("humidity"), 5000);
setInterval(updateValues("pressure"), 5000);
setInterval(updateValues("rssi"), 5000);
setInterval(updateValues("timeAndDate"), 5000);
function updateValues(value) {
console.log(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>
No explicaremos en detalle cómo funcionan HTML y CSS, pero un buen lugar para aprender es aquí. Sitio web de W3Schools.
Boceto Arduino del receptor LoRa
Copie el siguiente código en su IDE de Arduino o Descargue todos los archivos del proyecto aquí. Luego deberás ingresar tus credenciales de red (SSID y contraseña) para que funcione.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-lora-sensor-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
// Import Wi-Fi library
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <LittleFS.h>
//Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Libraries to get time from NTP Server
#include <NTPClient.h>
#include <WiFiUdp.h>
//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6
//OLED pins
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String day;
String hour;
String timestamp;
// Initialize variables to get and save LoRa data
int rssi;
String loRaMessage;
String temperature;
String humidity;
String pressure;
String readingID;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
// Replaces placeholder with DHT values
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();
}
//Initialize OLED display
void startOLED(){
//reset OLED display via software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//initialize OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.print("LORA SENDER");
}
//Initialize LoRa module
void startLoRA(){
int counter;
//SPI LoRa pins
SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);
while (!LoRa.begin(BAND) && counter < 10) {
Serial.print(".");
counter++;
delay(500);
}
if (counter == 10) {
// Increment readingID on every new reading
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(){
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
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();
}
// Read LoRa packet and get the sensor readings
void getLoRaData() {
Serial.print("Lora packet received: ");
// Read packet
while (LoRa.available()) {
String LoRaData = LoRa.readString();
// LoRaData format: readingID/temperature&soilMoisture#batterylevel
// String example: 1/27.43&654#95.34
Serial.print(LoRaData);
// Get readingID, temperature and soil moisture
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());
}
// Get RSSI
rssi = LoRa.packetRssi();
Serial.print(" with RSSI ");
Serial.println(rssi);
}
// Function to get date and time from NTPClient
void getTimeStamp() {
while(!timeClient.update()) {
timeClient.forceUpdate();
}
// The formattedDate comes with the following format:
// 2018-05-28T16:00:13Z
// We need to extract date and time
formattedDate = timeClient.getFormattedDate();
Serial.println(formattedDate);
// Extract date
int splitT = formattedDate.indexOf("T");
day = formattedDate.substring(0, splitT);
Serial.println(day);
// Extract time
hour = formattedDate.substring(splitT+1, formattedDate.length()-1);
Serial.println(hour);
timestamp = day + " " + hour;
}
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
startOLED();
startLoRA();
connectWiFi();
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", String(), false, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", temperature.c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", humidity.c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", pressure.c_str());
});
server.on("/timestamp", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", timestamp.c_str());
});
server.on("/rssi", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(rssi).c_str());
});
server.on("/winter", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/winter.jpg", "image/jpg");
});
// Start server
server.begin();
// Initialize a NTPClient to get time
timeClient.begin();
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0
timeClient.setTimeOffset(0);
}
void loop() {
// Check if there are LoRa packets available
int packetSize = LoRa.parsePacket();
if (packetSize) {
getLoRaData();
getTimeStamp();
}
}
Cómo funciona el código
Empiece por integrar las bibliotecas necesarias. Necesita bibliotecas para:
- Cree el servidor web asíncrono.
- Acceda al sistema de archivos ESP32 (LittleFS);
- comunicarse con el chip LoRa;
- Controla la pantalla OLED;
- Recuperar fecha y hora de un servidor NTP.
// Import Wi-Fi library
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <LittleFS.h>
//Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Libraries to get time from NTP Server
#include <NTPClient.h>
#include <WiFiUdp.h>
Defina los pines utilizados por el módulo transceptor LoRa.
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
Nota: Si utiliza otra placa LoRa, verifique los pines utilizados por el chip transceptor LoRa.
Defina la frecuencia LoRa:
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6
Configurando los pines OLED:
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
En las siguientes variables, ingrese sus credenciales de red para permitir que el ESP32 se conecte a su red local.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Defina un cliente NTP para recuperar la fecha y la hora:
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
Cree variables para almacenar fecha y hora:
String formattedDate;
String day;
String hour;
String timestamp;
Variables adicionales para almacenar los valores del sensor recibidos vía radio LoRa.
int rssi;
String loRaMessage;
String temperature;
String humidity;
String pressure;
String readingID;
Crea uno Servidor web asíncrono Objeto nombrado servidor en el puerto 80.
AsyncWebServer server(80);
Crea un objeto llamado Anuncio para la pantalla OLED:
AsyncWebServer server(80);
Procesador()
El Procesador() La función asigna valores a los marcadores de posición que creamos en el archivo HTML.
Acepta el marcador de posición como argumento y debería devolver una cadena que reemplace ese marcador de posición.
Por ejemplo, si encuentra TEMPERATURA Marcador de posición, será el temperatura Variable de cadena.
// Replaces placeholder with DHT values
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();
}
configuración()
En el configuración()Inicialice la pantalla OLED, la comunicación LoRa y conéctese a WiFi.
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
startOLED();
startLoRA();
connectWiFi();
También inicialice LittleFS:
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
Servidor web asíncrono
Usando la biblioteca ESPAsyncWebServer podemos configurar las rutas en las que el servidor escucha las solicitudes HTTP entrantes.
Por ejemplo, cuando llega una solicitud para la URL de la ruta, la enviamos Pagina principal Archivo almacenado en ESP32 LittleFS:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", String(), false, processor);
});
Como se mencionó anteriormente, agregamos un poco de Javascript al archivo HTML, que es responsable de actualizar la página web cada 10 segundos. Cuando esto sucede, se envía una solicitud al /Temperatura, /Humedad, /Presión, /Marca de tiempo, /rssi URL.
Por eso tenemos que lidiar con lo que sucede cuando recibimos estas solicitudes. Sólo tenemos que temperatura, humedad, Presión, marca de tiempo Y RSS Variables. Las variables deben enviarse en formato char, por eso lo usamos .c_str() Método.
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", temperature.c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", humidity.c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", pressure.c_str());
});
server.on("/timestamp", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", timestamp.c_str());
});
server.on("/rssi", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(rssi).c_str());
});
Desde que insertamos una imagen en la página web, recibimos una solicitud solicitando la imagen. Entonces necesitamos enviar la imagen almacenada en el ESP32 LittleFS.
server.on("/winter", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/winter.jpg", "image/jpg");
});
Finalmente, inicie el servidor web.
server.begin();
cliente NTP
Todavía en configuración()cree un cliente NTP para obtener la hora de Internet.
timeClient.begin();
La hora se devuelve en formato GMT. Entonces, si necesitas ajustarlo a tu zona horaria, puedes usar:
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0
timeClient.setTimeOffset(0);
Cinta()
En el Cinta()escuchamos los paquetes LoRa entrantes:
int packetSize = LoRa.parsePacket();
Cuando haya un nuevo paquete LoRa disponible, los llamaremos obtenerLoRaData() Y obtener marca de hora() Características.
if (packetSize) {
getLoRaData();
getTimeStamp();
}
El obtenerLoRaData() La función recibe el mensaje LoRa y lo divide para obtener las diferentes lecturas.
El obtener marca de hora() La función recupera la hora y la fecha de Internet tan pronto como recibimos el paquete.
Subir código y archivos
Después de ingresar sus credenciales de red, guarde su boceto. Luego ve a tu IDE de Arduino Bosquejo > Mostrar carpeta de bocetosy crea una carpeta llamada Datos.
El archivo HTML y el archivo de imagen deben estar en esta carpeta.
Después de asegurarse de tener todos los archivos que necesita en los directorios correctos, debe cargar los archivos en el sistema de archivos ESP32 LittleFS.
Prensa[[Ctrl]+[[Shift]+[[P]bajo Windows o[[⌘]+[[Shift]+[[P]en MacOS para abrir la paleta de comandos. busca eso Sube LittleFS a Pico/ESP8266/ESP32 comando y haga clic en él.
Si no tienes esta opción es porque no tienes instalado el complemento File System Uploader. Mira este tutorial.
Importante: Asegúrese de que el monitor serie esté cerrado antes de cargarlo en el sistema de archivos. De lo contrario, la carga fallará.
Después de unos segundos, los archivos deberían cargarse correctamente en LittleFS.
Ahora sube el boceto a tu tablero.
Abra el monitor serie con una velocidad de baudios de 115200.
Debería obtener la dirección IP ESP32 y comenzar a recibir paquetes LoRa del remitente.
La dirección IP también debe mostrarse en la pantalla OLED.
demostración
Abra un navegador e ingrese su dirección IP ESP32. Debería ver el servidor web con las últimas lecturas del sensor.
Con estas placas pudimos lograr una comunicación LoRa estable hasta 180 metros (590 pies) en campo abierto. Esto significa que el transmisor y el receptor pueden estar a 180 metros de distancia y aún así poder acceder y comprobar los valores medidos en el servidor web.
Es realmente impresionante conseguir una comunicación estable a una distancia de 180 metros con placas tan económicas y sin necesidad de ajustes adicionales.
En un proyecto anterior con un Chip transceptor RFM95 SX1276 LoRa Con una antena de fabricación propia conseguimos mejores resultados: más de 250 metros con muchos obstáculos de por medio.
El rango de comunicación depende en gran medida de su entorno, la placa LoRa utilizada y muchas otras variables.
Envolver
Puede llevar este proyecto más allá y construir un sistema de monitoreo fuera de la red agregando paneles solares y sueño profundo a su transmisor LoRa. Los siguientes artículos pueden ayudarle:
- ESP32 Deep Sleep con Arduino IDE y fuentes de activación
- Operar ESP32 con módulos solares
- ESP32 con pantalla OLED SX1276 LoRa y SSD1306 integrada (informe de prueba)
También es posible que desees acceder a las lecturas de tus sensores desde cualquier lugar o mostrarlas en un gráfico:
- Visualiza los valores de tus sensores desde cualquier parte del mundo (ESP32 + MySQL + PHP)
- ESP32 traza los valores del sensor en gráficos en tiempo real – servidor web
Esperamos que este proyecto te haya resultado interesante. Si desea ver más proyectos que utilizan la radio LoRa, háganoslo saber en la sección de comentarios.
Gracias por leer.
Monitoreo de sensor ESP32 LoRa con servidor web
En este proyecto, construirás un sistema de monitoreo de sensores utilizando una placa TTGO LoRa32 SX1276 OLED que envía lecturas de temperatura, humedad y presión a través de radio LoRa a un receptor ESP32 LoRa. El receptor muestra las últimas lecturas de los sensores en un servidor web.
¿Qué aprenderás?
- Enviar lecturas de sensores a través de radio LoRa entre dos placas ESP32.
- Agregar capacidades LoRa y Wi-Fi simultáneamente a tus proyectos (LoRa + Servidor web en la misma placa ESP32).
- Utilizar la placa TTGO LoRa32 SX1276 OLED u otras placas de desarrollo similares para proyectos de IoT.
Partes requeridas
Para este proyecto, necesitarás los siguientes componentes:
- Placas TTGO LoRa32 SX1276 OLED (2x).
- Sensor de temperatura, humedad y presión BME280.
- Algunos cables jumper y una protoboard.
Preparación de Arduino IDE
Para programar las placas TTGO LoRa32 SX1276 OLED, necesitarás instalar las placas ESP32 y el plugin ESP32 filesystem uploader en tu Arduino IDE.
Para más detalle sobre los pasos de instalación y configuración, puedes consultar el tutorial completo.
Pruebas del LoRa Sender
- Carga el código del LoRa Sender a tu ESP32 LoRa Sender.
- Abre el Monitor Serie para verificar que la placa esté enviando las lecturas de los sensores.
- Observa las lecturas en tiempo real en la pantalla OLED de la placa TTGO.
Para ver el código completo y más detalles sobre las pruebas, visita el tutorial original.
LoRa Receiver
El LoRa Receiver recibe los paquetes LoRa entrantes y muestra las lecturas recibidas en un servidor web asíncrono.
Subir código y archivos
Después de insertar tus credenciales de red, guarda tu esquema. Luego, en tu Arduino IDE ve a Sketch > Mostrar carpeta de esquemas, y crea una carpeta llamada ‘data’.
Sube los archivos HTML e imagen a la carpeta ‘data’. Luego, sube los archivos al sistema de archivos LittleFS del ESP32.
Para más detalles sobre cómo cargar archivos en el ESP32 LittleFS, revisa este enlace.
¡Genial! Me parece fascinante cómo se puede usar el ESP32 LoRa para monitorear sensores a larga distancia. ¡Gracias por compartir esta información!
Wow, qué increíble la forma en que el ESP32 LoRa facilita el monitoreo remoto de sensores. ¡Definitivamente una herramienta poderosa en la tecnología! ¡Gracias por compartir estos avances!
Qué interesante propuesta, parece una forma muy práctica de monitorear sensores a larga distancia. ¡Gracias por la info!
¡Me encantó el artículo! Es sorprendente ver cómo la tecnología del ESP32 LoRa permite monitorear sensores de forma remota. Definitivamente una herramienta que facilita mucho el trabajo. ¡Gracias por compartir!
Interesante artículo, me encanta ver cómo la tecnología nos permite monitorear a distancia con el ESP32 LoRa. ¡Muy útil!