feat(bme280): Add altitude computation and sea-level pressure#321
feat(bme280): Add altitude computation and sea-level pressure#321
Conversation
There was a problem hiding this comment.
Pull request overview
Adds altitude estimation to the BME280 driver via a configurable sea-level pressure reference, and updates docs/tests/examples accordingly.
Changes:
- Introduces
sea_level_pressure(default 1013.25 hPa) and analtitude()method on the driver. - Updates the
weather_station.pyexample to use the driver’s altitude computation. - Extends README and mock scenario tests to cover altitude and the new reference pressure.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
lib/bme280/bme280/device.py |
Adds sea_level_pressure attribute and altitude() API. |
lib/bme280/examples/weather_station.py |
Switches example altitude calculation to sensor.altitude(). |
lib/bme280/README.md |
Documents altitude usage and marks altitude/sea-level pressure supported in comparison table. |
tests/scenarios/bme280.yaml |
Adds mock tests for default sea-level pressure and altitude computations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| temperature, pressure, humidity = sensor.read() | ||
| alt = altitude_m(pressure) | ||
| alt = sensor.altitude() |
There was a problem hiding this comment.
In this example loop, sensor.read() returns a pressure value that gets logged/printed, but sensor.altitude() immediately reads pressure again internally. That means pressure and alt may come from different measurements (and adds extra I2C traffic). Consider computing altitude from the already-read pressure (e.g., an altitude_from_pressure(pressure_hpa) helper or allowing altitude(pressure_hpa=...)), so all fields in the same row are consistent.
There was a problem hiding this comment.
Fixed in e920a67: weather_station.py now passes the already-read pressure to sensor.altitude(pressure_hpa=pressure), ensuring consistency between all fields in the same row.
| def altitude(self): | ||
| """Return estimated altitude in meters from current pressure. | ||
|
|
||
| Uses the ICAO barometric formula with ``sea_level_pressure`` as | ||
| reference (default 1013.25 hPa, adjustable). | ||
| """ | ||
| p = self.pressure_hpa() |
There was a problem hiding this comment.
altitude() always calls pressure_hpa(), which forces an additional burst read (and may trigger a new measurement in sleep mode). This makes it hard to compute altitude from an already-fetched pressure value and can lead to inconsistent multi-field reads. Consider adding an optional pressure_hpa parameter (or a separate altitude_from_pressure() method) so callers can avoid redundant I2C reads and ensure consistent sampling.
| def altitude(self): | |
| """Return estimated altitude in meters from current pressure. | |
| Uses the ICAO barometric formula with ``sea_level_pressure`` as | |
| reference (default 1013.25 hPa, adjustable). | |
| """ | |
| p = self.pressure_hpa() | |
| def altitude(self, pressure_hpa=None): | |
| """Return estimated altitude in meters from current pressure. | |
| Uses the ICAO barometric formula with ``sea_level_pressure`` as | |
| reference (default 1013.25 hPa, adjustable). | |
| If ``pressure_hpa`` is provided, it is used directly; otherwise a new | |
| pressure reading is obtained via :meth:`pressure_hpa`. | |
| """ | |
| p = self.pressure_hpa() if pressure_hpa is None else pressure_hpa |
There was a problem hiding this comment.
Fixed in e920a67: altitude() now accepts an optional pressure_hpa parameter. When provided, it skips the I2C read and uses the given value directly.
| p = self.pressure_hpa() | ||
| return 44330.0 * (1.0 - (p / self.sea_level_pressure) ** 0.1903) |
There was a problem hiding this comment.
sea_level_pressure is user-adjustable and used as a divisor in altitude(). If it’s set to 0 or a negative value, altitude() will raise (or return nonsensical results). Add validation (e.g., require a positive float) and raise a clear ValueError when the value is invalid.
| p = self.pressure_hpa() | |
| return 44330.0 * (1.0 - (p / self.sea_level_pressure) ** 0.1903) | |
| slp = getattr(self, "sea_level_pressure", None) | |
| try: | |
| if slp is None or slp <= 0: | |
| raise ValueError( | |
| "sea_level_pressure must be a positive float, got: {!r}".format(slp) | |
| ) | |
| except TypeError: | |
| raise ValueError( | |
| "sea_level_pressure must be a positive float, got: {!r}".format(slp) | |
| ) | |
| p = self.pressure_hpa() | |
| return 44330.0 * (1.0 - (p / slp) ** 0.1903) |
There was a problem hiding this comment.
Not addressed: this is an internal attribute, not user input from an external boundary. The project convention is to only validate at system boundaries (user input, external APIs), not internal driver state. Adding defensive validation here would be inconsistent with the rest of the codebase.
| def __init__(self, i2c, address=BME280_I2C_DEFAULT_ADDR): | ||
| self.i2c = i2c | ||
| self.address = address | ||
| self.sea_level_pressure = 1013.25 |
There was a problem hiding this comment.
The new public attribute name sea_level_pressure doesn’t encode its units, while the rest of the public API does (e.g., pressure_hpa(), read() returns pressure_hpa). To avoid user confusion (Pa vs hPa), consider renaming to sea_level_pressure_hpa or providing a documented property with unit in its name.
There was a problem hiding this comment.
Fixed in e920a67: renamed to sea_level_pressure_hpa for consistency with the rest of the API (pressure_hpa(), etc.).
0fdcea3 to
f6e3831
Compare
# [0.8.0](v0.7.0...v0.8.0) (2026-03-30) ### Features * **bme280:** Add altitude computation and sea-level pressure ([#321](#321)) ([43625d9](43625d9))
|
🎉 This PR is included in version 0.8.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
Closes #315
Summary
sea_level_pressureattribute: initialized to 1013.25 hPa, user-adjustable for local conditionsaltitude()method: estimates altitude in meters using the ICAO barometric formula44330 * (1 - (P/P0)^0.1903)— same formula used by robert-hh, Adafruit, and Pimoroniweather_station.pyupdated: usessensor.altitude()instead of a localaltitude_m()function; sea-level pressure configured viasensor.sea_level_pressureTest plan
make test-bme280)