Introduction
My car tends to eat batteries! Sometimes, particularly during pandemic summers many weeks pass without the car being used, and during this time sometimes the battery discharges. I suspect the underlying problem is that somewhere current is leaking to ground, but that seems hard to fix. Instead, I’d be happy to just monitor the situation and charge the battery if needed.
The car is usually parked in range of the home WiFi network, so a convenient solution would be to have the car send me email about its battery every once in while. This article describes how to do just that.
All the files for this project are on GitHub1. The code is written in CircuitPython, the PCB was designed in KiCad, and the 3D-printable case was designed in OpenSCAD.
Design constraints
The only real constraint is that the device mustn’t draw too much current. To get a feel for the numbers say the car battery has a capacity of 100 amp hours, and in the absence of other drains we’d like a lifetime of about ten years (so that a month is roughly 1% of the capacity).
There are about 8,766 hours in a year, call it 10,000, and so about 100,000 hours in a decade. Our 100 amp hour battery can supply about 1mA for that time, so we should make sure that our gadget draws less than this.
Having satisfied the current constraint, I was keen to optimize for easy of implementation rather than anything. Rather than put components on a PCB, I was quite happy to use modules. Doubtless much smaller and cheaper designs exist, but I wasn’t fussed about that here.
Basic hardware
These days I think the default choice for random WiFi gadgets is something from the ESP32 family. I recently experimented with the ESP32S2 on the TinyS2 board, using a (slightly different) Pololu DC-DC converter to drop a 12V supply to 5V. You can read the details2 but the key numbers are:
State | Current consumption |
---|---|
Deep sleep | 90µA |
WiFi active | 45mA |
So, provided the WiFi isn’t on very often the current consumption might be an order of magnitude below the target.
I wanted to hear from the car every day but I don’t trust the accuracy of the clock, so I thought it best to send email every six hours. That way I can be reasonably confident of getting an email at night even if the car is away during the day.
It takes about 10s to connect to WiFi and send an email, so the duty cycle is 10s in 6 hours, or about 1 in 2000. This means that the average current for doing things is about 25µA, which when added to the sleep current of 90µA brings us to 115µA.
Schematic
Bill of Materials
Designator | Part | Footprint |
---|---|---|
U1 | Pololu D36V6F3 3.3V buck converter4 | |
U2 | TinyS25 | |
RV1 | V18AUMLA1210NH6 MLV | 1210 |
F1 | NANOASMDC010F-27 100mA polyfuse | 1206 |
D1 | SS248 Schottky diode | DO-214AA (SMB) |
R1 | 180k resistor | 0805 |
R2 | 33k resistor | 0805 |
C1 | 100nF X7R capacitor | 0805 |
Getting power
The gadget just needs a 12V power supply which is on even when the car is stopped and the engine’s off. I powered it from a cigarette lighter socket.
I bought a plug from Amazon which had both a fuse and LED. I replaced the fuse with one with a much lower current rating (500mA). The LED I removed completely: it drew a few mA!
Protection
I am no expert but I understand that the car’s 12V supply can be rather noisy so I made some attempts to protect the electronics. The DC-DC converter claims to support input voltages of 50V, so I just wanted something to handle spikes.
The delightfully named Littelfuse company make a wonderful range of varistors for precisely this task. These devices start to conduct if the voltage across them (in either direction) exceeds some threshold. If this went on for very long the magic smoke would escape, so I put a polyfuse in series with the supply.
Finally there’s a Schottky diode for reverse polarity protection.
Voltage sensing
The ESP32S2 has inbuilt ADCs, so all that’s needed is an external potential divider. The total resistance is about 200kΩ, which implies a current of about 60µA when fed with 12V.
Empirically a simple linear model was a good map from ADC count to input voltage. Fitting over the range 10–15V gives:
V = 4.0418 * (ADC / 10000) + 0.8294
which makes these predictions
True voltage / V | ADC count / 10,000 | Model value / V |
---|---|---|
6.0 | 1.2392 | 5.929 |
7.0 | 1.5132 | 7.021 |
8.0 | 1.7575 | 7.996 |
9.0 | 2.0196 | 9.041 |
10.0 | 2.2639 | 9.996 |
11.0 | 2.5221 | 11.015 |
12.0 | 2.7643 | 12.011 |
13.0 | 3.0146 | 13.010 |
14.0 | 3.2529 | 13.959 |
15.0 | 3.5071 | 14.973 |
Construction
Although the circuit is simple, I made a PCB to make things neat and tidy. I’d not realised that GPIO pin 0 is used by the bootloader, so had to bodge things a little. The files in the GitHub repo9 have been updated to fix this problem.
Software
All the software was written in CircuitPython. It is straightforward, but a few points are worth making:
We take all the ADC readings before turning on the WiFi because the wireless part draws lots of current which fluctuates rapidly.
Results are sent by SMTP to a mail server on the local network. I’ve written about this10 before.
There are three Python files:
code.py
11 which contains all the application code;tinys2.py
12 this comes with the TinyS2 and contains a driver for the onboard LED;secrets.py
13 this contains the WiFi access information, and details about the email setup.
Installation
There are four layers of software to consider.
The hardware bootloader in the ESP32. You need special software e.g. esptool14 to communicate with this.
A UF215 bootloader, which provides a USB mass-storage device to which firmware can be uploaded.
The CircuitPython binary, which is available as a UF2 image. When installed it provides a USB mass-storage device to which your Python code can be uploaded.
The Python files which contain your application.
The CircuitPython website has instructions16 for installing all this, and both the UF2 bootloader and CircuitPython UF2 images.
These are the steps:
Reset the board holding the BOOT button down.
Use esptool.py to install the UF2 boot loader (combined.bin).
Reset the board.
Install the CircuitPython UF2 image.
Reset the board.
Copy the three .py files to the board.
Reset the board.
Case
I designed a simple 3D-printable case in OpenSCAD. It is rather larger than necessary, but gives space to knot the incoming power cable to stop it being pulled out.
Conclusions
The device basically works as desired. The measured sleep current is about 130µA, so adding in the extra current used when active I expect the average to be about 155µA. This is a bit lower than I’d expected, probably because the DC-DC converter is a bit more efficient than in my earlier tests.
If I had time, it would be nice to fit all the components inside the cigarette-lighter plug but I doubt I’ll bother.
I am struck by just how easy it is to build something like this from pre-existing modules and Python, and still only sip power. I think we should all be thankful for the work that people have donated to the free commons which makes this possible.
References
- 1. https://github.com/mjoldfield/car-battery-monitor/
- 2. ../11/tiny-power.html
- 3. pcb.svg
- 4. https://www.pololu.com/product/3791
- 5. https://unexpectedmaker.com/tinys2
- 6. https://www.littelfuse.com/products/varistors/surface-mount/auml/v18aumla1210.aspx
- 7. https://www.littelfuse.com/products/polyswitch-resettable-pptcs/surface-mount/nanoasmd/nanoasmdc010f_2.aspx
- 8. https://www.taiwansemi.com/en/products/details/SS24
- 9. https://github.com/mjoldfield/car-battery-monitor/tree/main/pcb
- 10. ../11/python-smtp.html
- 11. https://github.com/mjoldfield/car-battery-monitor/blob/main/code/code.py
- 12. https://github.com/mjoldfield/car-battery-monitor/blob/main/code/tinys2.py
- 13. https://github.com/mjoldfield/car-battery-monitor/blob/main/code/secrets.py
- 14. https://github.com/espressif/esptool
- 15. https://github.com/microsoft/uf2
- 16. https://circuitpython.org/board/unexpectedmaker_tinys2/