IoT / Веб
Складний
Датчик на батарейці: BME280 + MQTT + deep sleep на місяці автономності
Плата прокидається раз на 10 хвилин, міряє температуру, вологість, тиск і заряд акумулятора, публікує їх у MQTT і знову засинає. Розбираємо, як вичавити максимум з батареї.
Задача
Поставити датчик на балконі чи в теплиці, де немає розетки, і не міняти батарею місяцями. Ключ — deep sleep: у цьому режимі ESP32 споживає ~10 мкА, а прокидається лише на 2–3 секунди для вимірювання й відправки.
Компоненти
- Плата з низьким струмом сну: FireBeetle ESP32, LOLIN D32, TinyPICO або голий модуль ESP32-WROOM зі стабілізатором HT7333/MCP1700. Звичайні DevKit через USB-UART та AMS1117 споживають 5–15 мА навіть уві сні!
- Датчик BME280 (I²C) — температура, вологість, тиск
- Li-Ion 18650 або Li-Po 1000–3000 мА·год
- Дільник напруги 2 × 100 кОм для вимірювання батареї
- MQTT-брокер (Mosquitto, наприклад add-on у Home Assistant)
Підключення
| Компонент | ESP32 |
|---|---|
| BME280 VIN / GND | 3V3 / GND |
| BME280 SDA / SCL | GPIO 21 / GPIO 22 |
| Середня точка дільника BAT+ → 100k → • → 100k → GND | GPIO 35 |
Бібліотеки
- PubSubClient (Nick O'Leary)
- Adafruit BME280 Library
Код
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
const char* MQTT_HOST = "192.168.1.10";
const int MQTT_PORT = 1883;
const char* MQTT_TOPIC = "home/balcony/sensor";
const uint64_t SLEEP_MINUTES = 10;
const int BATTERY_PIN = 35; // через дільник 100k/100k
RTC_DATA_ATTR uint32_t bootCount = 0; // переживає deep sleep
WiFiClient net;
PubSubClient mqtt(net);
Adafruit_BME280 bme;
void goToSleep() {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
esp_sleep_enable_timer_wakeup(SLEEP_MINUTES * 60ULL * 1000000ULL);
esp_deep_sleep_start();
}
void setup() {
unsigned long started = millis();
Serial.begin(115200);
bootCount++;
if (!bme.begin(0x76)) {
Serial.println("BME280 not found");
goToSleep();
}
// 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();
float t = bme.readTemperature();
float h = bme.readHumidity();
float p = bme.readPressure() / 100.0F;
float vbat = analogReadMilliVolts(BATTERY_PIN) * 2 / 1000.0;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
if (millis() - started > 10000) { // не палимо батарею, якщо роутер недоступний
Serial.println("WiFi timeout");
goToSleep();
}
delay(50);
}
mqtt.setServer(MQTT_HOST, MQTT_PORT);
if (mqtt.connect("esp32-balcony")) {
char payload[128];
snprintf(payload, sizeof payload,
"{\"t\":%.2f,\"h\":%.1f,\"p\":%.1f,\"vbat\":%.2f,\"boot\":%lu}",
t, h, p, vbat, (unsigned long)bootCount);
mqtt.publish(MQTT_TOPIC, payload, true); // retained
mqtt.loop();
delay(50);
mqtt.disconnect();
}
Serial.printf("Awake for %lu ms\n", millis() - started);
goToSleep();
}
void loop() {} // сюди ніколи не доходимо
Розрахунок автономності
| Фаза | Струм | Тривалість |
|---|---|---|
| Активна (Wi-Fi + MQTT) | ~120 мА | ~3 с |
| Deep sleep (хороша плата) | ~0.05 мА | 597 с |
Середній струм ≈ 120 × 3 / 600 + 0.05 ≈ 0.65 мА. Акумулятор 2000 мА·год → ≈ 3000 год ≈ 4 місяці.
Як прокидатися швидше (і жити довше)
- Статичний IP —
WiFi.config(ip, gateway, subnet, dns)економить 0.5–1 с на DHCP. - Запам'ятати канал і BSSID роутера в
RTC_DATA_ATTRта передати їх уWiFi.begin(ssid, pass, channel, bssid)— ще мінус секунда. - Рідше публікувати: відправляти дані лише коли температура змінилася більше ніж на 0.2 °C (попереднє значення зберігайте в RTC-пам'яті).
- ESP-NOW замість Wi-Fi (див. відповідний проєкт) — активна фаза скорочується до ~100 мс.
Home Assistant
Додайте MQTT-сенсори в configuration.yaml:
mqtt:
sensor:
- name: "Balcony temperature"
state_topic: "home/balcony/sensor"
unit_of_measurement: "°C"
device_class: temperature
value_template: "{{ value_json.t }}"
- name: "Balcony battery"
state_topic: "home/balcony/sensor"
unit_of_measurement: "V"
device_class: voltage
value_template: "{{ value_json.vbat }}"
Типові проблеми
- Батарея сідає за тиждень — плата з USB-UART/AMS1117 або світлодіод живлення. Виміряйте струм сну мультиметром.
- BME280 показує +2 °C — самонагрів; саме тому використовується forced mode.
- Показник батареї «стрибає» — додайте конденсатор 100 нФ між GPIO 35 і GND.