Aprende a construir una estación meteorológica con un ESP32 que muestra información meteorológica local o de internet en una pantalla e-Paper.
En este tutorial aprenderás a construir una estación meteorológica alimentada por batería que utiliza el modo deep-sleep del ESP32 y una pantalla e-Paper para un tiempo de funcionamiento prolongado. De hecho, vamos a construir dos versiones. Una versión muestra la temperatura ambiente, humedad y presión atmosférica recogidas mediante un sensor BME280. La otra versión lee datos meteorológicos de internet usando OpenWeather y utiliza el ESP32-e-Paper-Weather-Display software para mostrarlos.
¡Vamos a empezar!
Partes necesarias
Para este proyecto, estoy usando una placa ESP32 antigua (ESP32 lite), que ha sido descontinuada pero aún puedes conseguirla. Es la que aparece listada a continuación. Hay un modelo sucesor (Amazon) con especificaciones mejoradas. Y la placa por defecto que usa la biblioteca ESP32-e-Paper-Weather-Display es una LOLIN D32, que tiene un monitor integrado de voltaje de batería.
Pero cualquier otro ESP32, ESP8266 o Arduino (con WiFi) también funcionará. Preferiblemente, sin embargo, querrás una placa de desarrollo con capacidades de carga de batería y bajo consumo en deep-sleep, como las placas ESP32 mencionadas arriba.

Pantalla e-Paper de 2.9″

ESP32 lite

Sensor BME280

Cable de datos USB

Juego de cables Dupont

Protoboard
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Pantalla e-Paper
Una breve explicación sobre la pantalla e-Paper que vamos a usar para nuestra estación meteorológica. Las pantallas e-Paper, también llamadas pantallas e-Ink, tienen la ventaja de consumir muy poca energía. De hecho, solo se necesita energía para actualizar la pantalla. Una vez actualizada, el contenido mostrado permanece prácticamente para siempre sin consumir energía alguna.

Otra ventaja de una pantalla e-Paper es que tienen ángulos de visión fantásticos (>170 grados) y son fáciles de leer incluso bajo la luz solar.
Las desventajas son el tiempo lento de actualización, la gama limitada de colores y que no tienen retroiluminación; por lo que no se pueden leer en la oscuridad.
Normalmente, una pantalla e-Paper tarda 2 segundos en actualizarse, aunque puedes hacer actualizaciones parciales de secciones que son mucho más rápidas (0.3 segundos). Esto es para pantallas en blanco y negro. Las pantallas a color son mucho, mucho más lentas en refrescar (> 20 segundos), tienen pocos colores y son mucho más caras.
Pero para una estación meteorológica alimentada por batería que actualiza sus datos solo cada pocos minutos, las pantallas e-Paper son una excelente opción y además tienen muy buen aspecto.
Módulo de pantalla e-Paper de 2.9″
Para este proyecto, estoy usando específicamente un módulo de pantalla e-Paper de 2.9″, con resolución de 296×128 píxeles y un controlador integrado con interfaz SPI.

Ten en cuenta que la mayoría de los módulos de pantalla e-Paper con SPI tienen un pequeño interruptor o jumper que permite cambiar de SPI de 4 cables a SPI de 3 cables. Aquí usaremos el SPI de 4 cables por defecto.
El módulo de pantalla funciona a 3.3V o 5V, tiene un consumo en modo sleep súper bajo de 0.01µA y consume solo unos 26.4mW mientras actualiza su contenido. Esto significa que puedes usar una pantalla e-Paper durante mucho tiempo incluso con una batería pequeña.
Para más información sobre pantallas e-Paper, echa un vistazo a nuestro tutorial Interfacing Arduino To An E-ink Display.
Sensor BME280
Para nuestra estación meteorológica también queremos medir algunos datos ambientales, como temperatura, humedad y presión atmosférica. Voy a usar un BME280 sensor aquí. La razón principal es que también tiene un modo de bajo consumo, sleep, donde consume solo 0.1µA (3.6 μA en modo normal).
En combinación con una pantalla e-Paper y el ESP32-lite con un consumo en deep-sleep de 5.65mA (a 5V), esto crea un sistema de muy bajo consumo que puede funcionar mucho tiempo con batería.
El sensor BME280 es pequeño y normalmente viene en una placa breakout con interfaz I2C; mira la imagen abajo.

