or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-smbus2

A drop-in replacement for smbus-cffi/smbus-python in pure Python

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/smbus2@0.5.x

To install, run

npx @tessl/cli install tessl/pypi-smbus2@0.5.0

index.mddocs/

smbus2

A drop-in replacement for smbus-cffi/smbus-python in pure Python. smbus2 provides a complete implementation of the SMBus (System Management Bus) protocol for I2C communication, enabling comprehensive device interaction for embedded systems, IoT devices, and hardware interfacing applications.

Package Information

  • Package Name: smbus2
  • Language: Python
  • Installation: pip install smbus2

Core Imports

from smbus2 import SMBus, i2c_msg, I2cFunc

Individual component import:

from smbus2 import SMBus       # Main SMBus interface
from smbus2 import i2c_msg     # I2C message class for combined transactions
from smbus2 import I2cFunc     # I2C functionality flags enum

Basic Usage

from smbus2 import SMBus

# Basic usage with context manager (recommended)
with SMBus(1) as bus:
    # Read a byte from address 0x50, register 0x00
    data = bus.read_byte_data(0x50, 0x00)
    print(f"Read value: {data}")
    
    # Write a byte to address 0x50, register 0x00
    bus.write_byte_data(0x50, 0x00, 0xFF)

# Manual connection management
bus = SMBus(1)  # Open I2C bus 1
try:
    # Read word data from register
    word_data = bus.read_word_data(0x50, 0x10)
    print(f"Word data: {word_data}")
finally:
    bus.close()  # Always close the connection

# Enable Packet Error Checking (PEC)
with SMBus(1) as bus:
    bus.pec = 1  # Enable PEC
    data = bus.read_byte_data(0x50, 0x00)

Architecture

smbus2 is built on a layered architecture:

  • SMBus Class: High-level interface providing all standard SMBus operations
  • i2c_msg System: Low-level message system for combined I2C transactions beyond SMBus limitations
  • ctypes Integration: Direct interface to Linux I2C subsystem via ioctl calls
  • Pure Python Implementation: No external dependencies, compatible across Python versions

The library supports both traditional SMBus operations (limited to 32 bytes) and advanced I2C transactions (unlimited size) through the i2c_rdwr interface, making it suitable for both simple sensor communication and complex data transfer scenarios.

Capabilities

Connection Management

SMBus connection initialization, opening, and closing with support for context managers and manual resource management.

