Reverse-engineering notes and tools for reading diagnostic data from a Bosch PowerPack Frame 400 e-bike battery over its CAN bus, using cheap hobbyist hardware instead of the official Bosch dealer tool.
Two things live here:
- A passive CAN sniffer that captured a real diagnostic session performed with the official Bosch software (battery on a compatible new bike).
- A read-only reader that replays part of that session on its own, with no Bosch tool, reading fault codes, temperature and pack voltage directly from the BMS.
This project is not affiliated with or endorsed by Bosch.
Without any authentication you can read:
- Fault codes (for my battery, DTCs
606011,655003and61000E, i.e. display codes 606 / 655 / 610, see error codes) - Measured temperature inside the pack
- Pack voltage (and state of charge, passively)
The BMS gates its history behind UDS SecurityAccess (0x27). These stay
locked (NRC 0x33, securityAccessDenied) and were not recovered:
- Charge-cycle count
- Total Ah discharged
- Min / max recorded temperatures
Requesting a seed (27 11) returns a 16-byte challenge; the seed→key algorithm
is unknown, so the matching key (27 12) was never sent. If you crack that, the
rest of the DIDs listed in docs/protocol.md should open up.
- Adafruit Feather M4 CAN Express (ATSAME51 + built-in CAN transceiver)
- CircuitPython,
caniomodule - CAN bus at 500 kbit/s, tapped on the pack's CAN-H / CAN-L
No extra transceiver or shield is needed, the Feather M4 CAN has one onboard. (Mine has a 2.4" TFT FeatherWing attached underneath; it plays no role here.)
I used a Bosch Rear Rack Cable 720 mm – BDU2XX / BDU3XX / BDU4XX – BCH222, cut at one end. The intact connector plugs into the battery; the CAN wires from the cut end go to the Feather's CAN terminal block. No need to switch the battery on: starting the reader wakes it up.
If you'd rather not sacrifice a cable, others have 3D-printed a battery connector with CAN pins instead: Bosch 36V eBike battery connector with CAN pins (Printables).
![]() |
![]() |
![]() |
![]() |
A sample run on this setup is in
data/reader_output_my_battery.txt.
firmware/
sniffer/ passive CAN logger (never transmits) → firmware/sniffer/README.md
reader/ read-only diagnostic replay → firmware/reader/README.md
tools/
decode.py decode sniffer .bin captures to CSV
data/
can_0066.* the captured Bosch diagnostic session (bin + log + csv)
official_diag_report.pdf official Bosch report for the same pack (anonymized)
reader_output_my_battery.txt real reader output on my pack (3 DTCs)
docs/
protocol.md CAN IDs, UDS DIDs, DTCs, the security gate, reference values
images/ photos of the bench setup
Sniff a session, or just decode the included capture:
python3 tools/decode.py data/can_0066.bin /tmp/out.csvTo talk to a pack yourself, flash firmware/reader/code.py and open the serial
console - see firmware/reader/README.md. Start
from the sniffer if you want to capture your own reference session first.
- The sniffer is strictly passive and safe to leave on a live bus.
- The reader only reads. It never writes, clears, resets, or sends a SecurityAccess key.
- All findings come from one pack / firmware / bike. IDs and offsets may differ on yours. Verify before trusting any value.
- Work on your own battery, at your own risk.
Everything here comes from a single battery, so the most useful help is more data. Contributions are very welcome, in particular:
- Other models. Run the reader (or the sniffer) on other Bosch batteries, e.g. PowerPack 300/500, PowerTube, or other generations, and report what works: bit rate, CAN IDs, which DIDs answer and which are locked. Please include the battery part number and the serial output.
- DTCs. Share the fault codes your pack returns, ideally alongside what the
official Bosch tool or a dealer reports for them. The first three digits map
to the display code, but the meaning of the last three (e.g.
011in606011) is still unknown. - UDS decoding. Help confirm or correct the DID decodings in
docs/protocol.md, especially the ones marked as hypotheses (Ah, cycles,0x108), and map DIDs not covered yet.
Open an issue or a pull request with your captures and findings. Feel free to redact serial numbers.
MIT © 2026 Bruno Godefroy