La interfaz I2C facilita mucho la conexión y uso. El sensor puede medir presión de 300 hPa a 1100 hPa, temperatura de -40°C a +85°C, y humedad de 0% a 100%. Para más información sobre el BME280 lee nuestro tutorial sobre How To Use BME280 Pressure Sensor With Arduino.
Conexión y prueba de la pantalla e-Paper
Antes de intentar algo avanzado, conectemos y probemos la función de la pantalla e-Paper. La siguiente imagen muestra el cableado completo para alimentación y SPI.

Y aquí está la tabla con todas las conexiones. Ten en cuenta que puedes alimentar la pantalla con 3.3V o 5V, pero el ESP32-lite solo tiene salida de 3.3V y las líneas de datos SPI deben ser de 3.3V.
| Pantalla e-Paper | ESP32 lite |
|---|---|
| CS/SS | 5 |
| SCL/SCK | 18 |
| SDA/DIN/MOSI | 23 |
| BUSY | 15 |
| RES/RST | 2 |
| DC | 0 |
| VCC | 3.3V |
| GND | G |
Instalar la biblioteca GxEPD2
Antes de poder usar la pantalla e-Paper necesitamos instalar dos bibliotecas. La biblioteca Adafruit_GFX es una biblioteca gráfica base que proporciona un conjunto común de primitivas gráficas (texto, puntos, líneas, círculos, etc.). Y la biblioteca GxEPD2 proporciona el software controlador gráfico para controlar una pantalla e-Paper vía SPI.
Solo instala las bibliotecas de la forma habitual. Después de la instalación deberías verlas en el Library Manager así.

