A Raspberry Pi Zero 2 service that reads a Victron Cerbo GX over MQTT and renders an 800×480 e-ink dashboard for a TRMNL display via its BYOS (Bring Your Own Server) API.
Modular by design - extend it with your own hardware, or ask about the modules already built.
E-ink, always on. Easy on the eye, and always showing. No touching to wake a screen, no bright light during dark hours. It stays on permanently and fits the analog camper look. Battery life in months.
It goes where you need it. The TRMNL can be moved around, wherever you need it and when you need it. No wires to run, no holes to drill.
The screen is yours. The big benefit of this software is that it shows the data you care about, in a way you want it. The estimates come from your own history, not from generic percentages. Solar yield is forecast from the weather and then checked against what your panels really produced in the past. Water is shown in days, not percent: instead of "40% should last us two days", the screen says water for 2.4 days. Use less water this week and the number gets longer by itself. Most off-the-shelf systems do not do this.
It runs locally. No internet connection is needed for the system to work. A few features do need one now and then, like the weather forecast but all these are optional.
It is modular. Every van has a different set of devices, so the code is split into a core plus modules that feed it. This repository is the core: everything that works from a Cerbo GX alone. Working code also exists for the modules below. They are not public yet, please ask if you need one:
- Gas bottles - Mopeka ultrasonic BLE sensors, with level and days remaining (old version and new)
- Fridge and leak - Matter over Thread sensors, fridge temperature trend and a full-screen leak alert (Example Ikea temperature sensors with rechargable batteries)
- Battery BMS - SOK (ABC-BMS) and Wattcycle (JBD) over BLE: per-cell voltages, temperatures, cycle count, protection state (basically any can be made work that has BT)
- Shore charger - Victron Blue Smart IP65 over encrypted BLE Instant Readout, charging power while plugged in (or any Victron device that does not have VE direct)
- 4G router - MikroTik LTE signal, per-WAN daily data usage, cell-tower geolocation, WAN failover, SIM inbox (or any router if the capability exists)
- Starlink - dish latency, drop rate and obstruction telemetry
- Companion app - pushes telemetry to a backend for live view and graphs on your phone
Several of these talk to hardware with no documented API, so the protocol had to be worked out first.
There is a companion app (Kämpa), where all of this and more can be viewed, graphed and configured from your phone in real time. It needs a VPS and a permanent internet connection to the camper. We can offer the app as service. Email robert@robothead.eu for further information.
The photo above is a full build. Some of what you can see there comes from the optional modules - the gas bottle levels, the fridge warning across the top, the 4G signal and data counters. From a Cerbo GX alone you get:
- Battery - state-of-charge ring, voltage, charge/discharge power, time to full or time to empty
- Solar - MPPT power and charger state (bulk / absorption / float / off)
- Consumption - total DC draw, split into inverter and 12V loads
- Water tank - level bar, percentage, and a day-by-day countdown built from your own usage
- Weather - current conditions and a 4-day forecast, with a solar yield estimate per day that calibrates itself against what your panels actually produced
- Optional extras - schedule panel, travel-day counter, birthday screens
Which looks like this, straight out of this repository:
Everything is logged to SQLite, so the tank and solar and other estimates get better over the first couple of weeks.
The interface is translatable. The photos show it in Estonian; English is the default, and adding a
language is one dictionary in app/i18n.py.
| Device | Role | Required |
|---|---|---|
| Victron Cerbo GX | MQTT broker on the LAN | Yes |
| Victron battery monitor (SmartShunt / BMV) | State of charge | Yes |
| Raspberry Pi Zero 2 W or better | Runs this service | Yes |
| TRMNL 7.5" e-ink display | Shows the dashboard | Yes |
| Victron MPPT solar charger | Solar panel | No |
| Tank sensor on a Cerbo GX tank input | Water panel | No |
| Victron GPS | Location for weather | No |
If you do not have the optional parts, those panels just do not show up. Nothing breaks and there is nothing to switch off.
git clone <this repo>
cd victron-trmnl
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python scripts/test_render.py --save # PNGs land in preview/That renders every scenario (charging, discharging, low battery, no data) from mock state. It is also the smoke test CI runs on every push.
To run the whole server against fake Victron data, start python mock/publish_mqtt.py in one
terminal and bash scripts/run_dev.sh in another.
If the previews come out tiny and unreadable, no system font was found. Install DejaVu (
fonts-dejavu-core) or pointFONT_DIRat a folder containingDejaVuSans.ttf.
bash scripts/install.sh # apt deps, venv, /opt/victron-trmnl, systemd unit
cp .env.example .env
nano .env # at minimum: MQTT_HOST and DEVICE_HOST
sudo systemctl enable --now victron-trmnl
sudo journalctl -u victron-trmnl -fThen point your TRMNL device at http://<PI_IP>:7000/api/display.
Only two values really need setting, the Cerbo's address and the address the display fetches from:
MQTT_HOST=192.168.1.100 # your Cerbo GX
DEVICE_HOST=192.168.1.50 # this Pi, as the TRMNL device sees it
TIMEZONE=Europe/Helsinki
LANGUAGE=en # en or etEverything else in .env.example has a working default. It is grouped by feature and optional features are commented out. Uncomment a block to switch it on.
To update: cd /opt/victron-trmnl && git pull && sudo systemctl restart victron-trmnl.
| Endpoint | Purpose |
|---|---|
GET /api/display |
TRMNL BYOS JSON, points the device at the current image |
GET /api/setup |
Device registration, called by the firmware on first boot |
GET /image/latest.png |
The rendered dashboard |
GET /healthz |
Status, last-update timestamps, current readings |
GET /preview |
Every mock scenario plus the live image, in a browser |
GET/POST /api/travel |
Read or set the travel-day counter |
GET/PUT /api/schedule |
Read or replace the schedule |
The display path is open unless you set TRMNL_API_KEY. The write endpoints are open unless you set
CONTROL_API_KEY. Both are fine to leave open on a trusted LAN.
app/
main.py entry point, starts every enabled thread
config.py all configuration, read from .env
state.py shared state dataclasses
i18n.py UI strings (en, et)
render/draw.py the entire dashboard layout (Pillow)
render/fonts.py cross-platform font lookup
victron/ MQTT client and topic maps
weather/ Open-Meteo client and cache
web/server.py Flask: BYOS API, image, healthz, preview
db/logger.py SQLite history, tank and solar estimates
mock/ fake Victron publisher for development
scripts/ install, dev-run, render tests
systemd/ service unit
The code is free and always will be. But a van dashboard is not only software. It is a Pi, a display, a Cerbo GX, sensors, wiring, and a setup that matches your vehicle.
Robothead is looking for a prototype customer. If you would rather not do the work yourself, we will deliver the whole thing keys in hand: hardware included, set up, configured for your van, and working before it reaches you. Once you have it we will spend time to get it working with your system exactly the way you want it, companion app included.
To be clear about the stage: this is a working system in daily use, but the productised version is still a prototype. It costs money, and we will put more effort into it than a job like this would normally get, because we are building the product while we build yours. If that suits you, get in touch: robert@robothead.eu
If one of the modules above is why you are here, send an email as well.
Contributions are welcome, see CONTRIBUTING.md. Translations are the easiest
place to start: adding a language is one dictionary in app/i18n.py and nothing else.
Apache License 2.0, see LICENSE.
This is cleaned up version of the codebase that has been in development for almost a year. It should work, but will probably need some tinkering to make it work with your hardware.




