Home Lab / October 2026
My Caravan Has a Dashboard Now
An ESP32, a voltage divider and Home Assistant, and what a voltage can and can't tell you
Our caravan, kampica, is a 2010 Dethleffs AeroStyle 530 UL. It has one 12 V lead-acid battery, a Topla 85 Ah, and that battery has already been below 10 V once. I didn't know it was happening. For a lead-acid battery that's a bad place to be.
So the caravan got the same treatment as the house: measure first, then decide what the numbers mean.

The hardware
It's deliberately small and cheap. I added two separately fused circuits off the battery: one for a 60 W USB-C PD charger, one for the electronics. On the electronics side:
- an ESP32-WROOM-32D on a screw-terminal expansion board, running ESPHome (ESP-IDF framework), powered by a 12 V → 5 V buck converter,
- a 0–25 V voltage divider module feeding the ESP32's ADC (GPIO34) from the fused 12 V feed,
- an SHT41 for temperature and humidity inside the caravan,
- a waterproof DS18B20 probe on a 5 m cable for the outside temperature, with a second one meant for the fridge,
- a MikroTik router with an LTE stick.
The ESP32 sits under a bench near the battery, with the sensor cables running out to where they measure. It talks to Home Assistant over Wi-Fi. The plan is home Wi-Fi when the caravan is parked at home and the MikroTik's LTE when we're travelling, keeping mobile data small. Home Assistant on a Raspberry Pi already runs the house, so the caravan is just another set of entities. No cloud and no vendor app, and firmware updates go over the air.
The first problem was power, not sensors. One buck converter put out a correct 5 V on the meter but couldn't reliably run the ESP32.
The ADC on an ESP32 isn't a multimeter. So I measured the battery with a real multimeter and calibrated against it (a factor of 1.108). Now the voltage arrives about every 30 seconds and agrees with the meter.
Two metres of cable is a long way for I²C
The temperature side took longer than the battery side.
The SHT41 talks I²C. The first config had SDA and SCL swapped, which was easy. The harder problem was the cable. I ran the sensor over about two metres of UTP, one conductor per signal, and the bus scan "found" a device at every address. The sensor itself didn't answer, even with the bus slowed to 10 kHz.
With the data wires unplugged the scan found nothing. On short wires, under 20 cm, it found exactly one device at 0x44 and worked. So the long run is the problem. I didn't prove the exact mechanism, crosstalk or a marginal conductor, and I'm not going to pretend I did. The fix for a long run is the usual one: twist SDA with ground, SCL with 3.3 V or ground, and add 4.7 kΩ pull-ups at the ESP32 end if that isn't enough.
One more trap: ESPHome only looks for the SHT41 at boot. If the sensor doesn't answer then, the entities stay unknown until the ESP32 is power-cycled. After one rewiring it stayed unknown until I swapped the signal wires and hard-rebooted the ESP32.
The DS18B20 for the outside temperature was the easy one: one-wire, a 4.7 kΩ pull-up, done. The fridge probe can share the same pin when it goes in. I checked both sensors side by side with the living-room thermometer and gave them small offsets (+0.1 °C and +0.5 °C). They need checking again once they're mounted in the caravan.
A voltage is not a state of charge
This is the part I find most interesting, because it's where the sensor stops and the interpretation starts.
The ESP32 measures voltage only. There's no current sensor, so nothing in this setup knows amps, watts, amp-hours or how much capacity is left. And battery voltage lies in two directions:
- Under load it reads low. Switch something on and the voltage sags, even on a healthy battery.
- After charging it reads high. The surface charge holds it up for hours after the charger is unplugged.
Only a rested battery tells you roughly how full it is. After one full charge I watched it relax from 12.97 V to 12.72 V over about 21 hours without anything really being used.
So everything built on top of the voltage tries to respect that.
Alerts. Home Assistant has three alert levels: below 12.4 V for 15 minutes, below 12.3 V for 15 minutes, and at or below 12.2 V for 5 minutes. The delay means a short sag under load doesn't count. Each alert sends one notification to my phone per episode and only re-arms once the voltage is back 0.1 V above the threshold, so it doesn't nag. Nothing switches off automatically. The alert is a reason to go and look, not a decision.
Battery percentage. A standard rested lead-acid table maps 12.73 V to 100 % and 12.10 V to 50 %. But you shouldn't take lead-acid much below 50 %, so "50 %" on the dashboard was misleading: it looks like half a tank, and it's actually the bottom. I rescaled it. Real 50 % now shows as 10 %, charge now, and 20–30 % means charge soon. The tile goes green, orange and red on those bands. The real value is still stored alongside it.
Charging. While the charger is connected the percentage reads 100 and means nothing, so the dashboard shows a blue charging tile instead. My first version said "charging" above 13.3 V and "not charging" below 13.1 V. It stayed on "charging" after I unplugged, because the surface charge held the battery above 13.1 V. Looking at the real curve, the shore charger holds 14.4–14.5 V and then floats at about 13.54 V. After unplugging, the voltage fell below 13.4 V within about three and a half minutes. So the thresholds moved to on above 13.45 V and off below 13.4 V, each for two minutes. That works for the shore charger. It would miss a weak solar input that never pushes the battery above 13.45 V, and I've written that down rather than pretend otherwise.

Where it shows up
There's a Kampica tab on the house dashboard: a voltage gauge, the battery tile (or the charging tile), inside and outside temperature, humidity, and 24-hour graphs. The gauge is coloured by voltage band: red below 12.2 V, then orange, yellow, green for normal, and blue above 13.3 V for charging or fresh surface charge.
The data goes two places. Home Assistant keeps detailed history for ten days and hourly statistics forever. Everything Kampica-related is also exported to its own InfluxDB database, where it stays. Ten days is fine for "what happened last night". It's not enough for "how does this battery behave over a season".
The experiment
The point of the long history is a careful discharge experiment rather than guessing:
- Baseline. Charger off, only the ESP32 and the network gear on, and leave it alone for a day or two. The first hours are surface charge relaxing, not discharge.
- Mover standby. Switch the mover's isolator on for 30–60 minutes, without running the motors, and see what standby costs.
- One appliance at a time, only above about 12.4 V, with rest in between.
- Stop rule. Close to 12.3 V live, stop and switch off nonessential loads. If the rested voltage is 12.2 V or lower, recharge. No aiming for 11.8 V, and certainly not 10 V again.
Each step is logged from Home Assistant with a note, so the events line up with the voltage curve afterwards.
Who did what
I did the hardware, the wiring, the measuring and the decisions about what the numbers should mean. Claude Code did a lot of the configuration and integration work: ESPHome YAML, Home Assistant templates and dashboards, the InfluxDB export, and the notes that keep it all documented.
What it can't do yet
The honest limits:
- The percentage table is a generic lead-acid curve. It isn't verified for this battery, which has been deeply discharged once.
- The ESP32 measures at the fused feed, not at the battery terminals, so wiring losses under load look like a lower battery voltage.
- Real consumption and remaining capacity need a shunt: a current sensor that every amp in and out of the battery passes through, from the caravan's own electrics to the mover and every charger. That's the next step, and it means rewiring, which I'm not doing yet.
Also on the list: gas-cylinder weight with an HX711 and a 50 kg load cell, IR control of the air conditioner using the inside temperature for overnight regulation, a small OLED showing battery status, and a 3D-printed PETG enclosure. The rule is the same for all of them: simple, low-power, standard parts I can change myself.
For now the battery has a voice. It can't say how much is left in the tank, but it can say "I'm getting low" before it's at 10 V again, and that's what I wanted first.