Código de prueba
Aquí tienes un código de prueba simple que muestra el texto «Hello Makers!» en la pantalla. Mira el código completo primero y luego discutimos algunos detalles.
#define ENABLE_GxEPD2_GFX 0
#include "GxEPD2_BW.h"
#include "Fonts/FreeMonoBold9pt7b.h"
//CS(SS)=5, SCL(SCK)=18, SDA(MOSI)=23, BUSY=15, RES(RST)=2, DC=0
GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> epd(GxEPD2_290_BS(5, 0, 2, 15));
void initDisplay() {
epd.init(115200, true, 50, false);
epd.setRotation(1);
epd.setFont(&FreeMonoBold9pt7b);
epd.setTextColor(GxEPD_BLACK);
epd.setFullWindow();
epd.fillScreen(GxEPD_WHITE);
}
void displayText() {
epd.setCursor(20, 20);
epd.print("Hello");
epd.setCursor(20, 40);
epd.print("Makers!");
}
void setup() {
initDisplay();
displayText();
epd.display();
epd.hibernate();
}
void loop() {
}
Vamos a desglosar el código en sus componentes para entender cómo funciona.
Constantes y bibliotecas
El código comienza definiendo una constante ENABLE_GxEPD2_GFX como 0. Puedes ponerla a 1, lo que según el documento permite que la clase base GxEPD2_GFX pase referencias o punteros a la instancia de la pantalla como parámetro. Pero usa ~1.2k más de código y no lo necesitamos, así que se deja en 0.
#define ENABLE_GxEPD2_GFX 0
Luego incluimos el archivo de cabecera GxEPD2_BW.h para una pantalla e-Paper en blanco y negro (BW) y la fuente que vamos a usar. Si tienes una pantalla de 3 colores tendrías que incluir GxEPD2_3C.h, o GxEPD2_4C.h para una pantalla de 4 colores, y GxEPD2_7C.h para una pantalla de 7 colores, en su lugar.
#include "GxEPD2_BW.h" #include "Fonts/FreeMonoBold9pt7b.h"
La biblioteca Adafruit_GFX incluye muchas fuentes diferentes y las puedes encontrar en la carpeta de la biblioteca bajo {application_path}\Arduino\libraries\Adafruit_GFX_Library\Fonts.
Objeto de pantalla
La siguiente línea es importante. Crea el objeto de pantalla y depende del tipo o marca de pantalla. Probé una WeAct y una WaveShare y la siguiente línea funciona para ambas.
GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> epd(GxEPD2_290_BS(5, 0, 2, 15));
El Readme para la biblioteca GxEPD2 lista una gran cantidad de pantallas soportadas y puedes encontrar los detalles en los archivos de cabecera, por ejemplo GxEPD2.h.
Inicialización de la pantalla
La función initDisplay() es responsable de inicializar la pantalla e-Paper. Configura parámetros como velocidad de comunicación, rotación, fuente, color de texto y color de fondo. Si tienes problemas con la actualización de la pantalla, puede que tengas que ajustar el parámetro para la función init().
void initDisplay() {
epd.init(115200, true, 50, false);
epd.setRotation(1);
epd.setFont(&FreeMonoBold9pt7b);
epd.setTextColor(GxEPD_BLACK);
epd.setFullWindow();
epd.fillScreen(GxEPD_WHITE);
}
Mostrar texto
La función displayText() posiciona el cursor en la pantalla e imprime el texto «Hello» y «Makers!» en coordenadas específicas.
void displayText() {
epd.setCursor(20, 20);
epd.print("Hello");
epd.setCursor(20, 40);
epd.print("Makers!");
}
Función setup
En la función setup(), la pantalla se inicializa usando initDisplay(), se muestra texto con displayText(), y luego el contenido se muestra en la pantalla e-Paper. Finalmente, la pantalla se pone en modo hibernación. Esto apaga la pantalla y pone el controlador en modo deep-sleep.
void setup() {
initDisplay();
displayText();
epd.display();
epd.hibernate();
}
Función loop
La función loop() está vacía en este código ya que el contenido de la pantalla se configura en la función setup() y no necesita actualizarse continuamente. El ESP32 no ejecutará ninguna acción específica en el loop.
void loop() {
}
Subir y ejecutar el código
Ahora estamos listos para subir y ejecutar el código. Selecciona la placa que tienes en el board manager. En mi caso es la WEMOS LOLIN32 Lite que estaba listada en las Partes necesarias:

Luego presiona subir y después de un parpadeo, tu pantalla debería mostrar el siguiente texto:

Si funciona, podemos pasar a algo un poco más complicado. Si no, revisa el cableado y la línea donde se crea el objeto de pantalla. Específicamente, qué pines están asignados para la interfaz SPI.
Conectando la pantalla e-Paper y el BME280 al ESP32
Queremos mostrar temperatura ambiente, humedad y presión atmosférica usando el sensor BME280. Añadir el sensor es fácil, gracias a la interfaz I2C. Solo conecta SDA al pin 33 y SCL al pin 25, como se muestra abajo.

Puedes usar diferentes pines para I2C pero si lo haces, no olvides ajustar el código en la siguiente sección en consecuencia.
Ten en cuenta que hay versiones de la placa breakout BME280 para 5V y para 3.3V. Yo uso la versión de 3.3V y por eso conecto VCC al pin de 3.3V del ESP32.
Como la WEMOS LOLIN32 Lite tiene un puerto de batería y cargador integrados, puedes alimentar todo el sistema con una batería LiPo. La imagen abajo muestra el cableado completo con una batería LiPo conectada:

Incluso con la pequeña batería LiPo de 420mAh usada aquí, pude hacer funcionar el sistema durante varios días (con un ciclo de actualización de 5 minutos).
En la siguiente sección vamos a escribir el código para mostrar los datos del sensor en la pantalla e-Paper.
Código para estación meteorológica local
El siguiente código lee temperatura ambiente, humedad y presión atmosférica del BME280 cada 5 minutos y muestra esa información más la altitud en la pantalla e-Paper. La salida se ve así:

