--- /dev/null
+#!/usr/bin/env python
+
+# This software is copyright Neil Brown 2009.
+# It is licensed to you under the terms of the
+# GNU General Public License version 2.
+#
+# Simple status icon and control window for monitoring the
+# battery on the Freerunner and selecting input current.
+#
+# battery images copied from openmoko-panel-plugin
+
+import sys
+import pygtk
+import gtk
+import os
+import gobject
+import pango
+import time
+
+capfile = "/sys/class/power_supply/battery/capacity"
+fullfile = "/sys/class/power_supply/battery/time_to_full_now"
+emptyfile = "/sys/class/power_supply/battery/time_to_empty_now"
+statusfile = "/sys/class/power_supply/battery/status"
+curlimfile = "/sys/class/power_supply/usb/device/usb_curlim"
+chgfile = "/sys/class/power_supply/usb/device/chgmode"
+danger_file = "/sys/class/power_supply/usb/device/force_usb_limit_dangerous"
+# 'fast 3' or ...
+currfile = "/sys/class/power_supply/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)
+ lim = file_num(curlimfile)
+ 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
+ if configwindow:
+ configwindow.update_labels()
+ else:
+ setfile(icon)
+ to = gobject.timeout_add(30*1000, update)
+
+##################################################################
+
+def to_time(num):
+ if num == 3932100:
+ return "--"
+ num = num / 10
+ 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)
+
+class BatteryConfig(gtk.Window):
+ def __init__(self, oneshot):
+ gtk.Window.__init__(self)
+ self.set_default_size(480,640)
+ self.set_title("Battery")
+ self.connect('destroy', self.close_win)
+ self.oneshot = oneshot
+
+ 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('Current', fd)
+ self.addlabel('ChargeMode', fd)
+ self.addlabel('Curr Lim', fd)
+ self.addlabel('TimeToFull', fd)
+ self.addlabel('TimeToEmpty', 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, "Suspend", self.suspend)
+ 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, "100mA", self.set_curr, 100)
+ self.add_button(h, fd, "500mA", self.set_curr, 500)
+ self.add_button(h, fd, "1 Amp", self.set_curr, 1000)
+
+ 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_curr(self, widget, curr):
+ try:
+ f = open(danger_file, "w")
+ f.write("%d" % curr)
+ f.close()
+ except:
+ pass
+
+ def suspend(self, widget):
+ os.system("apm -s")
+
+ def shutdown(self, widget):
+ os.system("halt")
+
+
+ def update_labels(self, *a):
+ self.labels['Capacity'].set_text(file_text(capfile))
+ self.labels['Status'].set_text(file_text(statusfile))
+ self.labels['Current'].set_text(file_text(currfile))
+ self.labels['ChargeMode'].set_text(file_text(chgfile))
+ self.labels['Curr Lim'].set_text(file_text(curlimfile))
+ self.labels['TimeToFull'].set_text(to_time(file_num(fullfile)))
+ self.labels['TimeToEmpty'].set_text(to_time(file_num(emptyfile)))
+ global icon
+ setfile(icon)
+
+def open_window(*a):
+ global configwindow
+ if configwindow:
+ configwindow.present()
+ else:
+ configwindow = BatteryConfig(False)
+##################################################################
+
+configwindow = None
+def main(args):
+ if len(args) == 1:
+ global icon
+ icon = gtk.StatusIcon()
+ setfile(icon)
+ icon.set_visible(True)
+ icon.connect('activate', open_window)
+ to = gobject.timeout_add(30*1000, update)
+ else:
+ global configwindow
+ configwindow = BatteryConfig(True)
+
+ gtk.main()
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))