- C++ 98.6%
- Python 0.8%
- Shell 0.5%
- C 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .forgejo/workflows | ||
| docs | ||
| lib | ||
| scripts | ||
| src | ||
| test | ||
| tools | ||
| vectors | ||
| .clang-format | ||
| .editorconfig | ||
| .gitignore | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| platformio.ini | ||
| README.md | ||
Campervan Control Systems
Control systems for a campervan, talking to each other over a dedicated CAN bus at 250 kbps. Most controllers are Seeed Studio XIAO boards with the XIAO CAN Bus Expansion Board. Controllers lists the ones that are not.
docs/can-protocol.md is the authority for all firmware. If code and that document disagree, the document is wrong and gets fixed in the same pull request as the code.
Layout
docs/can-protocol.md Protocol specification. Read this first.
docs/hardware.md Boards, pins, driver polarity, touch sensing, wiring.
docs/host-simulator.md Running a node on Linux with no hardware.
docs/bus-diagnostics.md Reading a node's [bus] serial output when it goes quiet.
docs/autoterm-diagnostics.md
What the heater's state and phase readouts mean.
lib/can-protocol/ Wire protocol (can::): IDs, codecs, units, registries.
Header-only, no Arduino dependency. Keep it that way.
lib/node-runtime/ Shared runtime (ctrl::): bus handling, endpoints,
failsafe, peer liveness.
src/<node>/main.cpp One directory per controller.
src/host_sim/ The runtime as a Linux binary on SocketCAN.
test/ Native tests, run on the host with no hardware.
The two libraries are split on purpose. lib/can-protocol has no Arduino
dependency, which is what lets the codecs and the runtime's general paths be
tested on the host. Using millis() or Serial in there breaks that.
Building
pio run # build every node
pio run -e node_lighting # build one node
pio run -e node_lighting -t upload
pio device monitor # 115200 baud
pio test -e native # run the test suite on the host
pio run -e host_sim # build the host simulator
Every node uses the min_spiffs.csv partition table, which gives each OTA slot
1.875 MB. A board last flashed before that change needs one cabled -t upload
to move over, because the partition table cannot change over the air.
.forgejo/workflows/build.yml runs the tests and builds every node. Pull
requests publish nothing. Every push to main publishes a CalVer release
(YYYY.MM.<nth build that month>) as a Forgejo release and a
campervan-firmware package. See
CONTRIBUTING.md.
Running a node with no hardware
scripts/host_sim.sh
This runs the real runtime on a virtual CAN interface, announcing as the lighting node, so Home Assistant or any other consumer has a node to talk to. It can be muted, delayed and driven from the keyboard. docs/host-simulator.md has the details.
Controllers
| Node | ID | Environment | Board | CAN |
|---|---|---|---|---|
| Lighting, dimmable ceiling circuits | 0x10 |
node_lighting |
LOLIN32 (ESP32) | native TWAI + WCMCU-230 |
| Kitchen, under-cabinet strip and touch | 0x11 |
node_kitchen |
XIAO ESP32S3 | MCP2515 over SPI |
| Bathroom, PIR and extractor | 0x12 |
node_bathroom |
XIAO ESP32C3 | MCP2515 over SPI |
| Water heater, immersion element switching | 0x41 |
node_water_heater |
XIAO ESP32C3 | MCP2515 over SPI |
NODE_BRIDGE (0x01) is a Raspberry Pi running Home Assistant and the van's
display. Its code lives in its own repository.
docs/hardware.md covers why the lighting node is a different board, the pin assignments, driver polarity, touch sensing and bus wiring.
Contributing
CONTRIBUTING.md has the conventions, the branch and pull request rules, and how to allocate a node ID or an endpoint index.