Temperature, Humidity and Atmospheric Pressure Sensor (BME280) - Outdoor [RUA]
Project Overview
The Outdoor Environmental Sensor Project is a low-power autonomous system designed to monitor
temperature, relative humidity, and atmospheric pressure in an outdoor environment.
The system prioritizes energy efficiency, reliability, and long-term autonomy, making it suitable
for continuous operation using standard AA batteries.
An ESP32 microcontroller collects data from a BME280 sensor, transmits the measurements via Wi-Fi
to a Raspberry Pi, and immediately enters deep sleep mode to minimize power consumption.
The Raspberry Pi stores, processes, and exposes the data through a web-based interface. You can see here: https://joelbonifacio.dynip.sapo.pt/electro6.1.html
Fig.1 - Materials: ESP32, BME280, batteries, support for the batteries and cables.
BME280 Technical Specifications
Parameter
Value
Temperature Range
-40 °C to +85 °C
Temperature Accuracy
±1.0 °C
Humidity Range
0 – 100 % RH
Humidity Accuracy
±3 % RH
Response Time
1 second
Hysteresis
±1% RH
Pressure Range
300 – 1100 hPa
Absolute Accuracy
±1 hPa
Relative Accuracy
±0.12 hPa (equivalent to ±1 meter in altitude)
RMS Noise
0.2 Pa
Communication Interface
SPI
Operating Voltage
3.3 V
Communication Interface
I2C (Gravity Connector) or SPI
ESP32 ↔ BME280 Wiring Diagram (SPI)
Here is the schematic of the circuit.
Fig.2 - Schematic of the circuit.
FireBeetle 2 ESP32-C6 Firmware (Low Power Mode + SPI)
// ----- CONFIGURAÇÃO HARDWARE -----
// O fio VCC do sensor BME280 liga AQUI, e não nos 3.3V fixos.
// Isto permite desligar o sensor e o LED vermelho completamente.
#define SENSOR_POWER_PIN 14
#define BME_CS 21
#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
Adafruit_BME280 bme(BME_CS);
// ----- CONFIGURAÇÃO WIFI (IP ESTÁTICO) -----
const char* ssid =
const char* password =
// Configurações de Rede Fixa
IPAddress local_IP();
IPAddress gateway();
IPAddress subnet();
IPAddress primaryDNS();
const char* serverURL = ;
// ----- SLEEP -----
const uint64_t SLEEP_MINUTES = 15;
const uint64_t SLEEP_MICROS = SLEEP_MINUTES * 60ULL * 1000000ULL;
void setup() {
// Serial.begin(115200); // Descomentar apenas para testes. Em produção, desligar poupa tempo.
// ------------------------------------------------
// PASSO 1: LIGAR E LER O SENSOR (O Wi-Fi ainda está desligado!)
// ------------------------------------------------
pinMode(SENSOR_POWER_PIN, OUTPUT);
digitalWrite(SENSOR_POWER_PIN, HIGH); // LIGAR O SENSOR E O LED VERMELHO
delay(10); // Esperar 10ms para o sensor arrancar
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!bme.begin(BME_CS)) {
// Se o sensor falhar, vamos dormir logo para não gastar bateria
goToSleep();
}
// Configurar para ler apenas 1 vez (Forced Mode)
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1,
Adafruit_BME280::SAMPLING_X1,
Adafruit_BME280::SAMPLING_X1,
Adafruit_BME280::FILTER_OFF);
bme.takeForcedMeasurement(); // Medição instantânea
float temp = bme.readTemperature();
float hum = bme.readHumidity();
float pres = bme.readPressure() / 100.0F;
// *** POUPANÇA CRÍTICA ***
// Desligamos o sensor e o LED vermelho AGORA.
// Eles não gastam energia enquanto o Wi-Fi conecta.
digitalWrite(SENSOR_POWER_PIN, LOW);
// ------------------------------------------------
// PASSO 2: CONECTAR WI-FI
// ------------------------------------------------
WiFi.mode();
WiFi.config();
WiFi.begin();
// Timeout curto (10s). Se não der, desiste.
int wifiTimeout = 20;
while (WiFi.status() != WL_CONNECTED && wifiTimeout > 0) {
delay(500);
wifiTimeout--;
}
if (WiFi.status() == WL_CONNECTED) {
// ------------------------------------------------
// PASSO 3: ENVIAR DADOS
// ------------------------------------------------
StaticJsonDocument<200> doc;
doc["temperature"] = temp;
doc["humidity"] = hum;
doc["pressure"] = pres;
String json;
serializeJson(doc, json);
int response = http.POST(json);
http.end();
}
// ------------------------------------------------
// PASSO 4: DORMIR
// ------------------------------------------------
goToSleep();
}
void goToSleep() {
// Desliga Wi-Fi explicitamente
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
esp_sleep_enable_timer_wakeup(SLEEP_MICROS);
esp_deep_sleep_start();
}
void loop() {
// Não é necessário usar loop, porque o ESP32 acorda sozinho do deep sleep
}
Fig.3 - FireBeetle 2 ESP32-C6 Partial Code.
.
Python Services on Raspberry Pi
Flask API for data ingestion;
SQLite database logger;
Data aggregation and statistics.
Apache Reverse Proxy (XXXX.conf)
Apache is configured as a reverse proxy to forward /api/rua requests
to the internal Flask service. This isolates backend services and provides
clean, stable URLs for the frontend.
Power Consumption Analysis
Let's be conservative with these calculations (meaning I will assume the reasonable "worst-case" scenario).
Your Hardware Data (Datasheets)
Battery: 3x NiMH 2500mAh batteries.
Theoretical Total Capacity: 2500 mAh.
Note: Since the batteries do not discharge to 0V (the ESP32 shuts down around 3.0V or 2.8V), we only utilize about 85% of the charge. We will use 2125 useful mAh.
ESP32-C6 Consumption (FireBeetle 2):
Wi-Fi On (TX/RX): Average of 180 mA (peaks of 350mA, but the average is lower).
Awake without Wi-Fi (Measuring sensor): ~30 mA.
Deep Sleep: The datasheet says 13 µA, but let's be realistic and assume 25 µA (0.025 mA) to account for small circuit leakages.
BME280 Sensor Consumption:
Measuring: 1 mA (irrelevant as it is very fast).
Sleeping (via GPIO): 0 mA (cut the power at GPIO14).
15-Minute Cycle (900 Seconds)
Let's calculate the "Energy Cost" of each 15-minute cycle. We will use the unit mAs (milliAmpere-seconds), which is the "currency" of energy spent.
With static IP, the connection is fast. Let's assume 2.5 seconds in total to connect, send and receive the "OK".
Time: 2.5 seconds.
Consumption: 180 mA.
Cost: \(180 \text{ mA} \times 2.5 \text{ s} = \mathbf{450 \text{ mAs}}\).
Phase 3: Deep Sleep
The rest of the time until completing the 15 minutes.
Time: \(900 \text{ s} - 2.7 \text{ s} = 897.3 \text{ seconds}\).
Consumption: 0.025 mA (25 µA).
Cost: \(0.025 \text{ mA} \times 897.3 \text{ s} = \mathbf{22.4 \text{ mAs}}\).
Total per Cycle and Duration
Total Cost of 1 cycle (15 min):
\(6 + 450 + 22.4 = \mathbf{478.4 \text{ mAs}}\)
Average Consumption per Second (Average Current):
To know the equivalent continuous average current:
\(\text{Days of life} = \frac{4009}{24} \approx \mathbf{167 \text{ days}}\)
Theoretical Result: ~5 and a half months.
The "Reality Factor" (Important to read)
In theory, it gives 167 days. In practice, there are two invisible enemies:
NiMH Battery Self-discharge: Rechargeable batteries lose charge on their own, even sitting in a drawer. Normal batteries lose 10-20% of their charge per month. If they are "Ready to Use" batteries (like Eneloop or IKEA Ladda), they lose much less.
Regulator Efficiency: The FireBeetle has components that convert the battery voltage to 3.3V. This process is not 100% efficient.
My Estimate:
Applying a safety margin of 30% for self-discharge and inefficiencies (coeficient of security: 100% - 30% = 70%):
Something between 3 to 4 guaranteed months (it could reach 5 months if the batteries are of good quality).
This is the massive difference of:
Using Static IP (reduces Wi-Fi time).
Killing the sensor via GPIO (reduces consumption in sleep).
Using Deep Sleep correctly.
But why using 3 AA Batteries Instead of 4 Batteries AA?
Using 3 AA alkaline batteries provide an initial voltage of approximately 4.5 V,
which is safely handled by the ESP32 onboard regulator.
Usar 4 baterias elevaria a tensão para 6V, excedendo a gama ideal do regulador e aumentando a dissipação térmica.
SPI Was Mandatory Instead of I²C
During development, the use of I²C combined with active Wi-Fi on the ESP32 caused
intermittent communication failures and bus lockups.
Migrating the BME280 to SPI provided a dedicated, synchronous communication channel, fully eliminating the instability.
Outdoor Weather-Resistant Enclosure For Testing
I bought a waterproof box and made some minor modifications to adapt it to this project.
It has two large holes in the bottom for ventilation, and right above them is the BME280 sensor.
The goal is to prevent water from entering, especially since it's windy and raining heavily here (which is quite common), but at the same time, to avoid interfering with the sensor readings.
I also put a very fine green mesh to prevent insects from getting in and covering the sensor hole.
Now it will be screwed to the outside wall of the house.
P.S. - It will not be exposed directly to sun/rain.
This is the final result:
Fig.4 - Outdoor weather-resistant enclosure I.
Fig.5 - Outdoor weather-resistant enclosure II.
Fig.6 - Outdoor weather-resistant enclosure III.
Fig.7 - Outdoor weather-resistant enclosure IV.
Fig.8 - Outdoor weather-resistant enclosure on the wall below the balcony.
Temperature, Humidity and Atmospheric Pressure Sensor (BME280) - Outdoor [RUA]
Project Overview
The Outdoor Environmental Sensor Project is a low-power autonomous system designed to monitor temperature, relative humidity, and atmospheric pressure in an outdoor environment. The system prioritizes energy efficiency, reliability, and long-term autonomy, making it suitable for continuous operation using standard AA batteries.
An ESP32 microcontroller collects data from a BME280 sensor, transmits the measurements via Wi-Fi to a Raspberry Pi, and immediately enters deep sleep mode to minimize power consumption. The Raspberry Pi stores, processes, and exposes the data through a web-based interface. You can see here: https://joelbonifacio.dynip.sapo.pt/electro6.1.html
Hardware Components
Fig.1 - Materials: ESP32, BME280, batteries, support for the batteries and cables.
BME280 Technical Specifications
ESP32 ↔ BME280 Wiring Diagram (SPI)
Here is the schematic of the circuit.
Fig.2 - Schematic of the circuit.
FireBeetle 2 ESP32-C6 Firmware (Low Power Mode + SPI)
Fig.3 - FireBeetle 2 ESP32-C6 Partial Code.
Python Services on Raspberry Pi
Apache Reverse Proxy (XXXX.conf)
Apache is configured as a reverse proxy to forward
/api/ruarequests to the internal Flask service. This isolates backend services and provides clean, stable URLs for the frontend.Power Consumption Analysis
Let's be conservative with these calculations (meaning I will assume the reasonable "worst-case" scenario).
Your Hardware Data (Datasheets)
ESP32-C6 Consumption (FireBeetle 2):
BME280 Sensor Consumption:
15-Minute Cycle (900 Seconds)
Let's calculate the "Energy Cost" of each 15-minute cycle. We will use the unit mAs (milliAmpere-seconds), which is the "currency" of energy spent.
Time: 0.2 seconds (it's very fast).
Consumption: 30 mA.
Cost: \(30 \text{ mA} \times 0.2 \text{ s} = \mathbf{6 \text{ mAs}}\).
With static IP, the connection is fast. Let's assume 2.5 seconds in total to connect, send and receive the "OK".
Time: 2.5 seconds.
Consumption: 180 mA.
Cost: \(180 \text{ mA} \times 2.5 \text{ s} = \mathbf{450 \text{ mAs}}\).
The rest of the time until completing the 15 minutes.
Time: \(900 \text{ s} - 2.7 \text{ s} = 897.3 \text{ seconds}\).
Consumption: 0.025 mA (25 µA).
Cost: \(0.025 \text{ mA} \times 897.3 \text{ s} = \mathbf{22.4 \text{ mAs}}\).
Total per Cycle and Duration
Total Cost of 1 cycle (15 min):
Average Consumption per Second (Average Current):
To know the equivalent continuous average current:
This means that, in practice, the system behaves as if it were consuming only 0.53 mA constantly.
Final Calculation: How Long Does It Last?
We have 2125 mAh (useful capacity). The system consumes 0.53 mA.
The "Reality Factor" (Important to read)
In theory, it gives 167 days. In practice, there are two invisible enemies:
My Estimate:
Applying a safety margin of 30% for self-discharge and inefficiencies (coeficient of security: 100% - 30% = 70%):
Conclusion
Something between 3 to 4 guaranteed months (it could reach 5 months if the batteries are of good quality).
This is the massive difference of:
But why using 3 AA Batteries Instead of 4 Batteries AA?
Using 3 AA alkaline batteries provide an initial voltage of approximately 4.5 V, which is safely handled by the ESP32 onboard regulator. Usar 4 baterias elevaria a tensão para 6V, excedendo a gama ideal do regulador e aumentando a dissipação térmica.
SPI Was Mandatory Instead of I²C
During development, the use of I²C combined with active Wi-Fi on the ESP32 caused intermittent communication failures and bus lockups. Migrating the BME280 to SPI provided a dedicated, synchronous communication channel, fully eliminating the instability.
Outdoor Weather-Resistant Enclosure For Testing
I bought a waterproof box and made some minor modifications to adapt it to this project. It has two large holes in the bottom for ventilation, and right above them is the BME280 sensor. The goal is to prevent water from entering, especially since it's windy and raining heavily here (which is quite common), but at the same time, to avoid interfering with the sensor readings. I also put a very fine green mesh to prevent insects from getting in and covering the sensor hole. Now it will be screwed to the outside wall of the house.
P.S. - It will not be exposed directly to sun/rain.
This is the final result:
Fig.4 - Outdoor weather-resistant enclosure I.
Fig.5 - Outdoor weather-resistant enclosure II.
Fig.6 - Outdoor weather-resistant enclosure III.
Fig.7 - Outdoor weather-resistant enclosure IV.
Fig.8 - Outdoor weather-resistant enclosure on the wall below the balcony.
Vented Radiation Shield Implementation
You can see more in the Solidworks section.
Leave A Comment