- Stuff
- Monday, October 16th, 2006 at 5:33:33pm MDT
- #!/usr/bin/python
- #
- # battstat
- #
- # Copyright (C) 2006 by Tyler Gates <TGates81@gmail.com>
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- # USA.
- #
- import os, sys, re
- # globals
- if os.path.isdir("/proc/acpi/battery"): batt_basedir = "/proc/acpi/battery"
- else: batt_basedir = "/proc/apm/battery"
- def get_batts():
- """ return an array of all available batteries in batt_basedir """
- try:
- return os.listdir(batt_basedir)
- except Exception, e:
- print >>sys.stderr.write("Unable to find a battery in '"+batt_basedir+"'")
- return None
- def read_lines(file):
- """ read file contents and return readlines() """
- try:
- f = open(file)
- string = f.readlines()
- f.close()
- return string
- except Exception, e:
- print >>sys.stderr.write("Unable to open '"+file+"':\n" +str(e))
- return None
- def get_value(contents, property):
- """ return value of property from file contents (readlines) """
- for c in contents:
- if property in c:
- try:
- return c.split(':')[1].strip()
- except IndexError, e:
- print >>sys.stderr.write("Unable to parse file contents: "+str(e))
- return None
- return None
- def batt_percent(capacity, remaining_capacity):
- """ calculate and return remaining battery percentage as a string """
- # strip out units
- try:
- capacity = float(re.sub('\D', '', capacity))
- remaining_capacity = float(re.sub('\D', '', remaining_capacity))
- except:
- # must be 'unknown' values, i.e. a bad battery return N/A
- return 'N/A'
- # convert to float and calculate
- percent = float((remaining_capacity * 100) / capacity)
- # round to hundredths. 23.3524 || 23.3245 -> 23.35999 || 23.35000 + 0.001 = 23.360 || 23.351
- percent = round(percent, 2) + 0.001
- percent = str(percent)
- # remove extra thousandths place from rounding
- percent = percent[:(len(percent)-1)]
- return percent
- def time_left(remaining_capacity, present_rate):
- """ calculate and return remaining time in 00:00 hours units """
- # strip units
- try:
- remaining_capacity = float(re.sub('\D', '', remaining_capacity))
- present_rate = float(re.sub('\D', '', present_rate))
- except:
- return 'N/A'
- # get decimal time i.e. 1.34 hours
- decimal_time = remaining_capacity / present_rate
- # round to hundreths (see batt_percent() for more info)
- decimal_time = round(decimal_time, 2) + 0.001
- decimal_time = str(decimal_time)
- decimal_time = decimal_time[:(len(decimal_time)-1)]
- # split to the left and right of the decimal and convert the right (hundredths) to minutes
- whole = decimal_time.split('.')[0]
- # pad <num> to 0<num>
- if len(whole) == 1: whole = '0'+whole
- hundredths = decimal_time.split('.')[1]
- # convert hundredths place to minutes
- minutes = (int(hundredths) * 60) / 100
- minutes = str(minutes)
- if len(minutes) == 1: minutes = '0'+minutes
- return whole+':'+minutes
- def capacity_deviation(capacity, design_capacity):
- """ calculate and return the gain or loss of capacity based on spec and last charge """
- try:
- int_capacity = int(re.sub('\D', '', capacity))
- int_design_capacity = int(re.sub('\D', '', design_capacity))
- if int_capacity > int_design_capacity:
- diff = int_capacity - int_design_capacity
- diff = str(diff)
- return '+'+batt_percent(capacity, diff)
- elif int_capacity < int_design_capacity:
- diff = int_design_capacity - int_capacity
- diff = str(diff)
- return '-'+batt_percent(design_capacity, diff)
- else: return '0.00'
- except:
- return 'N/A'
- def main(battery):
- batt_dir = os.path.join(batt_basedir, battery)
- # info data
- info_file = os.path.join(batt_dir, 'info')
- info_contents = read_lines(info_file)
- if not info_contents: sys.exit(1)
- # state data
- state_file = os.path.join(batt_dir, 'state')
- state_contents = read_lines(state_file)
- if not state_contents: sys.exit(1)
- charging_state = get_value(state_contents, 'charging state')
- remaining_capacity = get_value(state_contents, 'remaining capacity')
- present_rate = get_value(state_contents, 'present rate')
- capacity_low = get_value(info_contents, 'design capacity low')
- capacity_warning = get_value(info_contents, 'design capacity warning')
- manufacturer = get_value(info_contents, 'OEM info')
- model_number = get_value(info_contents, 'model number')
- battery_type = get_value(info_contents, 'battery type')
- battery_tech = get_value(info_contents, 'battery technology')
- design_capacity = get_value(info_contents, 'design capacity')
- last_full_capacity = get_value(info_contents, 'last full capacity')
- if last_full_capacity != '':
- capacity = last_full_capacity
- else:
- capacity = design_capacity
- # calculate percent left on battery
- percent_left = batt_percent(capacity, remaining_capacity)
- # calculate capacity gain or loss
- capacity_dev = capacity_deviation(capacity, design_capacity)
- # determine time remaining based on charging state
- if charging_state == 'discharging':
- # time left to discharge
- time_remaining = time_left(remaining_capacity, present_rate)
- elif charging_state == 'charging':
- # time left to charge
- # use the difference between total capacity and remaining capacity
- try:
- remaining = int(re.sub('\D', '', remaining_capacity))
- capy = int(re.sub('\D', '', capacity))
- net = capy - remaining
- net = str(net)
- time_remaining = time_left(net, present_rate)
- except:
- time_remaining = 'N/A'
- else:
- # must be charged: nothing to calculate; ACPWR
- time_remaining = "--:--"
- # determine alert status
- try:
- if int(re.sub('\D', '', remaining_capacity)) <= int(re.sub('\D', '', capacity_low)): alert = 'LOW!'
- elif int(re.sub('\D', '', remaining_capacity)) <= int(re.sub('\D', '', capacity_warning)): alert = 'WARNING!'
- else: alert = 'ok'
- except:
- alert = 'N/A'
- # manufacturer, model number and battery technology may not have values; use N/A for screen output
- if not manufacturer: manufacturer = 'N/A'
- if not model_number: model_number = 'N/A'
- if not battery_tech: batter_tech = 'N/A'
- # don't display anything larger than 100.00%
- try:
- if float(percent_left) > 100.00: percent_left = '100.00'
- except:
- pass
- # output 100.00% if we have a 'charged' state
- if charging_state == 'charged': percent_left = '100.00'
- # output to screen
- print " << "+battery+" >>"
- print manufacturer+' - '+model_number+' | '+battery_type+' | '+battery_tech
- print "Remaining Charge : "+percent_left+" %"
- print "Time Left : "+time_remaining+' Hrs'
- print "Charging State : "+charging_state
- print "Rated Capacity Deviation : "+capacity_dev+" %"
- print "Charge Alert : "+alert
- if __name__ == "__main__":
- batteries = get_batts()
- if not batteries: sys.exit(1)
- for battery in batteries:
- main(battery)
advertising
Update the Post
Either update this post and resubmit it with changes, or make a new post.
You may also comment on this post.
Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.