Install the SPS30 Driver
The driver installation consists of creating a Python virtual environment, activating it, and installing the driver using pip.
Create a Python virtual environment:
python -m venv .venv
Activate the virtual environment:
source .venv/bin/activate
.venv\Scripts\Activate.ps1
.venv\Scripts\activate.bat
Install the driver:
python -m pip install sensirion_i2c_sps30
Use the SensorBridge on Windows
Install the driver for the Sensirion SEK-SensorBridge:
python -m pip install sensirion-shdlc-sensorbridgeConnect the SEK-SensorBridge to your PC over USB.
If the SEK-SensorBridge is not detected by your system, follow the SensorBridge FTDI Driver Installation.
Connect the SPS30 sensor to the SEK-SensorBridge.
Run the example script from the root of the repository.
By default, the script assumes that the SensorBridge is connected to the
COM1serial port. If a different port is used, specify it with the--serial-portparameter:python examples/example_usage_sensorbridge_sps30.py --serial-port <your COM port>
Example script
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# (c) Copyright 2026 Sensirion AG, Switzerland
#
# THIS FILE IS AUTOMATICALLY GENERATED!
#
# Generator: sensirion-driver-generator 1.9.3
# Product: sps30
# Model-Version: 1.0.2
#
import argparse
import time
from sensirion_i2c_driver import I2cConnection, CrcCalculator
from sensirion_shdlc_driver import ShdlcSerialPort, ShdlcConnection
from sensirion_shdlc_sensorbridge import (SensorBridgePort,
SensorBridgeShdlcDevice,
SensorBridgeI2cProxy)
from sensirion_driver_adapters.i2c_adapter.i2c_channel import I2cChannel
from sensirion_i2c_sps30.device import Sps30Device
from sensirion_i2c_sps30.commands import (OutputFormat)
parser = argparse.ArgumentParser()
parser.add_argument('--serial-port', '-p', default='COM1')
args = parser.parse_args()
with ShdlcSerialPort(port=args.serial_port, baudrate=460800) as port:
bridge = SensorBridgeShdlcDevice(ShdlcConnection(port), slave_address=0)
bridge.set_i2c_frequency(SensorBridgePort.ONE, frequency=100e3)
bridge.set_supply_voltage(SensorBridgePort.ONE, voltage=5)
bridge.switch_supply_on(SensorBridgePort.ONE)
i2c_transceiver = SensorBridgeI2cProxy(bridge, port=SensorBridgePort.ONE)
channel = I2cChannel(I2cConnection(i2c_transceiver),
slave_address=0x69,
crc=CrcCalculator(8, 0x31, 0xff, 0x0))
sensor = Sps30Device(channel)
try:
sensor.stop_measurement()
except BaseException:
...
try:
serial_number = sensor.read_serial_number()
print(f"serial_number: {serial_number}; "
)
product_type = sensor.read_product_type()
print(f"product_type: {product_type}; "
)
sensor.start_measurement(OutputFormat.OUTPUT_FORMAT_UINT16)
time.sleep(0.1)
except BaseException:
...
for i in range(50):
try:
time.sleep(1.0)
data_ready_flag = sensor.read_data_ready_flag()
print(f"data_ready_flag: {data_ready_flag}; "
)
(mc_1p0, mc_2p5, mc_4p0, mc_10p0, nc_0p5, nc_1p0, nc_2p5, nc_4p0, nc_10p0, typical_particle_size
) = sensor.read_measurement_values_uint16()
print(f"mc_1p0: {mc_1p0}; "
f"mc_2p5: {mc_2p5}; "
f"mc_4p0: {mc_4p0}; "
f"mc_10p0: {mc_10p0}; "
f"nc_0p5: {nc_0p5}; "
f"nc_1p0: {nc_1p0}; "
f"nc_2p5: {nc_2p5}; "
f"nc_4p0: {nc_4p0}; "
f"nc_10p0: {nc_10p0}; "
f"typical_particle_size: {typical_particle_size}; "
)
except BaseException:
continue
sensor.stop_measurement()
Use the Linux I²C Driver
On Linux systems, the sensor can alternatively be accessed directly through the Linux user-space I²C driver.
Connect the SPS30 sensor to an I²C port of your system, for example I²C port 1 of a Raspberry Pi.
Run the example script from the root of the repository.
By default, the script assumes that the sensor is connected to
/dev/i2c-1. If a different port is used, specify it with the--i2c-portparameter:python examples/example_usage_linux_sps30.py --i2c-port <your I2C port>
Example script
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# (c) Copyright 2026 Sensirion AG, Switzerland
#
# THIS FILE IS AUTOMATICALLY GENERATED!
#
# Generator: sensirion-driver-generator 1.9.3
# Product: sps30
# Model-Version: 1.0.2
#
import argparse
import time
from sensirion_i2c_driver import LinuxI2cTransceiver, I2cConnection, CrcCalculator
from sensirion_driver_adapters.i2c_adapter.i2c_channel import I2cChannel
from sensirion_i2c_sps30.device import Sps30Device
from sensirion_i2c_sps30.commands import (OutputFormat)
parser = argparse.ArgumentParser()
parser.add_argument('--i2c-port', '-p', default='/dev/i2c-1')
args = parser.parse_args()
with LinuxI2cTransceiver(args.i2c_port) as i2c_transceiver:
channel = I2cChannel(I2cConnection(i2c_transceiver),
slave_address=0x69,
crc=CrcCalculator(8, 0x31, 0xff, 0x0))
sensor = Sps30Device(channel)
try:
sensor.stop_measurement()
except BaseException:
...
try:
serial_number = sensor.read_serial_number()
print(f"serial_number: {serial_number}; "
)
product_type = sensor.read_product_type()
print(f"product_type: {product_type}; "
)
sensor.start_measurement(OutputFormat.OUTPUT_FORMAT_UINT16)
time.sleep(0.1)
except BaseException:
...
for i in range(50):
try:
time.sleep(1.0)
data_ready_flag = sensor.read_data_ready_flag()
print(f"data_ready_flag: {data_ready_flag}; "
)
(mc_1p0, mc_2p5, mc_4p0, mc_10p0, nc_0p5, nc_1p0, nc_2p5, nc_4p0, nc_10p0, typical_particle_size
) = sensor.read_measurement_values_uint16()
print(f"mc_1p0: {mc_1p0}; "
f"mc_2p5: {mc_2p5}; "
f"mc_4p0: {mc_4p0}; "
f"mc_10p0: {mc_10p0}; "
f"nc_0p5: {nc_0p5}; "
f"nc_1p0: {nc_1p0}; "
f"nc_2p5: {nc_2p5}; "
f"nc_4p0: {nc_4p0}; "
f"nc_10p0: {nc_10p0}; "
f"typical_particle_size: {typical_particle_size}; "
)
except BaseException:
continue
sensor.stop_measurement()