-
Notifications
You must be signed in to change notification settings - Fork 1
feat(bme280): Implement _ensure_data() auto-trigger pattern #318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,7 @@ | |
| STATUS_IM_UPDATE, | ||
| STATUS_MEASURING, | ||
| ) | ||
| from bme280.exceptions import BME280Error, BME280InvalidDevice, BME280NotFound | ||
| from bme280.exceptions import BME280InvalidDevice, BME280NotFound | ||
|
|
||
|
|
||
| class BME280(object): | ||
|
|
@@ -125,7 +125,7 @@ def _wait_boot(self, timeout_ms=50): | |
| if not (self._read_reg(REG_STATUS) & STATUS_IM_UPDATE): | ||
| return | ||
| sleep_ms(5) | ||
| raise BME280Error("BME280 NVM copy timeout") | ||
| raise OSError("BME280 NVM copy timeout") | ||
|
|
||
| def device_id(self): | ||
| """Read chip ID register. Expected: 0x60.""" | ||
|
|
@@ -239,6 +239,21 @@ def humidity_ready(self): | |
| # Forced measurement trigger | ||
| # -------------------------------------------------- | ||
|
|
||
| def _is_sleep_mode(self): | ||
| """Return True if the sensor is in sleep mode.""" | ||
| return (self._read_reg(REG_CTRL_MEAS) & MODE_MASK) == MODE_SLEEP | ||
|
|
||
| def _ensure_data(self): | ||
| """Trigger a forced measurement if the sensor is in sleep mode. | ||
|
|
||
| In normal mode this is a no-op. In sleep mode it triggers a | ||
| single conversion and waits for completion so that subsequent | ||
| register reads return fresh data. | ||
| """ | ||
| if self._is_sleep_mode(): | ||
| self.trigger_one_shot() | ||
| self._wait_measurement() | ||
|
|
||
| def trigger_one_shot(self): | ||
| """Trigger a single forced measurement. Poll data_ready() for completion.""" | ||
| ctrl = self._read_reg(REG_CTRL_MEAS) | ||
|
|
@@ -250,7 +265,7 @@ def _wait_measurement(self, timeout_ms=100): | |
| if self.data_ready(): | ||
| return | ||
| sleep_ms(5) | ||
| raise BME280Error("BME280 measurement timeout") | ||
| raise OSError("BME280 measurement timeout") | ||
|
|
||
| # -------------------------------------------------- | ||
| # Raw data burst read | ||
|
|
@@ -323,32 +338,60 @@ def _compensate_humidity(self, raw_hum): | |
| # -------------------------------------------------- | ||
|
|
||
| def temperature(self): | ||
| """Return compensated temperature in °C (float).""" | ||
| """Return compensated temperature in °C (float). | ||
|
|
||
| If the sensor is in sleep mode, a forced measurement is triggered | ||
| automatically before reading. | ||
| """ | ||
| self._ensure_data() | ||
| raw_temp, _, _ = self._read_raw() | ||
| return self._compensate_temperature(raw_temp) / 100.0 | ||
|
|
||
| def pressure_hpa(self): | ||
| """Return compensated pressure in hPa (float).""" | ||
| """Return compensated pressure in hPa (float). | ||
|
|
||
| If the sensor is in sleep mode, a forced measurement is triggered | ||
| automatically before reading. | ||
| """ | ||
| self._ensure_data() | ||
| raw_temp, raw_press, _ = self._read_raw() | ||
| self._compensate_temperature(raw_temp) | ||
| return self._compensate_pressure(raw_press) / 25600.0 | ||
|
|
||
| def humidity(self): | ||
| """Return compensated relative humidity in %RH (float).""" | ||
| """Return compensated relative humidity in %RH (float). | ||
|
|
||
| If the sensor is in sleep mode, a forced measurement is triggered | ||
| automatically before reading. | ||
| """ | ||
| self._ensure_data() | ||
| raw_temp, _, raw_hum = self._read_raw() | ||
| self._compensate_temperature(raw_temp) | ||
| return self._compensate_humidity(raw_hum) / 1024.0 | ||
|
|
||
| def read(self): | ||
| """Return (temperature_c, pressure_hpa, humidity_rh) tuple.""" | ||
| """Return (temperature_c, pressure_hpa, humidity_rh) tuple. | ||
|
|
||
| If the sensor is in sleep mode, a forced measurement is triggered | ||
| automatically before reading. | ||
| """ | ||
| self._ensure_data() | ||
| raw_temp, raw_press, raw_hum = self._read_raw() | ||
|
Comment on lines
372
to
379
|
||
| temp_c = self._compensate_temperature(raw_temp) / 100.0 | ||
| 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 read_one_shot(self): | ||
| """Trigger a forced measurement, wait, and return (temp_c, press_hpa, hum_rh).""" | ||
| """Trigger a forced measurement, wait, and return (temp_c, press_hpa, hum_rh). | ||
|
|
||
| Reads registers directly without calling _ensure_data() to avoid | ||
| a double trigger (forced mode returns the sensor to sleep). | ||
| """ | ||
| self.trigger_one_shot() | ||
| self._wait_measurement() | ||
| return self.read() | ||
| raw_temp, raw_press, raw_hum = self._read_raw() | ||
| temp_c = self._compensate_temperature(raw_temp) / 100.0 | ||
| 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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_ensure_data() relies on _wait_measurement(), which currently raises BME280Error("BME280 measurement timeout"). The auto-trigger convention in issue #159 calls for raising OSError on timeout; as implemented, callers will see a driver-specific exception type instead. Consider changing the timeout exception to OSError (or making BME280Error inherit from OSError) so timeout handling is consistent with the convention across drivers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The project convention uses driver-specific exceptions (e.g.
WSENPADSTimeoutin wsen-pads,BME280Errorhere), all inheriting fromException, notOSError. This is consistent across all drivers in the repo. KeepingBME280Errorfor now to stay aligned.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You were right — fixed in 3e6fd4f. The convention from #44 is indeed
OSErrorfor timeouts, and 5 out of 7 drivers already follow it. I had incorrectly aligned with WSEN-PADS/WSEN-HIDS which are the two outliers. Created #319 to harmonize those two remaining drivers.