Making PiicoDev compatible with the Adafruit MCP2221A Breakout

I asked Claude to make PiicoDev_Unified.py compatible with the Adafruit MCP2221A Breakout and the fix was surprisingly simple.

Changes to PiicoDev_Unified.py involved a new I2C class to wrap the pre-instantiated SMBus compatible class provided by the Easy MCP2221 library, and an extra few lines of logic in the create_unified_i2c method.

I’ve tested it with the buzzer, aq, and atmospheric pressure sensors so far, and it seems to work fine.

Modified code if anyone’s interested.

class I2CUnifiedSMBus(I2CBase):
    """Wraps a pre-instantiated SMBus-compatible object (e.g. EasyMCP2221.SMBus)."""
    def __init__(self, bus):
        self.i2c = bus

    def writeto_mem(self, addr, memaddr, buf, *, addrsize=8):
        if addrsize == 8:
            self.i2c.write_i2c_block_data(addr, memaddr, list(buf))
        elif addrsize == 16:
            reg_high = (memaddr >> 8) & 0xFF
            reg_low = memaddr & 0xFF
            self.i2c.write_i2c_block_data(addr, reg_high, [reg_low] + list(buf))
        else:
            raise Exception('addrsize must be 8 or 16')

    def readfrom_mem(self, addr, memaddr, nbytes, *, addrsize=8):
        if addrsize == 8:
            return self.i2c.read_i2c_block_data(addr, memaddr, nbytes)
        elif addrsize == 16:
            reg_high = (memaddr >> 8) & 0xFF
            reg_low = memaddr & 0xFF
            return self.i2c.read_i2c_block_data(addr, reg_high, nbytes)
        else:
            raise Exception('addrsize must be 8 or 16')

    def write8(self, addr, reg, data):
        if reg is None:
            d = int.from_bytes(data, 'big')
            self.i2c.write_byte(addr, d)
        else:
            r = int.from_bytes(reg, 'big')
            d = int.from_bytes(data, 'big')
            self.i2c.write_byte_data(addr, r, d)

    def read16(self, addr, reg):
        regInt = int.from_bytes(reg, 'big')
        val = self.i2c.read_word_data(addr, regInt)
        return val.to_bytes(2, byteorder='little', signed=False)

    def scan(self):
        pass

def create_unified_i2c(bus=None, freq=None, sda=None, scl=None, suppress_warnings=True):
    if _SYSNAME == 'microbit':
        i2c = I2CUnifiedMicroBit(freq=freq)
    elif _SYSNAME == 'Linux':
        if bus is not None and not isinstance(bus, int):
            i2c = I2CUnifiedSMBus(bus)
        else:
            i2c = I2CUnifiedLinux(bus=bus, suppress_warnings=suppress_warnings)
    else:
        i2c = I2CUnifiedMachine(bus=bus, freq=freq, sda=sda, scl=scl)
    return i2c