Entre los intervalos de 5 minutos, el ESP32, la pantalla e-Paper y el BME280 entran en modo deep-sleep, lo que reduce mucho el consumo de energía del sistema. Mira el código completo primero y luego analizamos los detalles:
#define ENABLE_GxEPD2_GFX 0
#include "Wire.h"
#include "GxEPD2_BW.h"
#include "Fonts/FreeMonoBold9pt7b.h"
#include "Fonts/FreeMono9pt7b.h"
#include "Fonts/FreeMonoBold18pt7b.h"
#include "Adafruit_BME280.h"
#include "esp_sleep.h"
#define SECONDS (1000 * 1000)
#define SEALEVELPRESSURE_HPA 1013.25
#define BME280_ADDRESS 0x76
Adafruit_BME280 bme;
GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> epd(GxEPD2_290_BS(5, 0, 2, 15));
void initDisplay() {
epd.init(115200, true, 50, false);
epd.setRotation(0);
epd.setFullWindow();
epd.setTextColor(GxEPD_BLACK);
epd.fillScreen(GxEPD_WHITE);
}
void initSensor() {
Wire.begin(33, 25); // Software I2C for BME280
bme.begin(BME280_ADDRESS, &Wire);
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF);
}
void displayText(int x, int y, const GFXfont* f, const char* text) {
epd.setFont(f);
epd.setCursor(x, y);
epd.print(text);
}
void displayHLine(int y) {
int o = 8;
epd.drawFastHLine(o, y, 128 - 2 * o, GxEPD_BLACK);
}
void displayLargeValue(int y, const char* name, float val, const char* unit) {
static char buffer[32];
sprintf(buffer, "%7.1f", val);
displayText(8, y, &FreeMono9pt7b, name);
displayText(4, y + 30, &FreeMonoBold9pt7b, buffer);
displayText(86, y + 30, &FreeMono9pt7b, unit);
displayHLine(y + 50);
}
void displaySmallValue(int y, char* name, float val, char* unit) {
static char buffer[32];
sprintf(buffer, "%5.1f", val);
displayText(8, y, &FreeMono9pt7b, name);
displayText(4, y + 35, &FreeMonoBold18pt7b, buffer);
displayText(110, y + 35, &FreeMono9pt7b, unit);
displayHLine(y + 50);
}
void setup() {
initSensor();
initDisplay();
int o = 20, d = 76;
bme.takeForcedMeasurement();
float temp = bme.readTemperature();
displaySmallValue(o, "temp", temp, "C");
float hum = bme.readHumidity();
displaySmallValue(o + d, "hum", hum, "%");
float alt = bme.readAltitude(SEALEVELPRESSURE_HPA);
displayLargeValue(o + 2 * d, "alt", alt, "m");
float pres = bme.readPressure() / 100.0;
displayLargeValue(o + 3 * d, "pres", pres, "hPa");
epd.display();
epd.hibernate();
esp_sleep_enable_timer_wakeup(5 * 60 * SECONDS);
esp_deep_sleep_start();
}
void loop() {
}
En el código anterior, mostramos lecturas de temperatura, humedad y presión de un sensor BME280 en una pantalla e-Paper. El sensor está conectado vía I2C por software y la pantalla se controla usando la biblioteca GxEPD2.
Constantes y bibliotecas
Comenzamos incluyendo las bibliotecas necesarias más tres bibliotecas de fuentes diferentes. Ten en cuenta que necesitarás instalar la Adafruit_BME280 library, si aún no lo has hecho.
#define ENABLE_GxEPD2_GFX 0 #include "Wire.h" #include "GxEPD2_BW.h" #include "Fonts/FreeMonoBold9pt7b.h" #include "Fonts/FreeMono9pt7b.h" #include "Fonts/FreeMonoBold18pt7b.h" #include "Adafruit_BME280.h" #include "esp_sleep.h" #define SECONDS (1000 * 1000) #define SEALEVELPRESSURE_HPA 1013.25 #define BME280_ADDRESS 0x76
La dirección I2C del sensor BME280 típicamente es 0x76 pero la tuya puede ser diferente y en algunas placas breakout puedes cambiar entre dos direcciones. La constante SEALEVELPRESSURE_HPA es usada por la biblioteca BME280 para calcular la altitud basada en la presión atmosférica. Esto es algo que debes ajustar según tu ubicación. Consulta nuestro tutorial sobre How To Use BME280 Pressure Sensor With Arduino, para más detalles.
Objetos de sensor y pantalla
Luego creamos los objetos para el sensor BME280 y la pantalla e-Paper. Como se mencionó antes, si usas una pantalla diferente o un cableado distinto, tendrás que ajustar la construcción del objeto de pantalla.
Adafruit_BME280 bme; GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> epd(GxEPD2_290_BS(5, 0, 2, 15));
Funciones de inicialización
La función initDisplay() inicializa la pantalla e-Paper configurando la comunicación, rotación, color y limpiando la pantalla. La función initSensor() inicializa el sensor BME280 iniciando la comunicación I2C y configurando los ajustes del sensor.
void initDisplay() {
...
}
void initSensor() {
Wire.begin(33, 25); // Software I2C for BME280
bme.setSampling(Adafruit_BME280::MODE_FORCED,
..
)
}
Como usamos I2C por software para el sensor BME280, necesitamos llamar a Wire.begin(33, 25) con los pines SDA y SCL que estamos usando. Si conectas el sensor BME280 a pines diferentes, tendrás que cambiar el código aquí.
Ten en cuenta que ejecutamos el sensor BME280 con el ajuste MODE_FORCED. En forced mode el sensor realiza una medición, almacena los resultados y luego entra en deep-sleep. Eso es lo que queremos, ya que entre mediciones pondremos también el ESP32 y la pantalla e-Paper en deep-sleep.
Funciones de pantalla
Hay múltiples funciones para mostrar texto, líneas horizontales, valores grandes (presión, altitud) y valores pequeños (temperatura, humedad) en la pantalla e-Paper. Estas funciones manejan el formato y la posición de los datos a mostrar.
void displayText(int x, int y, const GFXfont* f, const char* text) {
// Display text code
}
void displayHLine(int y) {
// Display horizontal line code
}
void displayLargeValue(int y, const char* name, float val, const char* unit) {
// Display large value code
}
void displaySmallValue(int y, char* name, float val, char* unit) {
// Display small value code
}
Función setup
En la función setup(), se inicializan el sensor y la pantalla. Se toman lecturas de temperatura, humedad, altitud y presión y se muestran en la pantalla e-Paper. Luego se actualiza la pantalla y se pone en modo hibernación.
Después también ponemos el ESP32 en modo deep-sleep y lo despertamos automáticamente después de 5 minutos.
void setup() {
initSensor();
initDisplay();
bme.takeForcedMeasurement();
float temp = bme.readTemperature();
displaySmallValue(o, "temp", temp, "C");
...
epd.display();
epd.hibernate();
esp_sleep_enable_timer_wakeup(5 * 60 * SECONDS);
esp_deep_sleep_start();
}
Función loop
La función loop() está vacía ya que el ESP32 entra en deep sleep tras setup y nunca entra en loop. Pero se despierta cada 5 minutos y ejecuta la función setup de nuevo.
Cada actualización de la pantalla tarda 2-3 segundos y produce mucho parpadeo, lo cual es bastante molesto y no queda bien. Puedes evitar esto haciendo una actualización parcial. Para más detalles, consulta el tutorial Partial Refresh of e-Paper Display.
Aparte de eso, ahora tienes una pequeña estación meteorológica alimentada por batería que muestra y actualiza temperatura ambiente, humedad, presión atmosférica y altitud.
Código para estación meteorológica de internet
Si quieres una estación meteorológica más avanzada que obtenga sus datos de internet, está la fantástica biblioteca ESP32-e-Paper-Weather-Display que lo hace por ti.
Dependiendo del tamaño de la pantalla, muestra temperatura, humedad, presión, dirección del viento, fases lunares, condiciones meteorológicas, pronóstico y más. En la pantalla e-Paper de 2.9″ que uso aquí, se ve así:

