From f6e383116c5d647ab2f8c61509638f170edf53f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NEDJAR?= Date: Sun, 29 Mar 2026 21:18:21 +0200 Subject: [PATCH 1/2] feat(bme280): Add altitude computation and sea-level pressure reference. --- lib/bme280/README.md | 20 +++++++++++-- lib/bme280/bme280/device.py | 10 +++++++ lib/bme280/examples/weather_station.py | 16 ++++------- tests/scenarios/bme280.yaml | 40 ++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/lib/bme280/README.md b/lib/bme280/README.md index ab85c9be..d3aa1092 100644 --- a/lib/bme280/README.md +++ b/lib/bme280/README.md @@ -163,6 +163,22 @@ Triggers a single forced measurement. Poll `data_ready()` for completion, then r --- +### Altitude + +```python +alt = sensor.altitude() +``` + +Returns the estimated altitude in **meters** using the ICAO barometric formula. + +The computation uses `sea_level_pressure` as reference (default: 1013.25 hPa). Adjust it for your location: + +```python +sensor.sea_level_pressure = 1020.0 # local sea-level pressure in hPa +``` + +--- + ## Data-Ready Status ```python @@ -288,8 +304,8 @@ Performs a soft reset, re-reads calibration data, and re-applies default configu | Oversampling (per channel) | ✅ | ✅ | ✅ | ✅ | ⚠️ Fixed x16 | ⚠️ Constants only | | IIR filter | ✅ | ❌ | ✅ | ✅ | ⚠️ Fixed x16 | ❌ | | Standby time | ✅ | ❌ | ✅ | ❌ | ⚠️ Fixed 500ms | ❌ | -| Altitude | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | -| Sea-level pressure | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | +| Altitude | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | +| Sea-level pressure | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | | Dew point | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | | Soft reset | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | | Full reset + recalibration | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | diff --git a/lib/bme280/bme280/device.py b/lib/bme280/bme280/device.py index 7ec28c83..480a97f7 100644 --- a/lib/bme280/bme280/device.py +++ b/lib/bme280/bme280/device.py @@ -39,6 +39,7 @@ class BME280(object): def __init__(self, i2c, address=BME280_I2C_DEFAULT_ADDR): self.i2c = i2c self.address = address + self.sea_level_pressure = 1013.25 self._check_device() self._wait_boot() self._read_calibration() @@ -395,3 +396,12 @@ def read_one_shot(self): press_hpa = self._compensate_pressure(raw_press) / 25600.0 hum_rh = self._compensate_humidity(raw_hum) / 1024.0 return temp_c, press_hpa, hum_rh + + 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() + return 44330.0 * (1.0 - (p / self.sea_level_pressure) ** 0.1903) diff --git a/lib/bme280/examples/weather_station.py b/lib/bme280/examples/weather_station.py index acfb7aa9..ed03e89e 100644 --- a/lib/bme280/examples/weather_station.py +++ b/lib/bme280/examples/weather_station.py @@ -1,7 +1,7 @@ """Continuous weather monitoring with altitude estimation. Reads temperature, pressure, and humidity every 5 seconds in normal mode, -computes approximate altitude from pressure using the barometric formula, +computes altitude using the driver's built-in barometric formula, and logs each measurement to the DAPLink flash as CSV. """ @@ -13,15 +13,15 @@ from daplink_flash import DaplinkFlash from machine import I2C -# Sea-level reference pressure in hPa (adjust to local conditions) -SEA_LEVEL_PRESSURE = 1013.25 - i2c = I2C(1) sensor = BME280(i2c) bridge = DaplinkBridge(i2c) flash = DaplinkFlash(bridge) +# Adjust sea-level pressure to local conditions for accurate altitude +# sensor.sea_level_pressure = 1020.0 + # Configure for weather monitoring: high pressure resolution, moderate temp/hum sensor.set_oversampling(temperature=OSRS_X2, pressure=OSRS_X16, humidity=OSRS_X2) sensor.set_iir_filter(FILTER_16) @@ -35,15 +35,9 @@ flash.write_line("temperature;pressure;humidity;altitude") - -def altitude_m(pressure_hpa): - """Estimate altitude in meters from pressure using the barometric formula.""" - return 44330.0 * (1.0 - (pressure_hpa / SEA_LEVEL_PRESSURE) ** 0.1903) - - while True: temperature, pressure, humidity = sensor.read() - alt = altitude_m(pressure) + alt = sensor.altitude() print( "T: {:.1f} C P: {:.1f} hPa H: {:.1f} %RH Alt: {:.0f} m".format( diff --git a/tests/scenarios/bme280.yaml b/tests/scenarios/bme280.yaml index b39b2cea..a371adba 100644 --- a/tests/scenarios/bme280.yaml +++ b/tests/scenarios/bme280.yaml @@ -581,3 +581,43 @@ tests: result = len(forced_writes) == 1 and abs(t - 25.08) < 0.1 expect_true: true mode: [mock] + + # ----- Altitude ----- + + - name: "Default sea_level_pressure is 1013.25" + action: script + script: | + result = dev.sea_level_pressure == 1013.25 + expect_true: true + mode: [mock] + + - name: "altitude() returns plausible value with default reference" + action: script + script: | + alt = dev.altitude() + # Mock pressure ~1009.21 hPa → altitude ~33.7 m at 1013.25 hPa reference + result = abs(alt - 33.7) < 1.0 + expect_true: true + mode: [mock] + + - name: "altitude() uses custom sea_level_pressure" + action: script + script: | + dev.sea_level_pressure = 1020.0 + alt = dev.altitude() + # Mock pressure ~1009.21 hPa → altitude ~89.6 m at 1020.0 hPa reference + result = abs(alt - 89.6) < 1.0 + dev.sea_level_pressure = 1013.25 + expect_true: true + mode: [mock] + + - name: "altitude() returns zero when pressure equals reference" + action: script + script: | + # Set reference to match actual pressure so altitude should be ~0 + dev.sea_level_pressure = dev.pressure_hpa() + alt = dev.altitude() + result = abs(alt) < 0.5 + dev.sea_level_pressure = 1013.25 + expect_true: true + mode: [mock] From e920a67806b067b6411f6771f90c12ad6c6f5f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NEDJAR?= Date: Mon, 30 Mar 2026 11:55:28 +0200 Subject: [PATCH 2/2] fix(bme280): Address Copilot review on altitude API. --- lib/bme280/README.md | 11 +++++++++-- lib/bme280/bme280/device.py | 18 +++++++++++------- lib/bme280/examples/weather_station.py | 4 ++-- tests/scenarios/bme280.yaml | 23 ++++++++++++++++------- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/bme280/README.md b/lib/bme280/README.md index d3aa1092..5b91f94f 100644 --- a/lib/bme280/README.md +++ b/lib/bme280/README.md @@ -171,10 +171,17 @@ alt = sensor.altitude() Returns the estimated altitude in **meters** using the ICAO barometric formula. -The computation uses `sea_level_pressure` as reference (default: 1013.25 hPa). Adjust it for your location: +You can also pass an already-read pressure value to avoid a redundant I2C read: ```python -sensor.sea_level_pressure = 1020.0 # local sea-level pressure in hPa +temperature, pressure, humidity = sensor.read() +alt = sensor.altitude(pressure_hpa=pressure) +``` + +The computation uses `sea_level_pressure_hpa` as reference (default: 1013.25 hPa). Adjust it for your location: + +```python +sensor.sea_level_pressure_hpa = 1020.0 ``` --- diff --git a/lib/bme280/bme280/device.py b/lib/bme280/bme280/device.py index 480a97f7..a0108e07 100644 --- a/lib/bme280/bme280/device.py +++ b/lib/bme280/bme280/device.py @@ -39,7 +39,7 @@ class BME280(object): def __init__(self, i2c, address=BME280_I2C_DEFAULT_ADDR): self.i2c = i2c self.address = address - self.sea_level_pressure = 1013.25 + self.sea_level_pressure_hpa = 1013.25 self._check_device() self._wait_boot() self._read_calibration() @@ -397,11 +397,15 @@ def read_one_shot(self): hum_rh = self._compensate_humidity(raw_hum) / 1024.0 return temp_c, press_hpa, hum_rh - def altitude(self): - """Return estimated altitude in meters from current pressure. + def altitude(self, pressure_hpa=None): + """Return estimated altitude in meters. - Uses the ICAO barometric formula with ``sea_level_pressure`` as - reference (default 1013.25 hPa, adjustable). + Uses the ICAO barometric formula with ``sea_level_pressure_hpa`` + as reference (default 1013.25 hPa, adjustable). + + Args: + pressure_hpa: pressure in hPa. If None, a new reading is taken + via :meth:`pressure_hpa`. """ - p = self.pressure_hpa() - return 44330.0 * (1.0 - (p / self.sea_level_pressure) ** 0.1903) + p = self.pressure_hpa() if pressure_hpa is None else pressure_hpa + return 44330.0 * (1.0 - (p / self.sea_level_pressure_hpa) ** 0.1903) diff --git a/lib/bme280/examples/weather_station.py b/lib/bme280/examples/weather_station.py index ed03e89e..a83e24ef 100644 --- a/lib/bme280/examples/weather_station.py +++ b/lib/bme280/examples/weather_station.py @@ -20,7 +20,7 @@ flash = DaplinkFlash(bridge) # Adjust sea-level pressure to local conditions for accurate altitude -# sensor.sea_level_pressure = 1020.0 +# sensor.sea_level_pressure_hpa = 1020.0 # Configure for weather monitoring: high pressure resolution, moderate temp/hum sensor.set_oversampling(temperature=OSRS_X2, pressure=OSRS_X16, humidity=OSRS_X2) @@ -37,7 +37,7 @@ while True: temperature, pressure, humidity = sensor.read() - alt = sensor.altitude() + alt = sensor.altitude(pressure_hpa=pressure) print( "T: {:.1f} C P: {:.1f} hPa H: {:.1f} %RH Alt: {:.0f} m".format( diff --git a/tests/scenarios/bme280.yaml b/tests/scenarios/bme280.yaml index a371adba..fca42d32 100644 --- a/tests/scenarios/bme280.yaml +++ b/tests/scenarios/bme280.yaml @@ -584,10 +584,10 @@ tests: # ----- Altitude ----- - - name: "Default sea_level_pressure is 1013.25" + - name: "Default sea_level_pressure_hpa is 1013.25" action: script script: | - result = dev.sea_level_pressure == 1013.25 + result = dev.sea_level_pressure_hpa == 1013.25 expect_true: true mode: [mock] @@ -600,14 +600,14 @@ tests: expect_true: true mode: [mock] - - name: "altitude() uses custom sea_level_pressure" + - name: "altitude() uses custom sea_level_pressure_hpa" action: script script: | - dev.sea_level_pressure = 1020.0 + dev.sea_level_pressure_hpa = 1020.0 alt = dev.altitude() # Mock pressure ~1009.21 hPa → altitude ~89.6 m at 1020.0 hPa reference result = abs(alt - 89.6) < 1.0 - dev.sea_level_pressure = 1013.25 + dev.sea_level_pressure_hpa = 1013.25 expect_true: true mode: [mock] @@ -615,9 +615,18 @@ tests: action: script script: | # Set reference to match actual pressure so altitude should be ~0 - dev.sea_level_pressure = dev.pressure_hpa() + dev.sea_level_pressure_hpa = dev.pressure_hpa() alt = dev.altitude() result = abs(alt) < 0.5 - dev.sea_level_pressure = 1013.25 + dev.sea_level_pressure_hpa = 1013.25 + expect_true: true + mode: [mock] + + - name: "altitude() accepts pressure_hpa parameter" + action: script + script: | + # Pass pressure directly to avoid redundant I2C read + alt = dev.altitude(pressure_hpa=1009.21) + result = abs(alt - 33.7) < 1.0 expect_true: true mode: [mock]