CANsub python-can interface
Project description
python-can-cansub
A python-can integration for the CANsub CAN bus interface family by CSS Electronics. Source on GitHub.
This package registers the CANsub as a standard python-can interface, making it compatible with all python-can tools and workflows. It also adds a CSV logger compatible with the webCAN browser tool provided with the device.
Tip: This README is optimized for LLMs. When using an AI coding assistant with this package, provide this file as context for accurate results.
python-can API
Installation
pip install python-can-cansub
Import
When python-can-cansub is installed, the cansub interface is automatically registered with python-can. Import with:
import can
Configuration
Python-can defines a hardware configuration by an interface and a channel (a single interface can have multiple channels).
The CANsub interface is fixed "cansub". The channel is constructed from the device hostname (unique) and channel index.
| Connection | Hostname | python-can channel string |
|---|---|---|
| USB | [DEVICE-ID]-usb.local |
[DEVICE-ID]-usb.local@[channel] |
| Ethernet | [DEVICE-ID]-eth.local |
[DEVICE-ID]-eth.local@[channel] |
The device-ID is printed on the device label. Channel indexing is 1-based - the first channel is 1.
A configuration is passed to can.Bus to open a bus.
Fixed
Example of a fixed configuration:
configs = [{"interface": "cansub", "channel": "aabbccdd-usb.local@1"},
{"interface": "cansub", "channel": "aabbccdd-usb.local@2"}]
Auto-detect
Example of using detect_available_configs to automatically discover (uses mDNS) all connected CANsub devices and channels:
configs = can.detect_available_configs(interfaces=["cansub"])
# e.g. [{"interface": "cansub", "channel": "aabbccdd-usb.local@1"},
# {"interface": "cansub", "channel": "aabbccdd-usb.local@2"}
# {"interface": "cansub", "channel": "11223344-eth.local@1"}
# {"interface": "cansub", "channel": "11223344-eth.local@2"}]
In the above example two CANsub devices are detected, each with two channels. One device is connected via USB and the other via Ethernet.
Opening a Bus
Single bus - hardcoded
with can.Bus(interface="cansub", channel="aabbccdd-usb.local@1", bitrate=250_000, data_bitrate=1_000_000) as bus:
pass
Single bus - from configs
with can.Bus(interface=configs[0]["interface"], channel=configs[0]["channel"], bitrate=250_000, data_bitrate=1_000_000) as bus:
pass
Multiple buses - from configs
with (can.Bus(interface=configs[0]["interface"], channel=configs[0]["channel"], bitrate=250_000, data_bitrate=1_000_000) as bus1,
can.Bus(interface=configs[1]["interface"], channel=configs[1]["channel"], bitrate=250_000, data_bitrate=1_000_000) as bus2):
pass
Tip:
**configunpacks a config dict directly intocan.Buskeyword arguments:with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus: pass
Receive and Transmit
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
# Transmit
msg_tx = can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04])
bus.send(msg_tx)
# Receive with timeout
msg_rx = bus.recv(timeout=1.0)
print(msg_rx)
Filters
Apply hardware filters by passing can_filters to can.Bus. Each filter specifies a can_id, a can_mask, and whether to match standard (extended=False) or extended (extended=True) frames. A frame passes if (frame_id & can_mask) == (can_id & can_mask).
filters = [
{"can_id": 0x123, "can_mask": 0x7FF, "extended": False}, # standard frames, exact ID match
{"can_id": 0x000, "can_mask": 0x000, "extended": True}, # all extended frames
]
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000, can_filters=filters) as bus:
msg = bus.recv(timeout=1.0)
print(msg)
Tip: Applying hardware filters reduces the network load between the CANsub and the connected client.
Notifier and Listeners
bus.recv() blocks until a frame arrives. A can.Notifier runs a background thread that dispatches received frames to one or more listeners, allowing the main program to continue other work.
python-can provides built-in listeners including can.Printer (print to stdout) and can.Logger (log to file). The example below logs to a CSV file while the main program continues. Custom listeners can be implemented by subclassing can.Listener.
from time import sleep
print_listener = can.Printer()
csv_listener = can.Logger("log.csv")
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
with can.Notifier([bus], listeners=[print_listener, csv_listener]):
# Perform other tasks here while frames are received in the background
sleep(10)
Broadcast Manager
Periodic transmission jobs can be started with bus.send_periodic().
Most periodic transmission job types can be offloaded to the CANsub hardware, providing much better transmission time accuracy (compared to a host-scheduled transmission). A host-side background task is used only as a fallback when hardware transmission is not available.
from time import sleep
msgs = [
can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04]),
can.Message(is_extended_id=False, arbitration_id=0x124, data=[0x05, 0x06, 0x07, 0x08]),
can.Message(is_extended_id=False, arbitration_id=0x125, data=[0x09, 0x0A, 0x0B, 0x0C]),
]
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
# period: time between individual frames (sequence repeats every len(msgs) * period)
# duration: total transmission time in seconds (None = transmit indefinitely)
task = bus.send_periodic(msgs, period=0.1, duration=5.0)
# Perform other tasks here while frames are transmitted in the background
sleep(6)
Replaying files
can.MessageSync can be used to replay messages from a log file.
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
with can.LogReader("log.csv") as reader:
for msg in can.MessageSync(messages=reader):
bus.send(msg)
python-can tools
python-can includes several command line tools. All tools accept --interface and --channel to select the bus, following the same configuration as the API.
The common argument pattern for the CANsub:
--interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000
can_logger
Log received frames to a file (CSV by default; format inferred from file extension):
can_logger --interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000 --output-file log.csv
can_player
Play back a previously recorded log file:
can_player --interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000 log.csv
can_viewer
Live terminal viewer showing received frames, updated counts, timestamps, and byte-level changes:
can_viewer --interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000
can_bridge
Forward all frames received on one bus to another (e.g. bridge two CANsub channels):
can_bridge --interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000 \
--interface2 cansub --channel2 aabbccdd-usb.local@2 --bitrate2 250000 --data-bitrate2 1000000
can_logconvert
Convert a log file between formats; the format is inferred from the file extension:
can_logconvert log.csv log.asc
Related Packages
The following packages complement python-can-cansub and are included here as inspiration for working with CAN data in Python.
cantools
cantools is a Python package for encoding and decoding CAN messages. Encoding/decoding rules can be created or loaded from DBC (and other) database files. It works directly with can.Message objects from python-can.
Installation
pip install cantools
Create database in code
A database can be constructed directly in Python without a database file:
import cantools
db = cantools.database.Database()
msg_def = cantools.database.can.Message(
frame_id=0x123,
name="Message1",
length=8,
signals=[
cantools.database.can.Signal(name="Signal1", start=0, length=16, scale=0.1, offset=0.0, minimum=0.0, maximum=100.0),
cantools.database.can.Signal(name="Signal2", start=16, length=16, scale=0.1, offset=0.0, minimum=0.0, maximum=100.0),
]
)
db.add_message(msg_def)
Load database from DBC file
import cantools
db = cantools.database.load_file("database.dbc")
msg_def = db.get_message_by_name("Message1")
Encode
Encode signal values into the byte payload of a can.Message:
data = msg_def.encode({"Signal1": 1.0, "Signal2": 42.5})
msg_tx = can.Message(arbitration_id=msg_def.frame_id,
is_extended_id=msg_def.is_extended_frame,
data=data)
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
bus.send(msg_tx)
Decode
Decode the byte payload of a received can.Message back into signal values:
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
msg_rx = bus.recv(timeout=1.0)
if msg_rx:
signals = db.decode_message(msg_rx.arbitration_id, msg_rx.data)
print(signals) # e.g. {'Signal1': 1.0, 'Signal2': 42.5}
asammdf
asammdf is a Python package for reading and writing MDF (Measurement Data Format) files.
When asammdf is installed, python-can automatically gains support for reading MDF log files via can.LogReader, allowing MDF recordings to be played back directly using can.MessageSync:
Installation
pip install asammdf
Playback of MDF log file
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
with can.LogReader("recording.mf4") as reader:
for msg in can.MessageSync(messages=reader):
bus.send(msg)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_can_cansub-2026.5.22.tar.gz.
File metadata
- Download URL: python_can_cansub-2026.5.22.tar.gz
- Upload date:
- Size: 17.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc9ccab1ad5ba0c3bbe10b5a9aa6a590647f9414653c1dabdeacaac1bb450e6c
|
|
| MD5 |
1a0abc60dd57e958e9dc6d5907a31a98
|
|
| BLAKE2b-256 |
ad7f686b021e8030a268771e6e2c16b99c7da6802aff636fcc0fde0e58bc37aa
|
File details
Details for the file python_can_cansub-2026.5.22-py3-none-any.whl.
File metadata
- Download URL: python_can_cansub-2026.5.22-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
958cf62b9f3875c023ce5d821aeee0b742939d07c14a91c11d556ef20442a79b
|
|
| MD5 |
dd80514435230734a3020783784097ce
|
|
| BLAKE2b-256 |
6db2c4f3b836095bac638b560ca3e3423a6555f8e8443bff971ab565759961d5
|