Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 1225

Python • Waveshare UPS battery monitoring script - help needed

$
0
0
Hi guys 👋.

I have modified a script from Waveshare for my UPS on a Raspberry Pi that monitors battery in the background. With my small modification it should now show a warning and shut Pi safely when it's below 20%.

The thing is that I never see a warning for some reason. I start the script at boot via rc.local at boot and indeed it runs in the background.🤔
But warning only appears if I manually run the script from terminal.
Any ideas why?

Here's the full code:

Code:

import smbusimport timeimport osimport sys# Config Register (R/W)_REG_CONFIG                 = 0x00# SHUNT VOLTAGE REGISTER (R)_REG_SHUNTVOLTAGE           = 0x01# BUS VOLTAGE REGISTER (R)_REG_BUSVOLTAGE             = 0x02# POWER REGISTER (R)_REG_POWER                  = 0x03# CURRENT REGISTER (R)_REG_CURRENT                = 0x04# CALIBRATION REGISTER (R/W)_REG_CALIBRATION            = 0x05class BusVoltageRange:    """Constants for ``bus_voltage_range``"""    RANGE_16V               = 0x00      # set bus voltage range to 16V    RANGE_32V               = 0x01      # set bus voltage range to 32V (default)class Gain:    """Constants for ``gain``"""    DIV_1_40MV              = 0x00      # shunt prog. gain set to  1, 40 mV range    DIV_2_80MV              = 0x01      # shunt prog. gain set to /2, 80 mV range    DIV_4_160MV             = 0x02      # shunt prog. gain set to /4, 160 mV range    DIV_8_320MV             = 0x03      # shunt prog. gain set to /8, 320 mV rangeclass ADCResolution:    """Constants for ``bus_adc_resolution`` or ``shunt_adc_resolution``"""    ADCRES_9BIT_1S          = 0x00      #  9bit,   1 sample,     84us    ADCRES_10BIT_1S         = 0x01      # 10bit,   1 sample,    148us    ADCRES_11BIT_1S         = 0x02      # 11 bit,  1 sample,    276us    ADCRES_12BIT_1S         = 0x03      # 12 bit,  1 sample,    532us    ADCRES_12BIT_2S         = 0x09      # 12 bit,  2 samples,  1.06ms    ADCRES_12BIT_4S         = 0x0A      # 12 bit,  4 samples,  2.13ms    ADCRES_12BIT_8S         = 0x0B      # 12bit,   8 samples,  4.26ms    ADCRES_12BIT_16S        = 0x0C      # 12bit,  16 samples,  8.51ms    ADCRES_12BIT_32S        = 0x0D      # 12bit,  32 samples, 17.02ms    ADCRES_12BIT_64S        = 0x0E      # 12bit,  64 samples, 34.05ms    ADCRES_12BIT_128S       = 0x0F      # 12bit, 128 samples, 68.10msclass Mode:    """Constants for ``mode``"""    POWERDOW                = 0x00      # power down    SVOLT_TRIGGERED         = 0x01      # shunt voltage triggered    BVOLT_TRIGGERED         = 0x02      # bus voltage triggered    SANDBVOLT_TRIGGERED     = 0x03      # shunt and bus voltage triggered    ADCOFF                  = 0x04      # ADC off    SVOLT_CONTINUOUS        = 0x05      # shunt voltage continuous    BVOLT_CONTINUOUS        = 0x06      # bus voltage continuous    SANDBVOLT_CONTINUOUS    = 0x07      # shunt and bus voltage continuousclass INA219:    def __init__(self, i2c_bus=1, addr=0x40):        self.bus = smbus.SMBus(i2c_bus);        self.addr = addr        # Set chip to known config values to start        self._cal_value = 0        self._current_lsb = 0        self._power_lsb = 0        self.set_calibration_32V_2A()    def read(self,address):        data = self.bus.read_i2c_block_data(self.addr, address, 2)        return ((data[0] * 256 ) + data[1])    def write(self,address,data):        temp = [0,0]        temp[1] = data & 0xFF        temp[0] =(data & 0xFF00) >> 8        self.bus.write_i2c_block_data(self.addr,address,temp)    def set_calibration_32V_2A(self):        """Configures to INA219 to be able to measure up to 32V and 2A of current. Counter           overflow occurs at 3.2A.           ..note :: These calculations assume a 0.1 shunt ohm resistor is present        """        # By default we use a pretty huge range for the input voltage,        # which probably isn't the most appropriate choice for system        # that don't use a lot of power.  But all of the calculations        # are shown below if you want to change the settings.  You will        # also need to change any relevant register settings, such as        # setting the VBUS_MAX to 16V instead of 32V, etc.        # VBUS_MAX = 32V             (Assumes 32V, can also be set to 16V)        # VSHUNT_MAX = 0.32          (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)        # RSHUNT = 0.1               (Resistor value in ohms)        # 1. Determine max possible current        # MaxPossible_I = VSHUNT_MAX / RSHUNT        # MaxPossible_I = 3.2A        # 2. Determine max expected current        # MaxExpected_I = 2.0A        # 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)        # MinimumLSB = MaxExpected_I/32767        # MinimumLSB = 0.000061              (61uA per bit)        # MaximumLSB = MaxExpected_I/4096        # MaximumLSB = 0,000488              (488uA per bit)        # 4. Choose an LSB between the min and max values        #    (Preferrably a roundish number close to MinLSB)        # CurrentLSB = 0.0001 (100uA per bit)        self._current_lsb = .1  # Current LSB = 100uA per bit        # 5. Compute the calibration register        # Cal = trunc (0.04096 / (Current_LSB * RSHUNT))        # Cal = 4096 (0x1000)        self._cal_value = 4096        # 6. Calculate the power LSB        # PowerLSB = 20 * CurrentLSB        # PowerLSB = 0.002 (2mW per bit)        self._power_lsb = .002  # Power LSB = 2mW per bit        # 7. Compute the maximum current and shunt voltage values before overflow        #        # Max_Current = Current_LSB * 32767        # Max_Current = 3.2767A before overflow        #        # If Max_Current > Max_Possible_I then        #    Max_Current_Before_Overflow = MaxPossible_I        # Else        #    Max_Current_Before_Overflow = Max_Current        # End If        #        # Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT        # Max_ShuntVoltage = 0.32V        #        # If Max_ShuntVoltage >= VSHUNT_MAX        #    Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX        # Else        #    Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage        # End If        # 8. Compute the Maximum Power        # MaximumPower = Max_Current_Before_Overflow * VBUS_MAX        # MaximumPower = 3.2 * 32V        # MaximumPower = 102.4W        # Set Calibration register to 'Cal' calculated above        self.write(_REG_CALIBRATION,self._cal_value)        # Set Config register to take into account the settings above        self.bus_voltage_range = BusVoltageRange.RANGE_32V        self.gain = Gain.DIV_8_320MV        self.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S        self.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_32S        self.mode = Mode.SANDBVOLT_CONTINUOUS        self.config = self.bus_voltage_range << 13 | \                      self.gain << 11 | \                      self.bus_adc_resolution << 7 | \                      self.shunt_adc_resolution << 3 | \                      self.mode        self.write(_REG_CONFIG,self.config)    def getShuntVoltage_mV(self):        self.write(_REG_CALIBRATION,self._cal_value)        value = self.read(_REG_SHUNTVOLTAGE)        if value > 32767:            value -= 65535        return value * 0.01    def getBusVoltage_V(self):        self.write(_REG_CALIBRATION,self._cal_value)        self.read(_REG_BUSVOLTAGE)        return (self.read(_REG_BUSVOLTAGE) >> 3) * 0.004    def getCurrent_mA(self):        value = self.read(_REG_CURRENT)        if value > 32767:            value -= 65535        return value * self._current_lsb    def getPower_W(self):        self.write(_REG_CALIBRATION,self._cal_value)        value = self.read(_REG_POWER)        if value > 32767:            value -= 65535        return value * self._power_lsb        if __name__=='__main__':    # Create an INA219 instance.    ina219 = INA219(addr=0x42)    while True:        bus_voltage = ina219.getBusVoltage_V()             # voltage on V- (load side)        shunt_voltage = ina219.getShuntVoltage_mV() / 1000 # voltage between V+ and V- across the shunt        current = ina219.getCurrent_mA()                   # current in mA        power = ina219.getPower_W()                        # power in W        p = (bus_voltage - 6)/2.4*100        if(p > 100):p = 100        if(p < 0):p = 0                #checking for battery level to initiate safe shutdown below 20%:        if p < 90 and current < 0:          os.system("shutdown -h +1")          os.system("zenity --warning --text='Low battery. Shutting down in 60 seconds!'")          #os.system("./shutdown_message.sh")          #os.system("sudo poweroff")          sys.exit(0)                            # INA219 measure bus voltage on the load side. So PSU voltage = bus_voltage + shunt_voltage        #print("PSU Voltage:   {:6.3f} V".format(bus_voltage + shunt_voltage))        #print("Shunt Voltage: {:9.6f} V".format(shunt_voltage))        print("Load Voltage:  {:6.3f} V".format(bus_voltage))        print("Current:       {:9.6f} A".format(current/1000))        print("Power:         {:6.3f} W".format(power))        print("Percent:       {:3.1f}%".format(p))        print("")        time.sleep(2)
But please mainly look at this part:

Code:

 #checking for battery level to initiate safe shutdown below 20%:        if p < 90 and current < 0:          os.system("shutdown -h +1")          os.system("zenity --warning --text='Low battery. Shutting down in 60 seconds!'")          #os.system("./shutdown_message.sh")          #os.system("sudo poweroff")          sys.exit(0)
And here's what I have in rc.local:

Code:

in_sympathy@RaspberryPi5:~ $ cat /etc/rc.local #!/bin/sh -e## rc.local## This script is executed at the end of each multiuser runlevel.# Make sure that the script will "exit 0" on success or any other# value on error.## In order to enable or disable this script just change the execution# bits.## By default this script does nothing.# Print the IP address_IP=$(hostname -I) || trueif [ "$_IP" ]; then  printf "My IP address is %s\n" "$_IP"ficd /home/in_sympathy/Code/UPS_HAT_B/ && sudo python INA219.py &exit 0

Statistics: Posted by in_sympathy — Mon Jun 03, 2024 5:26 pm



Viewing all articles
Browse latest Browse all 1225

Trending Articles