--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (C) 2009-2011 Neil Brown <neilb@suse.de>
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# Simple status icon and control window for monitoring the
+# battery on the OpenPhoenux GTA04.
+# Monitors average current usage since last change in power
+# supply, or last time the 'Restart' button was pressed
+#
+# battery images copied from openmoko-panel-plugin
+
+import sys
+import pygtk
+import gtk
+import os
+import gobject
+import pango
+import time
+import suspend
+
+capfile = "/sys/class/power_supply/bq27000-battery/capacity"
+fullfile = "/sys/class/power_supply/bq27000-battery/time_to_full_now"
+emptyfile = "/sys/class/power_supply/bq27000-battery/time_to_empty_now"
+statusfile = "/sys/class/power_supply/bq27000-battery/status"
+status2file = "/sys/class/power_supply/twl4030_usb/status"
+onlinefile = "/sys/class/power_supply/twl4030_usb/online"
+ccfile = "/sys/class/power_supply/bq27000-battery/cycle_count"
+cffile = "/sys/class/power_supply/bq27000-battery/charge_full"
+cfdfile = "/sys/class/power_supply/bq27000-battery/charge_full_design"
+cnowfile = "/sys/class/power_supply/bq27000-battery/charge_now"
+chgfile = "/sys/class/power_supply/bq27000-battery/status"
+# 'fast 3' or ...
+currfile = "/sys/class/power_supply/bq27000-battery/current_now"
+filename = "/usr/local/pixmaps/battery_%03d.png"
+filename_charging = "/usr/local/pixmaps/battery_%03d_charging_%d.png"
+
+def file_text(name):
+ try:
+ f = open(name)
+ except:
+ return ""
+ t = f.read()
+ return t.strip()
+def file_num(name):
+ try:
+ i = int(file_text(name))
+ except:
+ i = 0
+ return i
+
+prevfile = ""
+def setfile(icon):
+ cap = file_num(capfile)
+ capr = int((cap+5)/10)*10
+ curr = file_num(currfile)
+ status = file_text(chgfile)
+ if status == "Charging":
+ lim = 1000
+ else:
+ lim = 0
+ if curr >= 0 or lim == 0:
+ f = filename % capr
+ else:
+ f = filename_charging % (capr, lim)
+ #print f
+ if f == prevfile:
+ return
+ icon.set_from_file(f)
+
+def update():
+ global icon
+ global configwindow
+
+ to = gobject.timeout_add(30*1000, update)
+
+ if configwindow:
+ configwindow.update_labels()
+ else:
+ setfile(icon)
+
+ return False
+
+##################################################################
+
+def to_time(num):
+ if num == 3932100:
+ return "--"
+ then = time.strftime("(%H:%M)", time.localtime(time.time()+num))
+ if num <= 90:
+ return "%d seconds %s" % ( num, then )
+ if num <= 90*60:
+ return "%dm%ds %s" % (num/60, num%60, then)
+ num = num / 60
+ return "%dh%dm %s" % (num/60, num%60, then)
+
+def to_percent(num,total):
+ if total == 0:
+ return "0%"
+ return "%d%%" % (num * 100 / total)
+
+class BatteryMonitor:
+ def __init__(self, logfile = None):
+ self.logfile = logfile
+ self.reset()
+ def reset(self):
+ self.period_start = time.time()
+ self.chg_start = file_num(cnowfile)
+ self.cur_start = file_num(currfile)
+ self.status = file_text(status2file)
+
+ def watch_restart(self, *args):
+ mesg = time.strftime("%Y/%m/%d %H:%M:%S") + " " + \
+ self.just_avg_curr() + ' ' + self.avg_period() + '\n'
+ if self.logfile:
+ try:
+ f = open(self.logfile, "a")
+ f.write(mesg)
+ f.close()
+ except:
+ pass
+ self.reset()
+
+ def check_restart(self):
+ st = file_text(status2file)
+ if st != self.status:
+ self.watch_restart()
+ return True
+ def avg_curr(self):
+ self.check_restart()
+ return self.just_avg_curr()
+
+ def just_avg_curr(self):
+ now = time.time()
+ chg = file_num(cnowfile)
+ if now < self.period_start + 5:
+ return "-"
+ return "%+d" %((self.chg_start - chg) * 3600 / (now - self.period_start))
+
+ def avg_period(self):
+ return "%d minutes" % ((time.time() - self.period_start) / 60)
+
+
+class BatteryConfig(gtk.Window):
+ def __init__(self, oneshot, monitor):
+ gtk.Window.__init__(self)
+ self.set_default_size(480,640)
+ self.set_title("Battery")
+ self.connect('destroy', self.close_win)
+ self.oneshot = oneshot
+ self.m = monitor
+
+ self.create_ui()
+ self.update_labels()
+ self.show()
+
+ def close_win(self, *a):
+ if self.oneshot:
+ gtk.main_quit()
+ else:
+ global configwindow
+ if configwindow == self:
+ configwindow = None
+ self.destroy()
+
+
+ def create_ui(self):
+ # two columns of name/value
+ v = gtk.VBox(); self.add(v)
+ ev = gtk.EventBox(); v.add(ev)
+ h = gtk.HBox(); ev.add(h)
+ h.set_homogeneous(True)
+ v1 = gtk.VBox(); h.add(v1)
+ v2 = gtk.VBox(); h.add(v2)
+ self.v1 = v1; self.v2 = v2
+ self.labels = {}
+
+ fd = pango.FontDescription("sans 10")
+ fd.set_absolute_size(25 * pango.SCALE)
+ self.addlabel('Capacity', fd)
+ self.addlabel('Status', fd)
+ self.addlabel('Status2', fd)
+ self.addlabel('Online', fd)
+ self.addlabel('Current', fd)
+ self.addlabel('Avg Current', fd)
+ self.addlabel('Avg Period', fd)
+ self.addlabel('Cycle Count', fd)
+ self.addlabel('Capacity Status', fd)
+ self.addlabel('TimeToFull', fd)
+ self.addlabel('TimeToEmpty', fd)
+ self.addlabel('FlightMode', fd)
+ ev.connect('button_press_event', self.update_labels)
+ ev.add_events( gtk.gdk.BUTTON_PRESS_MASK
+ | gtk.gdk.BUTTON_RELEASE_MASK)
+
+
+ # Row of Buttons
+ h = gtk.HBox(); v.pack_end(h, expand=False)
+ h.set_homogeneous(True); h.set_size_request(-1,80)
+ self.add_button(h, fd, "Close", self.close_win)
+ self.add_button(h, fd, "Shutdown", self.shutdown)
+ h = gtk.HBox(); v.pack_end(h, expand=False)
+ h.set_homogeneous(True); h.set_size_request(-1,80)
+ self.add_button(h, fd, "FlightMode", self.set_flight, True)
+ self.add_button(h, fd, "Normal", self.set_flight, False)
+ self.add_button(h, fd, "Restart", self.m.watch_restart)
+
+ v.show_all()
+
+
+ def addlabel(self, name, fd):
+ l = gtk.Label(name + ' : ')
+ self.v1.pack_start(l, expand=False)
+ l.set_alignment(1,0.5)
+ l.modify_font(fd)
+
+ l = gtk.Label("")
+ l.set_alignment(0,0.5)
+ self.labels[name] = l
+ self.v2.pack_start(l, expand=False)
+ l.modify_font(fd)
+
+ def add_button(self, parent, font, label, func, *args):
+ b = gtk.Button(label)
+ b.child.modify_font(font)
+ b.connect("clicked", func, *args)
+ parent.add(b)
+ b.show()
+
+ def set_flight(self, widget, set):
+ if set:
+ try:
+ f = open("/var/lib/misc/flightmode/active", "w");
+ f.write("Y")
+ f.close(f)
+ except:
+ pass
+ else:
+ try:
+ f = open("/var/lib/misc/flightmode/active", "w");
+ f.close(f)
+ except:
+ pass
+
+ def get_flight(self):
+ try:
+ f = open("/var/lib/misc/flightmode/active", "r")
+ l = f.read(1)
+ f.close()
+ except:
+ l = ""
+ if len(l) == 0:
+ flight="Disabled"
+ else:
+ flight="Enabled"
+ return flight
+
+ def shutdown(self, widget):
+ os.system("halt")
+
+
+ def update_labels(self, *a):
+ self.labels['Capacity'].set_text(to_percent(file_num(capfile), 100))
+ self.labels['Status'].set_text(file_text(statusfile))
+ self.labels['Status2'].set_text(file_text(status2file))
+ self.labels['Online'].set_text(file_text(onlinefile))
+ self.labels['Current'].set_text(file_text(currfile))
+ self.labels['Avg Current'].set_text(self.m.avg_curr())
+ self.labels['Avg Period'].set_text(self.m.avg_period())
+ self.labels['Cycle Count'].set_text(file_text(ccfile))
+ self.labels['Capacity Status'].set_text(to_percent(file_num(cffile),
+ file_num(cfdfile)))
+ self.labels['TimeToFull'].set_text(to_time(file_num(fullfile)))
+ self.labels['TimeToEmpty'].set_text(to_time(file_num(emptyfile)))
+ self.labels['FlightMode'].set_text(self.get_flight())
+ global icon
+ setfile(icon)
+
+def open_window(*a):
+ global configwindow
+ if configwindow:
+ configwindow.present()
+ else:
+ global monitor
+ configwindow = BatteryConfig(False, monitor)
+##################################################################
+configwindow = None
+monitor = None
+def main(args):
+ global monitor
+ try:
+ os.mkdir("/var/lib/misc/flightmode")
+ except:
+ pass
+ if len(args) == 1:
+ global icon
+ monitor = BatteryMonitor("/var/log/curr.log")
+ suspend.monitor(monitor.check_restart, monitor.check_restart)
+ icon = gtk.StatusIcon()
+ setfile(icon)
+ icon.set_visible(True)
+ icon.connect('activate', open_window)
+ to = gobject.timeout_add(30*1000, update)
+ else:
+ global configwindow
+ monitor = BatteryMonitor()
+ configwindow = BatteryConfig(True, monitor)
+
+ gtk.main()
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))