/* ESP32 BMP280 sender with DEEP SLEEP (3 seconds) BMP280 and BME280 sensor can be used: Enable it with the #define in the code You have also to adapt the receiver MAC in the code. external libraries: Temperature and Pressure Sensor https://github.com/mahfuz195/BMP280-arduino-library or Temperature, Pressure and Humidty Sensor https://github.com/hasenradball/Bosch_BME280_Arduino.git 2026-01-30 mchris V3: first usable version 2026-01-31 mchris V4: Battery measurement added */ #include "BMP280.h" #include "Wire.h" #include #include #include "esp_adc_cal.h" //#define USE_BMP280 #define USE_BME280 #ifdef USE_BME280 #include // global instance BME::Bosch_BME280 bme{BME280_I2C_ADDR_PRIM, 249.67F, true}; #endif #ifdef USE_BMP280 BMP280 bmp; #endif #define LEDPIN 2 // Receiver MAC address uint8_t receiverMAC[] = {0xCC, 0x7B, 0x5C, 0x1E, 0xAC, 0x5C}; #define ADC_PIN 35 // GPIO35 (ADC1_CH7) VCC measurement #define R1 10000.0 // 10kΩ #define R2 47000.0 // 27kΩ #define POWERPIN 33 // Structure MUST match receiver structure typedef struct struct_message { float temperature; float pressure; float humidity; float batteryVoltage; float counter; char message[32]; } struct_message; struct_message sensorData; esp_now_peer_info_t peerInfo; // Deep sleep counter (RTC memory survives sleep) RTC_DATA_ATTR int bootCount = 0; // callback when data is sent // NEW (ESP32 Arduino Core 3.0+ / ESP-IDF v5.x) void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } esp_adc_cal_characteristics_t *adc_chars; esp_adc_cal_value_t val_type; void setup() { pinMode(LEDPIN, OUTPUT); // digitalWrite(LEDPIN, HIGH); pinMode(POWERPIN, OUTPUT); digitalWrite(POWERPIN, HIGH); // Configure ADC for Arduino API (12-bit, 0dB attenuation for 0-1.1V range) analogReadResolution(12); // 12-bit resolution (0-4095) analogSetAttenuation(ADC_0db); // 0-1.1V input range analogSetPinAttenuation(ADC_PIN, ADC_0db); // Apply to specific pin // Characterize ADC adc_chars = (esp_adc_cal_characteristics_t*)calloc(1, sizeof(esp_adc_cal_characteristics_t)); val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_0, ADC_WIDTH_BIT_12, 1100, adc_chars); Serial.begin(115200); Serial.print("Calibration scheme used: "); switch (val_type) { case ESP_ADC_CAL_VAL_EFUSE_TP: Serial.println("eFuse Two Point"); break; case ESP_ADC_CAL_VAL_EFUSE_VREF: Serial.println("eFuse Vref"); break; default: Serial.println("Default Vref"); break; } uint32_t adc_raw; adc_raw = analogRead(ADC_PIN); uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(adc_raw, adc_chars); // Scale for voltage divider: Vcc = Vin * (R1 + R2) / R1 float batteryVoltage = (voltage_mv / 1000.0f) * (R1 + R2) / R1; Serial.print("battery voltage: "); Serial.println(batteryVoltage); bootCount++; // Count wake-ups Serial.printf("Boot number: %d\n", bootCount); #ifdef USE_BMP280 if (!bmp.begin()) { Serial.println("BMP280 init failed!"); //esp_deep_sleep_start(); // Sleep immediately if sensor fails } Serial.println("BMP280 init success!"); bmp.setOversampling(4); #endif #ifdef USE_BME280 Wire.begin(); if (bme.begin() != 0) { Serial.println("\n\t>>> ERROR: Init of Bosch BME280 Sensor failed! <<<"); } #endif WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); //esp_deep_sleep_start(); } // Register callback esp_now_register_send_cb(OnDataSent); // Add peer memcpy(peerInfo.peer_addr, receiverMAC, 6); peerInfo.channel = 0; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add peer"); //esp_deep_sleep_start(); } Serial.println("ESP-NOW ready!"); } void loop() { double T = -1, P = -2, H = -3; char result = 1; #ifdef USE_BME280 bme.measure(); result = 1; #endif #ifdef USE_BMP280 result = bmp.startMeasurment(); #endif if (result != 0) { delay(result); #ifdef USE_BMP280 result = bmp.getTemperatureAndPressure(T, P); #endif #ifdef USE_BME280 T = bme.getTemperature(); P = bme.getPressure(); H = bme.getHumidity(); #endif if (result != 0) { digitalWrite(LEDPIN, HIGH); // Fill data structure sensorData.temperature = (float)T; sensorData.pressure = (float)P; sensorData.humidity = (float)H; sensorData.counter = bootCount; strcpy(sensorData.message, "BMP280 OK"); uint32_t adc_raw; adc_raw = analogRead(ADC_PIN); uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(adc_raw, adc_chars); // Scale for voltage divider: Vcc = Vin * (R1 + R2) / R1 float batteryVoltage = (voltage_mv / 1000.0f) * (R1 + R2) / R1; sensorData.batteryVoltage = batteryVoltage; digitalWrite(POWERPIN, LOW); esp_err_t sendResult = esp_now_send(receiverMAC, (uint8_t *) &sensorData, sizeof(sensorData)); if (sendResult == ESP_OK) { Serial.println("Sent with success"); } else { Serial.print("Send Error: "); Serial.println(sendResult); } // Print readings Serial.print("T="); Serial.print(T, 2); Serial.print("°C "); Serial.print("P="); Serial.print(P, 2); Serial.println("mBar"); delay(20); // importand: needed for sending data digitalWrite(LEDPIN, LOW); const uint16_t SLEEPSECONDS = 3; esp_sleep_enable_timer_wakeup(SLEEPSECONDS * 1000000ULL); esp_deep_sleep_start(); } } Serial.println("BMP read failed - retrying..."); delay(100); }