- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| custom_components/campervan | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| CLAUDE.md | ||
| hacs.json | ||
| pyproject.toml | ||
| README.md | ||
| requirements-dev.txt | ||
Campervan CAN bus
A Home Assistant custom integration for a campervan's CAN bus.
A Raspberry Pi running Home Assistant Core sits on the bus as node 0x01,
talking to an MCP2515 module through SocketCAN. It discovers the van's
controllers, presents them as devices and entities, and later commands them.
The controllers themselves, and the wire protocol they speak, live in
CampervanControlSystems.
docs/can-protocol.md
there is the authority for everything on the wire; this repository is the second
implementation of it, and when the two disagree the specification decides.
Status
Scaffolding. The integration installs, sets up against a named SocketCAN
interface and unloads again. It does not yet open the bus, and it exposes no
entities: PLATFORMS is deliberately empty.
Work is read-only first — discovery, entities, state, availability and alarms, with no command path at all — so that the hardware, the decode path and the entity model are proved before any bug can switch something on in a van.
Requirements
- Home Assistant Core, not OS and not Supervised. There is no add-on and no Supervisor here; the integration is the whole answer.
- A CAN interface up at 250 kbps, CAN 2.0B with 29-bit extended identifiers.
- No internet connection, cloud service or NTP. The van may have no network at all beyond the bus.
Bringing up can0
The interface is host configuration, and this repository does not own it: the
integration only needs to know what the interface is called. On a Pi with an
MCP2515 module, in /boot/firmware/config.txt:
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=<your module's crystal, in Hz>,interrupt=<its INT GPIO>
The oscillator frequency has to match the crystal actually fitted to the module. A wrong value does not fail loudly — it produces an interface that comes up and then never receives a valid frame.
Then, after a reboot:
sudo ip link set can0 up type can bitrate 250000
sudo ip link set can0 txqueuelen 128 # the 10-frame default drops bursts
ip -details -statistics link show can0
Make it persistent with systemd-networkd or your distribution's equivalent, so the bus is there before Home Assistant starts.
Installation
Copy custom_components/campervan into your Home Assistant config
directory's custom_components/, restart, then add the integration and give it
the interface name.
Development
uv venv --python 3.14 .venv
uv pip install --python .venv/bin/python -r requirements-dev.txt
.venv/bin/ruff check . # lint
.venv/bin/ruff format . # format
.venv/bin/mypy custom_components tests
.venv/bin/pytest
Python 3.14 is not a preference: it is what Home Assistant 2026.9 requires.
pytest-homeassistant-custom-component is pinned exactly, because its fixtures
track Home Assistant's internals and it pins the Home Assistant release it was
built against.
hassfest runs in CI as a container, and needs a runner that can run one.
hacs/action does not run: it validates a repository through the GitHub API,
and this repository is on Forgejo. The layout checks that are ours to make are
in tests/test_manifest.py instead.