Instalación de la biblioteca ESP32-e-Paper-Weather-Display
Para instalar la biblioteca ESP32-e-Paper-Weather-Display, necesitas descargar el archivo zip del repositorio de github y luego instalarlo vía Sketch -> Include Library -> Add .ZIP Library ....

También necesitarás la GxEPD2 library y la Adafruit_GFX library, pero ya las tienes instaladas de las secciones anteriores.
Configuración de la biblioteca ESP32-e-Paper-Weather-Display
Antes de poder mostrar datos meteorológicos de internet usando la biblioteca ESP32-e-Paper-Weather-Display, hay un poco de trabajo que hacer. Primero necesitamos obtener una clave API de OpenWeather, luego descargar el código de ejemplo para nuestra pantalla, y finalmente actualizar el archivo de configuración en el código de ejemplo con la clave API y nuestras credenciales Wi-Fi.
Clave API de OpenWeather
La biblioteca ESP32-e-Paper-Weather-Display usa el servicio gratuito OpenWeather para recibir datos meteorológicos de internet. Antes de poder usar cualquiera de las APIs de OpenWeather, necesitas una clave API y para eso necesitas una cuenta. Para crear una cuenta gratuita ve a sign-up page e introduce tus datos allí.

Después ve a la página de creación de api-key y crea una clave API. La clave API es esa cadena larga «sdfd87fakeby6apikeysf4z» que ves en la captura de pantalla abajo. Tu clave será diferente.

