Close

UPS-18650-NS Installed on the seismometer

A project log for Single-cell Li-Ion Powered UPS for Raspberry Pi

A simple yet complete UPS solution for most Raspberry Pi embedded applications, using a single-cell Li-Ion Battery.

bud-bennettBud Bennett 06/30/2017 at 22:520 Comments

The UPS-18650-NS is installed and working on my seismometer (I think.) The Raspberry Pi version that services the seismometer is a B+. The only way to know if it is working for sure is to disconnect power and wait 4-5 hours. Here's a photo of the installation:

I tried to get the UPS as far away from the capacitance-to-digital sensor as possible. I will have to perform a series of tests to see if the UPS needs to be shielded, but right now the seismometer appears to be working normally.

Here's the code that I'm using to monitor the UPS in the background:

#!/usr/bin/python3

'''
This program monitors the status of the UPS via the i2c interface and
manages the Raspberry Pi shutdown when the UPS signals that the battery
is exhausted. It lets the UPS determine when the battery is exhausted.
If the UPS battery voltage (VBAT) is greater than 3.2V, the status is checked
every minute. If VBAT < 3.2V then the checking interval is shortened to 1 second.
When the UPS asserts BATLOW = 1, the UPS will wait 5 seconds for the Raspberry Pi
to acknowledge by setting the SHUTDN bit. If the Pi sets SHUTDN = 1 then the UPS immediately
begins a 20 second timer to terminate the power. If the Pi has not set the SHUTDN bit
within the 5 second period then the UPS begins the 20 second timer irregardless.
So the Pi must initiate it's shutdown sequence immediately after receiving the BATLOW
signal from the UPS and sending/confirming the SHUTDN acknowledgement.
'''

from smbus import SMBus
import time, os
from datetime import datetime

ups_address = 0x36
i2c = SMBus(1)  # set interface to i2c-1
command = 0x00
VBAT = 5
bus_active = 0

def read_ups_data(address=0x36, cmd=0x00, debug=False):
    try:
        if debug: print('Sending command = {0:02x}'.format(command))
        word = i2c.read_word_data(ups_address, command)
        byte1 = 255 & word
        byte2 = word >> 8
        PWRGOOD = byte1 & 0x01
        BATLOW = (byte1 & 0x02) >> 1
        SHUTDN = (byte1 & 0x04) >> 2
        if byte2 != 0:
            VBAT = 2.048/byte2 * 255
        else:
            VBAT = 5.0
            if debug: print('ADC value error')
        bus_fail = 0
    except:
        bus_fail = 1
        VBAT = 5.0
        BATLOW = 0
        SHUTDN = 0
        PWRGOOD = 1
        if debug: print('I2C exception')

    if debug:
        print('PWRGOOD = {0}'.format(int(PWRGOOD)))
        print('BATLOW = {0}'.format(int(BATLOW)))
        print('SHUTDN = {0}'.format(int(SHUTDN)))
        print('VBAT = {0:.2f}\n'.format(VBAT))
    
    return PWRGOOD, BATLOW, SHUTDN, VBAT, bus_fail

time_now = datetime.now()
print("{0} Powerfail is active.".format(time_now))

while True:
    # read the UPS
    PWRGOOD, BATLOW, SHUTDN, VBAT, bus_fail = read_ups_data(ups_address, cmd=command, debug=False)
    
    # if the UPS has set BATLOW, then send SHUTDN command to initiate UPS shutdown
    # (but the UPS will shutdown in 5 seconds on its own...)
    if (BATLOW and not bus_fail):
        print('Sending shutdown command.')
        command = 0x04
        PWRGOOD, BATLOW, SHUTDN, VBAT, bus_fail = read_ups_data(ups_address, cmd=command, debug=False)


    # confirm that UPS received the shutdown command and then shutdown the Pi
    if (SHUTDN and command == 0x04):
        print('Shutting down now!')
        os.system("sudo shutdown -h now")
        while True:
            time.sleep(10)
    
    # check UPS status at 1 minute intervals until battery voltage drops below 3.2V, then
    # decrease interval to 1 second.
    if (VBAT < 3.2):   
        time.sleep(1)
    else:
        time.sleep(60)
I must get around to learning about logging someday...

Discussions