Pico with BME280 breakout (via Explorer Base and MicroPython)

Not quite sure the best place to put this but I’ve been able to communicate with the BME280 breakout board using the Pico and MicroPython though my code still needs more work it might help people communicate with more breakout boards or finish the bme280 calibration calculations part which is missing from mine:

from machine import Pin, I2C
from micropython import const
from time import sleep

_ADDR = const(0x76)

_CALIB2 = const(0xe1)
_CALIB1 = const(0x88)
_DATA = const(0xf7)
_CONFIG = const(0xf5)
_CTRL_MEAS = const(0xf4)
_CTRL_HUM = const(0xf2)
_CHIP_ID = const(0xd0)
_RESET = const(0xe0)

class TooManyAttempts(Exception):
“”“Too many attempts”""

class BME280:
def init(self, i2c):
self._i2c = i2c
self._ready = bytearray(1)
self._chip_id = bytearray(1)
self._data = bytearray(8)
self._calib1 = bytearray(26)
self._calib2 = bytearray(7)

def ready(self):
    attempts = 100
    while True:
        self._i2c.readfrom_into(_ADDR, self._ready)
        if self._ready == b'\x00':
            break
        attempts -= 1
        if not attempts:
            raise TooManyAttempts()

def chip_id(self):
    self.ready()
    self._i2c.readfrom_mem_into(_ADDR, _CHIP_ID, self._chip_id)
    return self._chip_id

def reset(self):
    self.ready()
    self._i2c.writeto_mem(_ADDR, _RESET, b'\xb6')
    
def ctrl_hum(self, osrs_h=16):
    self.ready()
    self._i2c.writeto_mem(_ADDR, _CTRL_HUM, chr(0b101))
    
def ctrl_meas(self, osrs_t=16, osrs_p=16, mode='normal'):
    self.ready()
    self._i2c.writeto_mem(_ADDR, _CTRL_MEAS, chr(0b10110111))
    
def config(self, t_sb=500, filter=2):
    self.ready()
    self._i2c.writeto_mem(_ADDR, _CONFIG, chr(0b10001000))
    
def data(self):
    self.ready()
    self._i2c.readfrom_mem_into(_ADDR, _DATA, self._data)
    return self._data

def calibration(self):
    self.ready()
    self._i2c.readfrom_mem_into(_ADDR, _CALIB1, self._calib1)
    self.ready()
    self._i2c.readfrom_mem_into(_ADDR, _CALIB2, self._calib2)

def init(self):
    self.reset()
    sleep(0.1)
    self.ctrl_hum()
    self.ctrl_meas()
    self.config()
    self.calibration()

bme280 = BME280(I2C(0, scl=Pin(21), sda=Pin(20)))
print(bme280.chip_id())

Great news that somebody is looking into this.
You may find these useful
GitHub - robert-hh/BME280: Micropython driver for the BME280 sensor, target platform Pycom devices

Thanks so much for this. When I didn’t see one in the pimoroni repo I assumed I’d have to write my own! Forced me to learn about MicroPython though.

Hope you manage to get it working. Please post when you do.
Beyond my current skills at the moment but I need a MicroPython driver for this sensor.
I think Raspberry Pi Pico team should be putting some effort into the MicroPython libraries for the most common sensors or most users will soon get fed up with just flashing LEDs and reading buttons and use CircuitPython which does not need a Pico!

from machine import Pin, I2C
from micropython import const
from time import sleep
import ustruct

_ADDR = const(0x76)

_CALIB2 = const(0xE1)
_CALIB1 = const(0x88)
_DATA = const(0xF7)
_CONFIG = const(0xF5)
_CTRL_MEAS = const(0xF4)
_CTRL_HUM = const(0xF2)
_CHIP_ID = const(0xD0)
_RESET = const(0xE0)


class TooManyAttempts(Exception):
    """Too many attempts"""


class BME280:
    def __init__(self, i2c):
        self._i2c = i2c
        self._ready = bytearray(1)
        self._chip_id = bytearray(1)
        self._data = bytearray(8)
        self._calib1 = bytearray(26)
        self._calib2 = bytearray(7)

    def ready(self):
        attempts = 100
        while True:
            self._i2c.readfrom_into(_ADDR, self._ready)
            if self._ready == b"\x00":
                break
            attempts -= 1
            if not attempts:
                raise TooManyAttempts()

    def chip_id(self):
        self.ready()
        self._i2c.readfrom_mem_into(_ADDR, _CHIP_ID, self._chip_id)
        return self._chip_id

    def reset(self):
        self.ready()
        self._i2c.writeto_mem(_ADDR, _RESET, b"\xb6")

    def ctrl_hum(self, osrs_h=16):
        self.ready()
        self._i2c.writeto_mem(_ADDR, _CTRL_HUM, chr(0b101))

    def ctrl_meas(self, osrs_t=16, osrs_p=16, mode="normal"):
        self.ready()
        self._i2c.writeto_mem(_ADDR, _CTRL_MEAS, chr(0b10110111))

    def config(self, t_sb=500, filter=2):
        self.ready()
        self._i2c.writeto_mem(_ADDR, _CONFIG, chr(0b10001000))

    def data(self):
        self.ready()
        self._i2c.readfrom_mem_into(_ADDR, _DATA, self._data)

    @property
    def raw_pressure(self):
        data = self._data
        return (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)

    @property
    def raw_temperature(self):
        data = self._data
        return (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)

    @property
    def raw_humidity(self):
        data = self._data
        return (data[6] << 8) | data[7]

    @property
    def temperature(self):
        temp_raw = self.raw_temperature
        dig_T1, dig_T2, dig_T3 = self._calib[:3]
        var1 = ((((temp_raw >> 3) - (dig_T1 << 1))) * (dig_T2)) >> 11
        var2 = (
            ((((temp_raw >> 4) - (dig_T1)) * ((temp_raw >> 4) - (dig_T1))) >> 12)
            * (dig_T3)
        ) >> 14
        t_fine = var1 + var2
        return float(((t_fine * 5) + 128) >> 8) / 100.0

    def calibration(self):
        self.ready()
        self._i2c.readfrom_mem_into(_ADDR, _CALIB1, self._calib1)
        self.ready()
        self._i2c.readfrom_mem_into(_ADDR, _CALIB2, self._calib2)
        self._calib = ustruct.unpack("HhhHhhhhhhhhBb", self._calib1) + ustruct.unpack(
            "hBbbbB", self._calib2
        )

    def init(self):
        self.reset()
        sleep(0.1)
        self.ctrl_hum()
        self.ctrl_meas()
        self.config()
        self.calibration()


bme280 = BME280(I2C(0, scl=Pin(21), sda=Pin(20)))
print(bme280.chip_id())
bme280.init()

then

bme280.data() refreshes the data and bme280.temperature is a float containing the current temperature.

My temperature calibration code is from MattHawkinsUK/rpispy-misc which is using bit shifting whereas the pimoroni code at pimoroni/bme280-python seems to be doing lots of floating point maths.