Si necesitas más ayuda, consulta nuestro tutorial: Simple ESP32 Internet Weather Station.
Luego, descarga el código de ejemplo para el tamaño y tipo de pantalla desde el repositorio github de la biblioteca ESP32-e-Paper-Weather-Display. Por ejemplo, yo descargué el código para la Waveshare_2_9 example.
Alternativamente, puedes usar el IDE de Arduino que también tiene algunos, pero no todos, los ejemplos:

Archivo de configuración owm_credential.h
Finalmente, abre el archivo .ino (por ejemplo Waveshare_2_9.ino) en el IDE de Arduino y haz clic en la pestaña del archivo owm_credential.h.
Este archivo tiene todos los ajustes específicos para tu estación meteorológica como ubicación, unidades, idioma, zona horaria, etc. Lo más importante es que contiene las constantes para tus credenciales Wi-Fi (ssid, password) y la clave API de OpenWeather que debes configurar allí.

owm_credential.hArchivo de configuración para ESP32-e-Paper-Weather-DisplayComo se mencionó, dependiendo del tamaño de la pantalla e-Paper, la biblioteca ESP32-e-Paper-Weather-Display muestra información meteorológica más o menos detallada. En una pantalla grande de 7.5″, obtienes un conjunto muy completo de datos meteorológicos y se ve absolutamente fantástico:

Monitor de batería
Finalmente, la biblioteca ESP32-e-Paper-Weather-Display también muestra de forma nativa información de batería si usas un Lolin D32 board que tiene el GPIO-35 como entrada ADC:

En otras placas, tendrás que cambiar la instrucción analogRead(35) en el código y especificar el pin donde está conectado tu monitor de voltaje.

Un monitor de voltaje puede ser un simple divisor de voltaje conectado a los terminales de la batería. Consulta How to Monitor Battery Voltage for Battery Powered Projects para más detalles sobre eso. Para estimaciones más precisas de carga de batería, puedes usar ICs específicos para monitorización de batería, como el MAX1704X.
Conclusiones
En este tutorial aprendiste a construir una estación meteorológica alimentada por batería con un ESP32, un sensor BME280 y una pantalla e-Paper.
Usamos un sensor BME280 para medir temperatura ambiente, humedad y presión atmosférica. Y usamos el software ESP32-e-Paper-Weather-Display para mostrar datos meteorológicos de internet.
Con eso tienes todo lo necesario para construir tu propia versión que, por ejemplo, podría combinar datos meteorológicos de internet con información local. También podrías recopilar información de sensores remotos y añadirla a la pantalla.
¡Diviértete trasteando y si tienes alguna pregunta no dudes en preguntar! 😉

