Python-based CAN sniffer/router using inexpensive USB–CAN adapters.
- 1-channel mode: passive sniffer that listens on a single CAN bus and logs frames.
- 2-channel mode: bi-directional router between two CAN segments (A⇄B) with direction/origin tagging.
- Selectable output:
- CSV file
- JSON Lines (JSONL) file
- Console-only debug logging
This project is intended to be managed with uv and a pyproject.toml file.
If you are starting from scratch with a new folder:
mkdir sniffer
cd sniffer
uv initFor this existing project, from repository root:
uv syncRun sniffer (1 channel):
uv run sniffer run \
--channels 1 \
--device-a /dev/tty.usbserial-1310 \
--output consoleRun router (2 channels):
uv run sniffer run \
--channels 2 \
--device-a /dev/tty.usbserial-A \
--device-b /dev/tty.usbserial-B \
--output jsonl \
--output-path capture.jsonlFind serial devices on macOS:
ls /dev/tty.*Generate a PNG chart from a JSONL capture to visualize byte trends over time:
uv run sniffer plot \
--input-path full_charge_cycle.jsonl \
--can-ids 0x70A,0x718 \
--byte-indexes 1,2,3,4,5,6 \
--output-path charge_trends.pngGenerate a combined scaled plot (proposed SOC/Voltage/Current channels):
uv run sniffer plot-scaled \
--input-path full_charge_cycle.jsonl \
--series "SOC[%]:0x70A:0:1:0" \
--series "Vpack[V]:0x70A:1:0.4:0" \
--series "Ichg[A]:0x70A:3:0.0368:0" \
--output-path scaled_channels.png