class SMBus:
    def __init__(self, bus=None, force=False):
        """
        Initialize SMBus instance.
        
        Parameters:
        - bus: int or str, I2C bus number (e.g. 1) or device path (e.g. '/dev/i2c-1')
        - force: bool, force using slave address even when driver is already using it
        """
    
    def __enter__(self):
        """Context manager entry, returns self."""
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit, closes connection."""
    
    def open(self, bus):
        """
        Open I2C bus connection.
        
        Parameters:
        - bus: int or str, I2C bus number or device path
        
        Raises:
        - TypeError: if bus type is not int or str
        """
    
    def close(self):
        """Close I2C connection."""

Basic SMBus Operations

Fundamental SMBus operations including quick commands and single byte read/write operations.

def write_quick(self, i2c_addr, force=None):
    """
    Perform SMBus Quick Command.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - force: bool, optional override for force flag
    
    Raises:
    - IOError: if operation fails
    """

def read_byte(self, i2c_addr, force=None):
    """
    Read single byte from I2C device.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - force: bool, optional override for force flag
    
    Returns:
    - int: byte value (0-255)
    """

def write_byte(self, i2c_addr, value, force=None):
    """
    Write single byte to I2C device.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - value: int, byte value to write (0-255)
    - force: bool, optional override for force flag
    """

Register-Based Operations

SMBus byte and word data operations for reading from and writing to specific device registers.

def read_byte_data(self, i2c_addr, register, force=None):
    """
    Read byte from specified register.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address (0-255)
    - force: bool, optional override for force flag
    
    Returns:
    - int: byte value from register
    """

def write_byte_data(self, i2c_addr, register, value, force=None):
    """
    Write byte to specified register.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address (0-255)
    - value: int, byte value to write (0-255)
    - force: bool, optional override for force flag
    """

def read_word_data(self, i2c_addr, register, force=None):
    """
    Read 16-bit word from specified register.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address (0-255)
    - force: bool, optional override for force flag
    
    Returns:
    - int: 16-bit word value from register
    """

def write_word_data(self, i2c_addr, register, value, force=None):
    """
    Write 16-bit word to specified register.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address (0-255)
    - value: int, 16-bit word value to write (0-65535)
    - force: bool, optional override for force flag
    """

Process Call Operations

SMBus Process Call operations for atomic write-then-read transactions.

def process_call(self, i2c_addr, register, value, force=None):
    """
    Execute SMBus Process Call (write 16-bit value, read 16-bit response).
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address
    - value: int, 16-bit value to send
    - force: bool, optional override for force flag
    
    Returns:
    - int: 16-bit response value
    """

def block_process_call(self, i2c_addr, register, data, force=None):
    """
    Execute SMBus Block Process Call (write block, read block response).
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, register address
    - data: list of int, data bytes to send (max 32 bytes)
    - force: bool, optional override for force flag
    
    Returns:
    - list of int: response data bytes
    
    Raises:
    - ValueError: if data length exceeds 32 bytes
    """

Block Data Operations

SMBus block data operations for reading and writing multiple bytes in a single transaction.

def read_block_data(self, i2c_addr, register, force=None):
    """
    Read block of data from register (up to 32 bytes).
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, start register address
    - force: bool, optional override for force flag
    
    Returns:
    - list of int: data bytes read
    """

def write_block_data(self, i2c_addr, register, data, force=None):
    """
    Write block of data to register (up to 32 bytes).
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, start register address
    - data: list of int, data bytes to write (max 32 bytes)
    - force: bool, optional override for force flag
    
    Raises:
    - ValueError: if data length exceeds 32 bytes
    """

def read_i2c_block_data(self, i2c_addr, register, length, force=None):
    """
    Read I2C block data with specified length.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, start register address
    - length: int, number of bytes to read (max 32)
    - force: bool, optional override for force flag
    
    Returns:
    - list of int: data bytes read
    
    Raises:
    - ValueError: if length exceeds 32 bytes
    """

def write_i2c_block_data(self, i2c_addr, register, data, force=None):
    """
    Write I2C block data.
    
    Parameters:
    - i2c_addr: int, I2C slave address
    - register: int, start register address
    - data: list of int, data bytes to write (max 32 bytes)
    - force: bool, optional override for force flag
    
    Raises:
    - ValueError: if data length exceeds 32 bytes
    """

Advanced I2C Operations

Combined I2C read/write operations using i2c_msg for transactions beyond SMBus limitations.

def i2c_rdwr(self, *i2c_msgs):
    """
    Execute combined I2C read/write operations with repeated start.
    
    Parameters:
    - i2c_msgs: i2c_msg instances created with i2c_msg.read() or i2c_msg.write()
    
    Note: Allows bulk transfers beyond SMBus 32-byte limit
    """

class i2c_msg:
    """I2C message for combined transactions."""
    
    @staticmethod
    def read(address, length):
        """
        Create I2C read message.
        
        Parameters:
        - address: int, I2C slave address
        - length: int, number of bytes to read
        
        Returns:
        - i2c_msg: configured for read operation
        """
    
    @staticmethod
    def write(address, buf):
        """
        Create I2C write message.
        
        Parameters:
        - address: int, I2C slave address
        - buf: list of int or str, data to write
        
        Returns:
        - i2c_msg: configured for write operation
        """
    
    def __iter__(self):
        """Iterate over message data bytes."""
    
    def __len__(self):
        """Get message length."""
    
    def __bytes__(self):
        """Get message data as bytes."""
    
    def __repr__(self):
        """String representation of message."""
    
    def __str__(self):
        """Decoded string representation of message data."""
    
    # Properties
    addr: int       # I2C slave address
    flags: int      # Message flags (e.g., I2C_M_RD for read)
    len: int        # Message length in bytes
    buf: pointer    # Message data buffer

Configuration and Capabilities

Device capability detection and configuration management including Packet Error Checking.

def enable_pec(self, enable=True):
    """
    Enable or disable Packet Error Checking (SMBus 1.1+).
    
    Parameters:
    - enable: bool, True to enable PEC, False to disable
    
    Raises:
    - IOError: if device doesn't support PEC
    """

# Properties
pec: int  # PEC setting (0=disabled, 1=enabled)
funcs: I2cFunc  # Device capability flags
fd: int  # File descriptor for I2C device
address: int  # Current I2C slave address
force: bool  # Force flag setting

class I2cFunc:
    """IntFlag enum for I2C/SMBus capability flags."""
    
    # Basic I2C capabilities
    I2C = 0x00000001
    ADDR_10BIT = 0x00000002
    PROTOCOL_MANGLING = 0x00000004
    SMBUS_PEC = 0x00000008
    NOSTART = 0x00000010
    SLAVE = 0x00000020
    
    # SMBus operation capabilities
    SMBUS_QUICK = 0x00010000
    SMBUS_READ_BYTE = 0x00020000
    SMBUS_WRITE_BYTE = 0x00040000
    SMBUS_READ_BYTE_DATA = 0x00080000
    SMBUS_WRITE_BYTE_DATA = 0x00100000
    SMBUS_READ_WORD_DATA = 0x00200000
    SMBUS_WRITE_WORD_DATA = 0x00400000
    SMBUS_PROC_CALL = 0x00800000
    SMBUS_READ_BLOCK_DATA = 0x01000000
    SMBUS_WRITE_BLOCK_DATA = 0x02000000
    SMBUS_READ_I2C_BLOCK = 0x04000000
    SMBUS_WRITE_I2C_BLOCK = 0x08000000
    SMBUS_BLOCK_PROC_CALL = 0x00008000
    SMBUS_HOST_NOTIFY = 0x10000000
    
    # Combined capability flags
    SMBUS_BYTE = 0x00060000
    SMBUS_BYTE_DATA = 0x00180000
    SMBUS_WORD_DATA = 0x00600000
    SMBUS_BLOCK_DATA = 0x03000000
    SMBUS_I2C_BLOCK = 0x0c000000
    SMBUS_EMUL = 0x0eff0008

Usage Examples

Basic Sensor Reading

from smbus2 import SMBus

# Read temperature from sensor at address 0x48
with SMBus(1) as bus:
    # Read 2-byte temperature value
    temp_raw = bus.read_word_data(0x48, 0x00)
    # Convert to Celsius (example conversion for specific sensor)
    temperature = (temp_raw >> 8) * 0.5
    print(f"Temperature: {temperature}°C")

Block Data Transfer

from smbus2 import SMBus

# Read configuration block from EEPROM
with SMBus(1) as bus:
    # Read 16 bytes starting from address 0x00
    config_data = bus.read_i2c_block_data(0x50, 0x00, 16)
    print(f"Config: {[hex(b) for b in config_data]}")
    
    # Write new configuration
    new_config = [0x01, 0x02, 0x03, 0x04, 0x05]
    bus.write_i2c_block_data(0x50, 0x00, new_config)

Combined I2C Transactions

from smbus2 import SMBus, i2c_msg

# Advanced I2C operations beyond SMBus limits
with SMBus(1) as bus:
    # Write command and read large response in single transaction
    write_cmd = i2c_msg.write(0x40, [0x01, 0x02])
    read_response = i2c_msg.read(0x40, 64)  # Read 64 bytes
    
    bus.i2c_rdwr(write_cmd, read_response)
    
    # Access response data
    response_data = list(read_response)
    print(f"Response: {response_data}")

Capability Detection

from smbus2 import SMBus, I2cFunc

with SMBus(1) as bus:
    # Check device capabilities
    if bus.funcs & I2cFunc.SMBUS_PEC:
        print("Device supports Packet Error Checking")
        bus.pec = 1  # Enable PEC
    
    if bus.funcs & I2cFunc.SMBUS_BLOCK_DATA:
        print("Device supports SMBus block operations")
    
    if bus.funcs & I2cFunc.I2C:
        print("Device supports I2C operations")

Constants

# I2C device control constants
I2C_SLAVE = 0x0703          # Use this slave address
I2C_SLAVE_FORCE = 0x0706    # Use this slave address, even if already in use by a driver
I2C_FUNCS = 0x0705          # Get the adapter functionality mask
I2C_RDWR = 0x0707           # Combined R/W transfer (one STOP only)
I2C_SMBUS = 0x0720          # SMBus transfer. Takes pointer to i2c_smbus_ioctl_data
I2C_PEC = 0x0708            # != 0 to use PEC with SMBus

# SMBus transfer direction markers
I2C_SMBUS_WRITE = 0
I2C_SMBUS_READ = 1

# SMBus operation size identifiers
I2C_SMBUS_QUICK = 0
I2C_SMBUS_BYTE = 1
I2C_SMBUS_BYTE_DATA = 2
I2C_SMBUS_WORD_DATA = 3
I2C_SMBUS_PROC_CALL = 4
I2C_SMBUS_BLOCK_DATA = 5         # Not supported by Pure-I2C drivers with SMBUS emulation
I2C_SMBUS_BLOCK_PROC_CALL = 7    # Not supported by Pure-I2C drivers either
I2C_SMBUS_I2C_BLOCK_DATA = 8
I2C_SMBUS_BLOCK_MAX = 32

# I2C message flags
I2C_M_RD = 0x0001

Error Handling

Common exceptions that may be raised:

  • IOError: I2C operation failed (device not responding, bus error, insufficient permissions, PEC not supported)
  • ValueError: Invalid parameter values (data length exceeds I2C_SMBUS_BLOCK_MAX (32 bytes), invalid length specification)
  • TypeError: Incorrect parameter types (bus must be int or str)

Specific error conditions:

  • Block operations raise ValueError if data length > 32 bytes
  • enable_pec() raises IOError if device doesn't support SMBUS_PEC functionality
  • open() raises TypeError if bus parameter is not int or str

Always use try-except blocks for robust error handling:

from smbus2 import SMBus, I2cFunc

try:
    with SMBus(1) as bus:
        # Check PEC support before enabling
        if bus.funcs & I2cFunc.SMBUS_PEC:
            bus.pec = 1
        data = bus.read_byte_data(0x50, 0x00)
except IOError as e:
    print(f"I2C communication error: {e}")
except ValueError as e:
    print(f"Invalid parameter: {e}")
except TypeError as e:
    print(f"Invalid type: {e}")