Tempy is a lightweight, offline, low-power altimeter and thermometer built for the Heltec WiFi Kit 32 V3 using a BMP280 sensor. It displays temperature, elevation/altitude, and an animated face on the OLED. Tempy runs entirely without WiFi, internet, or cloud services. Designed for accuracy, portability, and very low sleep power consumption.
This project is intentionally simple and hackable. Users can recompile it with their own calibration, unit system, and display preferences in Config.h.
• Accurate temperature (°C/°F) • Accurate barometric altitude (feet or meters) • Sleep cycles with RTC-retained calibration • Smooth altitude display using optional averaging window • Animated face and slide transitions • Instant-on from deep sleep • Button-driven wake and display modes • Fully offline; no WiFi or external services • Simple configuration through a single header file
• Heltec WiFi Kit 32 V3 (ESP32-S3) • BMP280 pressure sensor (I²C) • Heltec onboard OLED display (I²C, separate internal bus)
Tempy uses two I²C controllers:
- Heltec's internal OLED bus (handled by the Heltec library)
- An external I²C bus dedicated to the BMP280
/src
App.cpp / App.h
Config.h
Sensor.cpp / Sensor.h
Sleep.cpp / Sleep.h
UI.cpp / UI.h
Face.cpp / Face.h
main.cpp
All configuration happens in Config.h.
Key options:
- Unit system (metric or imperial)
- Whether temperature or elevation is primary in the UI
- Whether to show both temperatures
- Optional introductory banner
- Calibration (SEA_LEVEL_HPA and SITE_ALTITUDE_M)
Tempy supports three calibration modes. Only one is active at a time depending on Config.h.
You provide a known sea-level pressure (QNH). Tempy uses it directly as P0.
Set:
static constexpr float SEA_LEVEL_HPA = 1018.6f;Tempy will:
- Trust that value fully
- Ignore SITE_ALTITUDE_M
- Use this as the sea-level reference
- Write the result into RTC memory so it persists through deep sleep
You provide your known elevation in meters.
Set:
static constexpr float SITE_ALTITUDE_M = 125.6f;Tempy will:
- Read current pressure
- Compute correct sea-level pressure using the barometric formula
- Seed that into RTC memory
- Use the derived P0 for all future altitude calculations
Leave both values at zero:
static constexpr float SEA_LEVEL_HPA = 0.0f;
static constexpr float SITE_ALTITUDE_M = 0.0f;Tempy will:
- Read pressure at the moment of the first boot
- Assume that height is 0 m (baseline)
- Compute the sea-level pressure
- Store it in RTC memory
- Use that as the reference P0 on all subsequent deep-sleep wakeups
Tempy always establishes a stable sea-level reference P0:
- If Mode A: P0 = your provided SEA_LEVEL_HPA
- If Mode B: P0 = derived sea-level pressure from your elevation
- If Mode C: P0 = derived assuming current height = 0 m
After the initial boot, P0 is stored in RTC slow memory, not flash.
This means:
- Deep sleep cycles retain precise calibration
- Hard resets (power loss) clear RTC and revert to Mode A/B/C depending on Config
- Travel works correctly because altitude is recomputed every reading using the seeded P0
Only a true cold boot away from your baseline location causes temporary inaccuracy. A reboot back at your starting location reseeds it correctly.
Tempy optionally averages several altitude samples to reduce jitter:
static constexpr uint8_t ALT_SMOOTH_WINDOW = 4;Set to 1 to disable smoothing entirely.
BMP280-based altitude is highly sensitive to weather changes. With proper seeding:
- Local travel within a region is accurate enough for casual use
- Mountain driving will show meaningful elevation gain/loss
- Day-to-day drift is minimized because P0 persists across deep sleep
Accuracy cannot match GNSS but is excellent for a novelty altimeter.
- The device sleeps after a configurable time
- Wake-from-button extends active time
- RTC slow memory keeps the seeded P0 for correct altitude on wake
This project uses PlatformIO.
To build:
pio run
To upload:
pio run -t upload
To monitor:
pio device monitor