Raspberry Pi Zero Lipo Fuel Gauge With Safe Shutdown

The Pi Zero (and Zero W) are quite tolerant in respect to their power requirements. They can even be run from a LiFePO4 battery that has a voltage range of 3.6 to 2.5V. LiPo batteries are better-suited as their voltage ranges from 4.2 down to about 3V. When running the boards from the blank cell (it should have protection circuitry!), they last even longer because fewer losses occur since there is no boost converter in the system. In fact, the 5V is only needed for the USB host, although many devices are supposed to work from voltages down to 3V.


Unfortunately, these single board computers lack power management and don’t have shutdown buttons and there are not that many simple and cost-effective solutions for these problems. https://www.tindie.com/products/xorbit/lifepo4weredpi/ is one nice example, but unfortunately not fully open source.
My idea was to combine a MAX17043 LiPo fuel gauge with a pushbutton and a LiPo charging circuit to create a battery and safe shutdown management add-on for the Pi Zero.









The little board occupies only the first 10 pins and uses only GPIO4 and SDA + SCL. Design files for the tiny custom TP4056 charger board can be downloaded as a .zip archive:


TP4056mCH

The Python script the make the thing work is attached below. Add it to rc.local to execute on startup.


#!/usr/bin/python

#Python Script for MAX17043 fuel gauge and safe shutdown button
#in order to execute on startup add the following line to /etc/rc.local
#(sleep 10;python /home/pi/fuelgauge.py) &
#assuming that fuelgauge.py is in /home/pi 
#sleep 10 is probably not necessary

import RPi.GPIO as GPIO
import smbus
import time
import os


#threshold in % below which the pi gets shut down
threshold=15.0
buttonPin=4
# I2C-Adddress of MAX17043
address = 0x36

#registers
VCELL_REGISTER=0x02
SOC_REGISTER=0x04
MODE_REGISTER=0x06
VERSION_REGISTER=0x08
CONFIG_REGISTER=0x0C
COMMAND_REGISTER=0xFE

#  open the bus by creating an instance
MAX17043 = smbus.SMBus(1)

#set up GPIO for shutdown button
GPIO.setmode(GPIO.BCM)
#Using GPIO nr 4
GPIO.setup(buttonPin,GPIO.IN,pull_up_down=GPIO.PUD_UP)

def reset():
    MAX17043.write_byte_data(address, COMMAND_REGISTER, 0x00)
    MAX17043.write_byte_data(address, COMMAND_REGISTER, 0x04)

def quickStart():
    MAX17043.write_byte_data(address, MODE_REGISTER, 0x40)
    MAX17043.write_byte_data(address, MODE_REGISTER, 0x00)

#get state of charge
def getSOC():
    # Konfiguration des MAX17043
    MSB= MAX17043.read_byte_data(address, SOC_REGISTER)
    LSB = MAX17043.read_byte_data(address, SOC_REGISTER)
    percentage= MSB+ LSB/256.0
    #print percentage
    if percentage < threshold:
        os.system("sudo shutdown -h now")


#Arduino map function for convenience
def arduino_map(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min

#setup
reset()
quickStart()

# Loop
while True:
    getSOC()
    time.sleep(1.5)
    #shutdown if button is pressed and held
    if (GPIO.input(buttonPin)==0):
        os.system("sudo shutdown -h now")


if __name__ == "__main__":
   main()


5 thoughts on “Raspberry Pi Zero Lipo Fuel Gauge With Safe Shutdown”

    1. um, good question, thanks for the hint. This has to be verified somehow. Since I’m resetting on startup, I have no clue whether it really works out. If you figure it out let me know.

      1. Seems the instructions by BYTE dosn’t work on all registers.

        Datasheet 17043/44: “Register reads and writes are only valid if all 16 bits are transferred.”

        Datasheet 17048/49, same device, more sw-features: “All registers must be written and read as 16-bit words; 8-bit writes cause no effect.”

        So the read and return of the SOC- or CONFIG-register by byte results twice times in LSB (0x05/0x0c). Datasheet SOC: “The upper byte least-significant bit has units of 1%. The lower byte provides additional resolution.”.

        Same problem by writing by byte, instead use word. I can’t check if quickstart or reset happens. In your script there is no need to reset and quickstart at the same time.

        Pls check your chip version nr:

        print hex ( MAX17043.read_word_data ( address, 0x08 ) )

        Mine shows 0x1200.

        1. Hey, I tried “print hex ( MAX17043.read_word_data ( address, 0x08 ) )”, but got no output. Neither with read_byte_data, nor with read_word data.
          Are chip versions that different? Annoying!

          1. Tx4testing.

            Yes, chip versions are different, mine must be a MAX17048 (can’t read the text on the chip) , yours a MAX17043. But there is no difference by accessing the version register. Yours shoult show a “3” or 0x0300, mine shows “18” or 0x1200 which “can” be the chiptype MAX1704(8). But I’m not shure.

            MAX1704(3), MAX1704(4), MAX1704(8), MAX1704(9)

            Try this:

            #!/usr/bin/python
            # tested on a RPi 2
            import smbus
            MAX17043 = smbus.SMBus(1)
            print hex ( MAX17043.read_word_data ( 0x36, 0x08 ) )

Leave a Reply

Your email address will not be published. Required fields are marked *