I have a weather station in the back garden now. It mostly works, which for a first hardware project running off a battery in a British November is a higher bar than it sounds. It reads temperature, humidity and pressure every few minutes, posts them to a little server in the loft, and then goes back to sleep. The going-back-to-sleep part is the whole project, really. Everything else was an afternoon.
The hardware is unglamorous and that's deliberate. An ESP32 dev board, a BME280 sensor on the I2C bus for temperature, humidity and pressure, an 18650 cell, and a cheap TP4056 charging board so I can top it up without unscrewing the box. The BME280 is the sort of part that makes you feel briefly competent: four wires, a well-supported library, sensible readings within seconds. I had numbers on the serial monitor before I'd finished my tea.
temp=8.42C humidity=87.1% pressure=1009.3hPa
That 87% humidity is, of course, correct. It is November and I live in England.
the part that nearly didn't work
The naive version drained the battery in under a day. The ESP32's WiFi radio is hungry, and a board sat in a loop reading a sensor and holding a connection open will happily flatten an 18650 overnight. The fix, the thing the whole exercise is actually about, is deep sleep.
The pattern is: wake, read the sensor, connect to WiFi, post the reading, then put the chip into deep sleep with a timer to wake it again. In deep sleep the ESP32 pulls a few tens of microamps instead of the hundred-plus milliamps it draws with the radio up. The difference is roughly three orders of magnitude, which is the difference between a day and a fortnight.
esp_sleep_enable_timer_wakeup(5 * 60 * 1000000ULL); // 5 minutes, in microseconds
esp_deep_sleep_start();
Two things bit me here. First, deep sleep is a full reset, not a pause: execution restarts from the top of setup() on wake, so anything you want to survive has to live in RTC memory or be re-derived. That's fine once you expect it, baffling for an hour if you don't. Second, the slowest part of every wake cycle is the WiFi association and DHCP, not the sensor read. Caching a static IP and the channel shaved the radio-on time from around eight seconds to under three, and at these duty cycles the time the radio is awake is almost the entire energy budget.
mostly works
The "mostly" is honest. The enclosure is a plastic box with holes drilled in the wrong places and a Stevenson-screen ambition it does not live up to, so direct sun would skew the temperature if we got any, which we don't. The pressure trend tracks the Met Office nicely, which is oddly satisfying to confirm with your own hardware. And the battery now lasts the thick end of two weeks per charge, up from less than a day, purely from being disciplined about when the radio is allowed to be on.
That's the lesson I'm taking from it. On a battery-powered radio device, the firmware is mostly a power-management problem wearing a sensor costume. The reading is easy. Deciding when to be awake is the engineering.