|
| 1 | +from time import sleep_ms |
| 2 | + |
| 3 | +from bme280.const import ( |
| 4 | + BME280_CHIP_ID, |
| 5 | + BME280_I2C_DEFAULT_ADDR, |
| 6 | + MODE_SLEEP, |
| 7 | + OSRS_P_SHIFT, |
| 8 | + OSRS_T_SHIFT, |
| 9 | + OSRS_X1, |
| 10 | + REG_CHIP_ID, |
| 11 | + REG_CTRL_HUM, |
| 12 | + REG_CTRL_MEAS, |
| 13 | + REG_SOFT_RESET, |
| 14 | + REG_STATUS, |
| 15 | + RESET_DELAY_MS, |
| 16 | + SOFT_RESET_CMD, |
| 17 | + STATUS_IM_UPDATE, |
| 18 | +) |
| 19 | +from bme280.exceptions import BME280InvalidDevice, BME280NotFound |
| 20 | + |
| 21 | + |
| 22 | +class BME280(object): |
| 23 | + """MicroPython driver for the Bosch BME280 temperature, humidity, and pressure sensor.""" |
| 24 | + |
| 25 | + def __init__(self, i2c, address=BME280_I2C_DEFAULT_ADDR): |
| 26 | + self.i2c = i2c |
| 27 | + self.address = address |
| 28 | + self._check_device() |
| 29 | + self._configure_default() |
| 30 | + |
| 31 | + # -------------------------------------------------- |
| 32 | + # Low level I2C |
| 33 | + # -------------------------------------------------- |
| 34 | + |
| 35 | + def _read_reg(self, reg): |
| 36 | + """Read a single byte from register.""" |
| 37 | + return self.i2c.readfrom_mem(self.address, reg, 1)[0] |
| 38 | + |
| 39 | + def _read_block(self, reg, length): |
| 40 | + """Read a block of bytes from consecutive registers.""" |
| 41 | + return self.i2c.readfrom_mem(self.address, reg, length) |
| 42 | + |
| 43 | + def _write_reg(self, reg, value): |
| 44 | + """Write a single byte to register.""" |
| 45 | + self.i2c.writeto_mem(self.address, reg, bytes([value])) |
| 46 | + |
| 47 | + # -------------------------------------------------- |
| 48 | + # Device identification and initialization |
| 49 | + # -------------------------------------------------- |
| 50 | + |
| 51 | + def _check_device(self): |
| 52 | + """Verify device presence and ID.""" |
| 53 | + try: |
| 54 | + chip_id = self.device_id() |
| 55 | + except OSError as err: |
| 56 | + raise BME280NotFound( |
| 57 | + "BME280 not found at address 0x{:02X}".format(self.address) |
| 58 | + ) from err |
| 59 | + if chip_id != BME280_CHIP_ID: |
| 60 | + raise BME280InvalidDevice( |
| 61 | + "Expected chip ID 0x{:02X}, got 0x{:02X}".format(BME280_CHIP_ID, chip_id) |
| 62 | + ) |
| 63 | + |
| 64 | + def _configure_default(self): |
| 65 | + """Apply default configuration after reset.""" |
| 66 | + # Wait for NVM copy to complete |
| 67 | + self._wait_boot() |
| 68 | + # Set humidity oversampling (must be written before ctrl_meas) |
| 69 | + self._write_reg(REG_CTRL_HUM, OSRS_X1) |
| 70 | + # Set temperature and pressure oversampling, sleep mode |
| 71 | + self._write_reg( |
| 72 | + REG_CTRL_MEAS, |
| 73 | + (OSRS_X1 << OSRS_T_SHIFT) | (OSRS_X1 << OSRS_P_SHIFT) | MODE_SLEEP, |
| 74 | + ) |
| 75 | + |
| 76 | + def _wait_boot(self, timeout_ms=50): |
| 77 | + """Wait for NVM data copy to complete.""" |
| 78 | + for _ in range(timeout_ms // 5): |
| 79 | + if not (self._read_reg(REG_STATUS) & STATUS_IM_UPDATE): |
| 80 | + return |
| 81 | + sleep_ms(5) |
| 82 | + |
| 83 | + def device_id(self): |
| 84 | + """Read chip ID register. Expected: 0x60.""" |
| 85 | + return self._read_reg(REG_CHIP_ID) |
| 86 | + |
| 87 | + def soft_reset(self): |
| 88 | + """Perform a soft reset. Device returns to power-on defaults.""" |
| 89 | + self._write_reg(REG_SOFT_RESET, SOFT_RESET_CMD) |
| 90 | + sleep_ms(RESET_DELAY_MS) |
| 91 | + self._wait_boot() |
| 92 | + |
| 93 | + def reset(self): |
| 94 | + """Reset and reconfigure.""" |
| 95 | + self.soft_reset() |
| 96 | + self._configure_default() |
0 commit comments