Category Archive : Bus

As you may or may not know, I have a bus that I use as an RV. I use two large lead-acid batteries with a capacity of 280Ah each to power the lights, the fridge, the coffee maker, etc. The batteries are wired in series to give me 280Ah at 24V. As the batteries are starting to degrade to the point that it’s getting annoying and prices for Lithium-based batteries are coming down, I decided to ditch the lead-acid batteries and go for lithium instead. More specifically, Lithium iron phosphate (LiFePO4)

You can’t just wire up a couple of lithium cells in series and go camping. They need some additional stuff to keep them happy and safe. Since I like to fiddle with electronics and I certainly don’t mind saving some money in the process, I’m building the battery myself.

In this post I will explain which components I’ll use and why.

The cells

The 320Ah LiFePO4 cells I ordered

Lithium-based batteries can be discharged almost completely without damaging them, while lead-acid-based batteries need to be kept above 50% state of charge (SOC). Disobeying this rule will decrease the number of usable charge/discharge cycles. Lithium-based batteries also have the advantage of being lighter, smaller, and more efficient.

Lithium batteries come with some disadvantages as well. They’re more expensive, require additional electronics, some types can be dangerous if mishandled, and you can’t charge most types below freezing temperatures.

There are three main types of lithium batteries: Lithium-ion, lithium-iron-phosphate (LiFePO4), and lithium-titanate-oxide (LTO). All three types have their own characteristics, pros and cons.

  • Lithium-ion is relatively cheap. The life expectancy is the lowest of all lithium-based battery chemistries at 300 to 500 full cycles, making the cost per cycle not that great. The real showstopper for me is the fire hazard though. Lithium-ion batteries are infamous for their tendency to spontaneously catch on fire if mishandled. To make it worse: A lithium-ion fire is very hard to put out because li-ion cells produce their own oxygen while burning. Not something I want to be using in my RV.
  • Lithium-titanate-oxide (LTO) cells have a great life expectancy, as much as 20000 cycles. They can be charged in freezing temperatures and are almost impossible to set on fire. Sounds like the ideal battery chemistry, right? Unfortunately, all these advantages come at a cost. LTO cells are about four times as expensive as LiFePO4 cells. Even though the price per cycle is OK, the long life expectancy is not really an advantage as these cells would probably outlive my RV (and me).
  • Lithium-iron-phosphate (LiFePO4) cells have a life expectancy of up to 6000 cycles. Prices have come down significantly over the last year or so, and last but not least: They don’t ignite or explode. There are some more nerdy advantages like their stable output voltage, but that’s not really important.

One disadvantage all lithum-based batteries have is the need to protect them from high/low voltages, and high/low temperatures. You must also keep all individual cells in the pack at the same voltage. Fortunately, all this is now easily taken care of by one of the many battery management systems (BMS) you can now buy at reasonable prices. More on that topic later.

I ordered 8 320Ah LiFePO4 cells and some flexible busbars to connect them in series.


A BMS is responsible for the well-being of the individual cells in a battery. In the case of LiFePO4 cells, this means:

  • Make sure the battery can’t be charged below freezing. It’s okay to draw power from cold cells, but an attempt to charge them while frozen will damage the cells instantly.
  • Protect the cells from overheating.
  • Protect the cells from over-discharging by switching off the load if the cell voltage drops below 2,5V.
  • Protect the cells from overcharging by switching off the charger if the cell voltage reaches 2,65V.
  • Balance the cell voltages to make sure all cells are equally charged.

There are many BMS-es that offer these features. The main reason I chose the Seplos BMS V3, is because it can communicate with my Victron Cerbo GX. This allows me to really integrate the battery into my energy system and let it control my MPPT solar charge controller, among other things. It’s affordable, able to handle a decent amount of current (150A) and according to Andy over at the Off-grid garage, it works great if you use the latest software.

This BMS should also be able to control a battery heater. I have to figure out how to hook that all up when it arrives. The BMS will only turn on the heater if the cells are too cold and an attempt is made to charge the battery. Heating up the battery when it’s not going to be charged anyway is just a waste of energy. That’s why I didn’t want to use a thermostat.


