Skip to content

Commit 43625d9

Browse files
authored
feat(bme280): Add altitude computation and sea-level pressure (#321)
* feat(bme280): Add altitude computation and sea-level pressure reference. * fix(bme280): Address Copilot review on altitude API.
1 parent 70a515c commit 43625d9

4 files changed

Lines changed: 93 additions & 13 deletions

File tree

lib/bme280/README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,29 @@ Triggers a single forced measurement. Poll `data_ready()` for completion, then r
163163

164164
---
165165

166+
### Altitude
167+
168+
```python
169+
alt = sensor.altitude()
170+
```
171+
172+
Returns the estimated altitude in **meters** using the ICAO barometric formula.
173+
174+
You can also pass an already-read pressure value to avoid a redundant I2C read:
175+
176+
```python
177+
temperature, pressure, humidity = sensor.read()
178+
alt = sensor.altitude(pressure_hpa=pressure)
179+
```
180+
181+
The computation uses `sea_level_pressure_hpa` as reference (default: 1013.25 hPa). Adjust it for your location:
182+
183+
```python
184+
sensor.sea_level_pressure_hpa = 1020.0
185+
```
186+
187+
---
188+
166189
## Data-Ready Status
167190

168191
```python
@@ -288,8 +311,8 @@ Performs a soft reset, re-reads calibration data, and re-applies default configu
288311
| Oversampling (per channel) ||||| ⚠️ Fixed x16 | ⚠️ Constants only |
289312
| IIR filter ||||| ⚠️ Fixed x16 ||
290313
| Standby time ||||| ⚠️ Fixed 500ms ||
291-
| Altitude | ||||||
292-
| Sea-level pressure | ||||||
314+
| Altitude | ||||||
315+
| Sea-level pressure | ||||||
293316
| Dew point |||||||
294317
| Soft reset |||||||
295318
| Full reset + recalibration |||||||

lib/bme280/bme280/device.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class BME280(object):
3939
def __init__(self, i2c, address=BME280_I2C_DEFAULT_ADDR):
4040
self.i2c = i2c
4141
self.address = address
42+
self.sea_level_pressure_hpa = 1013.25
4243
self._check_device()
4344
self._wait_boot()
4445
self._read_calibration()
@@ -395,3 +396,16 @@ def read_one_shot(self):
395396
press_hpa = self._compensate_pressure(raw_press) / 25600.0
396397
hum_rh = self._compensate_humidity(raw_hum) / 1024.0
397398
return temp_c, press_hpa, hum_rh
399+
400+
def altitude(self, pressure_hpa=None):
401+
"""Return estimated altitude in meters.
402+
403+
Uses the ICAO barometric formula with ``sea_level_pressure_hpa``
404+
as reference (default 1013.25 hPa, adjustable).
405+
406+
Args:
407+
pressure_hpa: pressure in hPa. If None, a new reading is taken
408+
via :meth:`pressure_hpa`.
409+
"""
410+
p = self.pressure_hpa() if pressure_hpa is None else pressure_hpa
411+
return 44330.0 * (1.0 - (p / self.sea_level_pressure_hpa) ** 0.1903)

lib/bme280/examples/weather_station.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Continuous weather monitoring with altitude estimation.
22
33
Reads temperature, pressure, and humidity every 5 seconds in normal mode,
4-
computes approximate altitude from pressure using the barometric formula,
4+
computes altitude using the driver's built-in barometric formula,
55
and logs each measurement to the DAPLink flash as CSV.
66
"""
77

@@ -13,15 +13,15 @@
1313
from daplink_flash import DaplinkFlash
1414
from machine import I2C
1515

16-
# Sea-level reference pressure in hPa (adjust to local conditions)
17-
SEA_LEVEL_PRESSURE = 1013.25
18-
1916
i2c = I2C(1)
2017

2118
sensor = BME280(i2c)
2219
bridge = DaplinkBridge(i2c)
2320
flash = DaplinkFlash(bridge)
2421

22+
# Adjust sea-level pressure to local conditions for accurate altitude
23+
# sensor.sea_level_pressure_hpa = 1020.0
24+
2525
# Configure for weather monitoring: high pressure resolution, moderate temp/hum
2626
sensor.set_oversampling(temperature=OSRS_X2, pressure=OSRS_X16, humidity=OSRS_X2)
2727
sensor.set_iir_filter(FILTER_16)
@@ -35,15 +35,9 @@
3535

3636
flash.write_line("temperature;pressure;humidity;altitude")
3737

38-
39-
def altitude_m(pressure_hpa):
40-
"""Estimate altitude in meters from pressure using the barometric formula."""
41-
return 44330.0 * (1.0 - (pressure_hpa / SEA_LEVEL_PRESSURE) ** 0.1903)
42-
43-
4438
while True:
4539
temperature, pressure, humidity = sensor.read()
46-
alt = altitude_m(pressure)
40+
alt = sensor.altitude(pressure_hpa=pressure)
4741

4842
print(
4943
"T: {:.1f} C P: {:.1f} hPa H: {:.1f} %RH Alt: {:.0f} m".format(

tests/scenarios/bme280.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,52 @@ tests:
581581
result = len(forced_writes) == 1 and abs(t - 25.08) < 0.1
582582
expect_true: true
583583
mode: [mock]
584+
585+
# ----- Altitude -----
586+
587+
- name: "Default sea_level_pressure_hpa is 1013.25"
588+
action: script
589+
script: |
590+
result = dev.sea_level_pressure_hpa == 1013.25
591+
expect_true: true
592+
mode: [mock]
593+
594+
- name: "altitude() returns plausible value with default reference"
595+
action: script
596+
script: |
597+
alt = dev.altitude()
598+
# Mock pressure ~1009.21 hPa → altitude ~33.7 m at 1013.25 hPa reference
599+
result = abs(alt - 33.7) < 1.0
600+
expect_true: true
601+
mode: [mock]
602+
603+
- name: "altitude() uses custom sea_level_pressure_hpa"
604+
action: script
605+
script: |
606+
dev.sea_level_pressure_hpa = 1020.0
607+
alt = dev.altitude()
608+
# Mock pressure ~1009.21 hPa → altitude ~89.6 m at 1020.0 hPa reference
609+
result = abs(alt - 89.6) < 1.0
610+
dev.sea_level_pressure_hpa = 1013.25
611+
expect_true: true
612+
mode: [mock]
613+
614+
- name: "altitude() returns zero when pressure equals reference"
615+
action: script
616+
script: |
617+
# Set reference to match actual pressure so altitude should be ~0
618+
dev.sea_level_pressure_hpa = dev.pressure_hpa()
619+
alt = dev.altitude()
620+
result = abs(alt) < 0.5
621+
dev.sea_level_pressure_hpa = 1013.25
622+
expect_true: true
623+
mode: [mock]
624+
625+
- name: "altitude() accepts pressure_hpa parameter"
626+
action: script
627+
script: |
628+
# Pass pressure directly to avoid redundant I2C read
629+
alt = dev.altitude(pressure_hpa=1009.21)
630+
result = abs(alt - 33.7) < 1.0
631+
expect_true: true
632+
mode: [mock]

0 commit comments

Comments
 (0)