I already mentioned that LiFePO4 cells can not be charged below freezing. I’m adding a couple of heaters to the battery pack to overcome that limitation. The heaters will be hooked up to the BMS, which switches them on if an attempt is made to charge the battery while it’s frozen. When the battery is heated up sufficiently, the BMS will automatically switch off the heaters and allow charging.


Lithium cells can deliver enormous amounts of current: The maximum allowed discharge current is 300A, although the BMS I chose is limited to 150A. The impedance of each cell is less than 0.25mΩ according to the specifications, which means that the short circuit current of a charged cell can be thousands of amps. That’s not good 🙂 I’ve ordered one of these breakers to make sure the current stays below 150A.


I wanted to have some neat battery terminals to mount in the box. I have to connect the finished battery one way or another. These ones can carry 200A and come with covers.

Torque wrench

The nuts on the cells need to be torqued to specification. No more than 8nm (5.9 lbf · ft) it says in the manual, so 5nm (3.7 lbf · ft) should be fine. I don’t want to over-tighten the nuts. The studs in the cells are aluminum. I’ve already seen people (on YouTube) rip the threads out. I own a torque wrench, but it’s a big one. It’s not suitable for small nuts like this. That’s why I ordered this one.

That’s it!

Well, almost. There’s some small stuff I’ve ordered like self-adhesive foam pads, but nothing really worth mentioning. So now it’s time to practice my patience and wait for all the parts to be delivered.

In the meantime, I will think about the mechanical part of this project. How to build the casing, where to position the terminals, the BMS display, the breaker, etc.

I have been looking for a good way to measure the amount of propane left in the tank in my RV. It turns out the manufacturer of the tank sells a gauge that can be easily fitted to the tank by replacing the old, non-electric one. How the sensor works is beyond the scope of this blog, what’s important is that the sensor has a variable resistance: 0 Ohms means the tank is empty, 90 Ohms means the tank is full (at 80%).

Of course, the manufacturer sells a display as well, but I wanted to connect the tank level sensor to my already existing ESP32-based logger. So I needed a way to measure resistance with a microcontroller. The most common and easy way is by pulling up an analog input of the controller and connecting the sensor between the analog input and ground, like this:

R2 is the sensor. It has a value between 0 Ohms and 90 Ohms. In order to be able to use the full range of the ESP32’s Analog to Digital Converter (ADC), Ohm’s law dictates that R1 should be 46 Ohms. We need 3.3V over R2 if it is at its maximum value of 90 Ohms. Therefore we need a current of 3.3/90 = 36.7mA. The voltage over R1 should be 1.7V (5V – 3.3V), so the value for R1 needs to be 1.7/0.0366 = 46 Ohms.

This solution is easy and cheap, but it has the disadvantage that the voltage at the analog input pin of the ESP32 (and thus the measured value in the software) is not linear to the value of R2 and therefore not linear to the amount of propane left in the tank.

This is due to the fact that if R2’s resistance changes, the current flowing through both resistors changes as well. This becomes clear if you look at the table below:

Tank levelResistanceVoltage% of voltage
0%0 Ohms0V0%
25%22.5 Ohms1.648%
50%45 Ohms2.472%
75%67.5 Ohms2.988%
100%90 Ohms3.3V100%
Output voltages of the voltage divider network at different tank levels.

As you can see, the behavior is not linear at all. Of course, this could be fixed in the software running on the ESP32, but the non-linearity makes the readings on one end of the range less accurate than on the other end.

Since the problem lies in the fact that a change in the resistance of R2 does also influence the current flowing through the circuit, I decided to solve this issue by using a constant current source. Building one is easier than you might think. Take a look at this circuit:

Measuring resistance with the help of a constant current source.

For now, just forget about C1, C2, and D1. I will get back to those later. U1 is a standard voltage regulator. It regulates it’s output voltage to a constant 5V, regardless of the output current or input voltage. This means that the voltage across R1 will always be 5V. R1 has a fixed value, therefore the current through R1 will be constant as well. Since R1 and R2 are in series, this also results in a constant current through R2.

To calculate the value for R1 we use Ohm’s law again. We still need the 36.7mA current through R2 to get 3.3V at full scale. 36.7mA at 5V means 5/0.0367 = 136 ohms. I’d use the next higher available value because in practice the current will be a little bit higher due to U1’s own power consumption.

With the current through R2 now being constant, the voltage at the input of the ESP32 will be linear to the resistance of R2 and thus linear to the propane level in the tank.

So what’s up with C1, C2 and D1?

First the capacitors C1 and C2. They keep U1 from oscillating. D1 is added as a safety measure. Because of the voltage drop between the input and the output of U1, the supply voltage needs to be higher than 5V. I use 12V in this example, but anything between 7V and 40V is fine. If R2 is for some reason disconnected, this would cause a voltage of around 9V on the input pin of the ESP32, which will probably destroy it.

If you would like to learn more and fiddle around with Ohm’s law and voltage divider networks, take a look at this page.

A couple of years ago I bought a coach and converted it into an RV. After the first season, I parked it and hooked up a battery charger to keep the batteries charged during winter. When the winter was over, I found out that the charger blew a fuse and my batteries were dead. I decided to add some monitoring. I bought a Victron BMV 702 battery monitor (which has both a display and a serial connection), hooked it up to an ESP32 microcontroller and started fiddling around with it. Soon the project exploded. I hooked up a couple of DS18b20 temperature sensors, my Victron MPPT solar charge controller (which has a serial connection as well) and a cheap GPS module I bought off eBay.

Hardware specs:

ESP32 dev board (NodeMCU-32S)
  • ESP32 microcontroller (with built-in WiFi)
  • USB connection for programming/debugging
  • Power input (5V)
  • 2 Optically isolated serial inputs (for Victron VE.bus)
  • 1 Non-isolated serial input (for GPS receiver)
  • “1-wire” I/O (for Dallas DS18B20 temperature sensors)
  • 3 General purpose I/O’s (can be used as digital input or output, analog input, PWM output, RS232. I2C etc)
  • 2 Onboard relays (dry contact outputs)


The software is written in C++ using the Arduino IDE.

Current software features :

  • Reading and parsing of VE.bus messages from a Victron BMV series battery monitor.
  • Reading and parsing of VE.bus messages from a Victron MPPT solar charge controller.
  • Reading various temperatures (inside, outside, hot water, etc.) using up to 10 Dallas DS18B20 1Wire temperature sensors.
  • Reading and parsing of NMEA data from a GPS receiver.
  • GPS location upload supports both GeoHash and Lat/Lon.
  • Reading a resistive tank level sensor.
  • Measurements can be uploaded to a server using http(s) GET.
  • Measurements can be written directly to Influxdb. Both http and https are supported.
  • Switching on the 24V to 12V DC/DC converter to charge the 12V battery if the 24V battery voltage is above a certain level. Switching of if the voltage drops below a certain level. The DC/DC converter is switched by one of the two onboard relays. 24V battery voltage measurements are read from the Victron BMV battery monitor.
  • Data upload is encrypted (HTTPS).
  • Over-the-air software updates (OTA). New software images are automatically downloaded on a seperate partition of the flash memory and verified. If verification is successfull, the ESP32 automatically boots the new image. Both upgrades and downgrades are supported.
  • Most settings (WiFi SSID and password, Influxdb hostname, username/password, what measurements to write etc) are configurable through the web interface.
  • Settings are stored on a separate partition of the SPI Flash File System (SPIFFS) and are therefore not lost after a software upgrade.
  • Measurement collection runs in a separate background task.
  • All measurements can be downloaded directly from the web interface in JSON format.
  • A portal is available for those who do not want to set up their own server for software updates etc. When using the portal for management, data can still be written to your own Influxdb instance.


PCB design
PCB design 3D model


None of the items on my todo list require any hardware updates. Luckily the ESP32 is flexible enough to facilitate all the things I thought of after I had the PCBs produced. Until now, at least 🙂 This is mainly because of the built-in matrix switch which allows you to assign any function (like UART RX, UART TX, digital in, digital out, analog in, PWM out) to any IO pin.

  • Add an extra temperature sensor to measure the temperature of the water heater. No extra I/O’s needed, extra sensors can be connected parallel to the existing ones since every DS18B20 sensor has a unique address.
  • Make the resistive tank sensor configurable.
  • Finish the portal.
  • Tweak the “12V charger on/off” criteria.


The schematics and PCB design can be found in the download section.
The code is on GitHub.
The portal can be found at

The live telemetry page of my bus can be found here.
I visualize the data using Grafana.