diff options
Diffstat (limited to 'powermanager/powermanage.py')
-rw-r--r-- | powermanager/powermanage.py | 606 |
1 files changed, 0 insertions, 606 deletions
diff --git a/powermanager/powermanage.py b/powermanager/powermanage.py deleted file mode 100644 index bc84d64..0000000 --- a/powermanager/powermanage.py +++ /dev/null @@ -1,606 +0,0 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- -########################################################################### -# Copyright (C) 2006 by Sebastian Kügler -# <sebas@kde.org> -# -# Copyright: See COPYING file that comes with this distribution -# -########################################################################### -# An API for changing the powerstate of a notebook - -import dbus -import dbus.glib -import os, time -from dcopext import DCOPClient, DCOPApp # Used for tdescreensaver -import xf86misc - -DEBUG = False - -def debug(msg): - """ Print debug message to terminal. """ - if DEBUG: - print msg - -# Default values for actions when battery runs out. -BATTERY_CRITICAL_MINUTES=5 - -# Only do an emergency suspend if charge level percentage is below ... -CHARGE_LEVEL_THRESHOLD = 10 - -isroot = os.environ["USER"] == "root" - -# Send suspend / hibernate commands to HAL or use Sx_COMMANDS -SUSPEND_USE_HAL = True - -# Show the cpu frequency widgets in the tooltip? -SHOW_CPUFREQ = True - - -# Command to initiate suspend-to-disk when not using HAL -S4_COMMAND = "/usr/local/bin/hibernate" -# Command to initiate suspend-to-ram when not using HAL -S3_COMMAND = "/usr/local/bin/s2ram" - -# Override isLaptop method -#IS_LAPTOP = True - -def _readValue(filename, line=0): - """ Reads a single value from the first line of a file. """ - fhandle = open(filename) - value = fhandle.readlines()[line][:-1] - fhandle.close() - return value - -class PowerManage: - """ Class providing low-level power managerment functionality. """ - - def __init__(self): - # (En|Dis)able using hdparm to set disk timeout - self.USE_HDPARM = True - # (En|Dis)able using laptop_mode to make the disk spin up less often - self.USE_LAPTOP_MODE = True - # (En|Dis)able using cpufreq to control cpu frequency scaling - self.USE_CPUFREQ = True - # (En|Dis)able using wireless adapter powermanagement (causes lag in network connection) - self.USE_WI_PM = True - # (En|Dis)able using display powermanagement - self.USE_DPMS = True - # (En|Dis)able using display brightness switching - self.USE_DISPLAY = True - # (En|Dis)able screensaver blankonly - self.SCREENSAVER_BLANKONLY = True - - - try: - xg = xf86misc.XF86Server() - self.xscreen = xg.getDefaultScreen() - except xf86misc.XF86Error: - print "Problem connecting to X server for idletime detection." - # Currently only used in the test method - self.display_dark = 0.5 - self.display_light = 1 - - # Some status initialisations - self.lowBatteryState = False - self.warningBatteryState = False - self.criticalBatteryState = False - - self.criticalBatteryState = False - self.lidClosedState = False - - # What does HAL support on this machine - self.hasBrightness = False - self.hasAC = False - self.hasLid = False - self.hasBattery = False - self.hasCpuFreqGovernors = False - - # Used to track if the previous check reported a battery to determine - # if we want to fire a notice "battery removed|plugged in" - self.wasOnBattery = False - self._initHAL() - self._initBrightness() - self._initBattery() - self._initAc() - self._initLid() - self._checkSuspend() - self._checkCpuCapabilities() - self._findDisks() - - def checkHAL(self): - """ Handle HAL and DBus restarts """ - try: - self.hal_manager.FindDeviceByCapability("") - except dbus.DBusException, e: - if str(e) == 'org.freedesktop.DBus.Error.Disconnected: Connection is closed' \ - or str(e) == 'org.freedesktop.DBus.Error.Disconnected: Connection was disconnected before a reply was received': - # DBus doesn't support on-the-fly restart - print "connection with DBus lost, please restart the display manager" - return - - if os.system("ps aux|grep [h]ald-runner") == 0: - print "connection with HAL lost, trying to reconnect" - self._initHAL() - self._initBrightness() - self._initBattery() - self._initAc() - self._initLid() - self._checkSuspend() - self._checkCpuCapabilities() - else: - print "HAL is not running" - - def isLaptop(self): - """ Detect if system is laptop. """ - try: - return IS_LAPTOP - except NameError: - pass - self.computerObject = self.bus.get_object("org.freedesktop.Hal", - u'/org/freedesktop/Hal/devices/computer') - properties = self.computerObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") - # formfactor sometimes (ppc) also reports "unknown" for laptops - # workaround: consider laptop anything with primary battery (see LP #64053) - return properties["system.formfactor"] == "laptop" or self.hasBattery - - def _findDisks(self): - """ Scan /sys/block for non-removable and non-ramdisks, used for hdparm actions, - currently not implemented in the powermanager frontend. """ - self.disks = [] - blk_path = "/sys/block/" - for d in os.listdir(blk_path): - # No RAM disks, no DM-RAID - if d.startswith("ram") or d.startswith("dm"): - continue - fhandle = open(blk_path+d+"/removable") - if fhandle.readlines()[0][:-1] == "0": - self.disks.append(d) - debug("Detected disks: "+" ".join(self.disks)) - - def onBattery(self): - """ Find out if we're on AC or on battery using HAL. """ - if not self.hasAC: - print "No AC adapter found - assume that we are on batteries." - return False - properties = self.acObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") - if properties.has_key("ac_adapter.present"): - return not properties['ac_adapter.present'] - else: - print "Error: ac_adapter has no property \"present\"" - return False - - def _initBattery(self): - """ Looks for a battery in HAL. """ - batteryDevices = self.hal_manager.FindDeviceByCapability("battery") - self.batteries = {} - self.batteryIsPresent = {} - - numBatt = 0 - for batt in batteryDevices: - battObj = self.bus.get_object("org.freedesktop.Hal", batt) - properties = battObj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") - if properties['battery.type'] != "primary": - continue - self.batteries[numBatt] = battObj - self.batteryIsPresent[numBatt] = properties['battery.present'] - numBatt += 1 - - if numBatt > 0: - self.hasBattery = True - else: - self.hasBattery = False - print "No battery found." - - def getBatteryState(self,batt): - """ Read battery status from HAL and return - (battery state, charge percentage, remaining seconds). - """ - try: - properties = self.batteries[batt].GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") - except dbus.DBusException: - print "problem getting battery state from dbus." - return "not present", 0, 0, 0, 0, 0 - - if not properties['battery.present']: - return "not present", 0, 0, 0, 0, 0 - else: - current = full = level = remain = rate = 0 - if properties.has_key("battery.charge_level.current"): - current = properties["battery.charge_level.current"] - if properties.has_key("battery.charge_level.last_full"): - full = properties["battery.charge_level.last_full"] - - if properties["battery.rechargeable.is_charging"]: - state = "charging" - elif properties["battery.rechargeable.is_discharging"]: - if self.onBattery(): - state = "discharging" - else: - state = "charged" - elif not properties["battery.rechargeable.is_discharging"] \ - and not properties["battery.rechargeable.is_charging"]: - if current == 0: - state = "empty" - else: - state = "charged" - else: - print "Unknown battery state ..." - - # Sometimes, HAL doesn't report the percentage, but we can compute that ourselves anyway - if properties.has_key("battery.charge_level.percentage"): - level = properties["battery.charge_level.percentage"] - elif current > 0 and full > 0: - level = current / full - - if state in ("charging","discharging"): - if properties.has_key("battery.remaining_time"): - remain = properties["battery.remaining_time"] - if properties.has_key("battery.charge_level.rate"): - rate = properties["battery.charge_level.rate"] - - return state, level, remain, rate, current, full - - def showInfo(self): - """ Outputs some random information to show that it does not work yet. """ - print "OnBattery:", self.onBattery() - print "CPUs:", len(self.cpus) - - def _initHAL(self): - """ Initialise HAL client to be used later. """ - self.bus = dbus.SystemBus() - hal_manager_obj = self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager") - self.hal_manager = dbus.Interface(hal_manager_obj, "org.freedesktop.Hal.Manager") - - def _initLid(self): - """ Find out if there's a Lid device. """ - lidDevice = self.hal_manager.FindDeviceStringMatch("button.type", "lid") - if len(lidDevice) >= 1: - self.hasLid = True - self.lidObject = self.bus.get_object("org.freedesktop.Hal" ,lidDevice[0]) - - def _initAc(self): - """ Search HAL for detecting if power is plugged in. """ - acDevice = self.hal_manager.FindDeviceByCapability("ac_adapter") - if len(acDevice) >= 1: - self.hasAC = True - self.acObject = self.bus.get_object("org.freedesktop.Hal" ,acDevice[0]) - - def _checkSuspend(self): - """ Ask HAL whether we can suspend / hibernate. """ - if SUSPEND_USE_HAL: - self.computerObject = self.bus.get_object("org.freedesktop.Hal", - u'/org/freedesktop/Hal/devices/computer') - properties = self.computerObject.GetAllProperties( - dbus_interface="org.freedesktop.Hal.Device") - self.canSuspend = properties["power_management.can_suspend"] - self.canHibernate = properties["power_management.can_hibernate"] - else: - self.canSuspend = self.canHibernate = True - - def _initBrightness(self): - """ Search HAL for a screen with brightness controls.""" - - brightnessDevice = self.hal_manager.FindDeviceByCapability("laptop_panel") - - if len(brightnessDevice) >= 1: - self.hasBrightness = True - self.brightnessObject = self.bus.get_object("org.freedesktop.Hal", brightnessDevice[0]) - self.brightness_properties = self.brightnessObject.GetAllProperties( - dbus_interface="org.freedesktop.Hal.Device") - try: - self.brightness_levels = self.brightness_properties[u'laptop_panel.num_levels'] - except KeyError,e: - self.hasBrightness = False - return 0 # Really don't know what to do here, but don't crash in any case. - try: - self.old_b = self.brightness_levels[-1] # Setting cached brightness value to brightest - except TypeError,e: - return 0 # Really don't know what to do here, but don't crash in any case. - - def getBrightness(self): - """ Read brightness from HAL. """ - if not self.hasBrightness: - debug("Brightness setting not supported.") - return - try: - b = self.brightnessObject.GetBrightness( - dbus_interface="org.freedesktop.Hal.Device.LaptopPanel") - except dbus.DBusException, e: - # Sometimes, right after resume, the HAL call - # fails, in that case, we return the last value - # and hope that it goes well next time. - print "Warning: in getBrightness(): ", e - # try and return the old brightness setting, but don't die in any case: - try: - return self.old_b - except AttributeError, errmsg: - return - self.old_b = b - return b - - def adjustBrightness(self, level): - """ Adjust the brightness via HAL. """ - if not self.hasBrightness: - debug("Brightness setting not supported.") - return - try: - self.brightnessObject.SetBrightness(level, - dbus_interface="org.freedesktop.Hal.Device.LaptopPanel") - except dbus.DBusException, e: - print e - - def _checkCpuCapabilities(self): - """ Find out the number of CPUs / cores, check which governors are avaible.""" - cpufreq_dir = "/sys/devices/system/cpu" - self.cpus = [] - for cpu in os.listdir(cpufreq_dir): - if cpu.startswith('cpu') and cpu != 'cpuidle': - self.cpus.append(cpu) - self.cpus.sort() - - # Map our policies to cpufreq governors. - self.cpu_policy = {} - self.cpu_policy['dynamic/ac'] = [] - self.cpu_policy['dynamic/battery'] = [] - self.cpu_policy['powersave'] = [] - self.cpu_policy['performance'] = [] - - try: - comp_obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/devices/computer') - self.cpufreq = dbus.Interface(comp_obj, 'org.freedesktop.Hal.Device.CPUFreq') - self.governor_available = self.cpufreq.GetCPUFreqAvailableGovernors() - except dbus.DBusException: - return - self.hasCpuFreqGovernors = True - - if 'ondemand' in self.governor_available: - self.cpu_policy['dynamic/ac'].append('ondemand') - self.cpu_policy['dynamic/battery'].append('ondemand') - if 'conservative' in self.governor_available: - self.cpu_policy['dynamic/ac'].append('conservative') - self.cpu_policy['dynamic/battery'].insert(0,'conservative') - if 'userspace' in self.governor_available: - self.cpu_policy['dynamic/ac'].append('userspace') - self.cpu_policy['dynamic/battery'].append('userspace') - if 'powersave' in self.governor_available: - self.cpu_policy['powersave'].append('powersave') - if 'performance' in self.governor_available: - self.cpu_policy['performance'].append('performance') - - def getSupportedCpuPolicies(self): - """ Report a list of supported CPU policies """ - policies = [] - if len(self.cpu_policy['dynamic/ac']) > 0: - policies.append('dynamic') - if len(self.cpu_policy['powersave']) > 0: - policies.append('powersave') - if len(self.cpu_policy['performance']) > 0: - policies.append('performance') - return policies - - def getCpuPolicy(self): - """ Translate current CPU frequency governor into policy """ - if not self.USE_CPUFREQ or not self.hasCpuFreqGovernors: - return "" - gov = self.cpufreq.GetCPUFreqGovernor() - for policy in self.cpu_policy.keys(): - if gov in self.cpu_policy[policy]: - return policy.split('/')[0] # strip ac or battery off - return gov ## return as-is - no conversion - - def setCpuPolicy(self,policy): - """ Using cpufreq governors. Mode is powersave, dynamic or performance. We're assuming that - the available governors are the same for all CPUs. This method changes the cpufreq - governor on all CPUs to a certain policy.""" - if not self.USE_CPUFREQ or not self.hasCpuFreqGovernors: - return False - - if policy == "dynamic": - if self.onBattery(): - policy = "dynamic/battery" - else: - policy = "dynamic/ac" - - for gov in self.cpu_policy[policy]: - try: - self.cpufreq.SetCPUFreqGovernor(gov) - return True - except dbus.DBusException: - pass - return False # no of governor worked - - def cpuIsOnline(self,cpu): - """ Check if cpu is online. CPU0 is always online, CPU1 might be unplugged. Since - /sys/devices/system/cpu/$cpu/cpufreq is not readable for normal users, we just - check for the cpufreq subdir (which is where it's really needed anyway). - """ - if cpu == "cpu0": return True - else: return os.path.isdir("/sys/devices/system/cpu/"+cpu+"/cpufreq") - - def getCpuState(self,cpu): - """ Reads the status of a CPU from /sys. """ - state = {} - state['online'] = self.cpuIsOnline(cpu) - if not state['online']: - debug("getCpuState: "+cpu+" is offline") - return state - try: - state['cpu'] = cpu - state['cur'] = int(_readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_cur_freq"))/1000 - state['governor'] = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_governor") - state['driver'] = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_driver") - state['steps'] = [] - freqs = _readValue("/sys/devices/system/cpu/"+cpu+"/cpufreq/scaling_available_frequencies") - except IOError: - # CPUFREQ has gone away, let's disable it. - state['online'] = False - return state - for v in freqs.split(): - state['steps'].append(int(v)/1000) - state['max'] = max(state['steps']) - state['min'] = min(state['steps']) - debug(state) - return state - - def getLidClosedState(self): - """ Returns True if the lid is currently closed, or False if it isn't. """ - try: - properties = self.lidObject.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") - return properties["button.state.value"] - except (KeyError, dbus.DBusException): - return False - - def setPowerSave(self, state): - # No SetPowerSave in Ubuntu's HAL - try: - self.computerObject.SetPowerSave(state, - dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") - except dbus.DBusException, e: - print "Warning: While setting SystemPowerManagement to ", state, ": ", - print e - - def blankScreen(self): - """ Call dpms to switch off the screen immediately. """ - os.system('xset dpms force standby') - - def setScreensaverBlankOnly(self,blankonly): - """ Switches a screensaver to blankonly, so cpu hungry screensavers will not drain the poor - battery.""" - # create a new DCOP-Client: - client = DCOPClient() - # connect the client to the local DCOP-server: - client.attach() - # create a DCOP-Application-Object to talk to amarok: - kdesktop = DCOPApp('kdesktop', client) - # call a DCOP-function: - ok, foo = kdesktop.KScreensaverIface.setBlankOnly(blankonly) - if not ok: - debug("Failed to set kdesktop screensaver to blankonly.") - return False - return True - - def getIdleSeconds(self): - """ Get idle seconds from X server. """ - return self.xscreen.getIdleSeconds() - - def resetIdleSeconds(self): - """ Reset idle seconds. """ - return self.xscreen.resetIdleSeconds() - - def test(self): - """ Try all kinds of stuff and see what breaks.""" - print "Trying to adjust brightness ..." - bright = self.getBrightness() - self.adjustBrightness(2) - time.sleep(1) - self.adjustBrightness(bright) - print " ... OK." - - if self.USE_CPUFREQ: - print "Reading speeds from cpufreq..." - for cpu in self.cpus: - print self.getCpuState(cpu) - print "Report supported cpufreq policies..." - for policy in self.cpu_policy.keys(): - print "Policy:", policy, "=", self.cpu_policy[policy] - - print "Trying all cpufreq policies ..." - orig_pol = self.getCpuPolicy() - for pol in self.cpu_policy.keys(): - print ". ", pol - self.setCpuPolicy(pol) - self.setCpuPolicy(orig_pol) - print "... OK." - else: - print "Skipping CPUFREQ: USE_CPUFREQ = False" - - if self.SCREENSAVER_BLANKONLY: - if self.setScreensaverBlankOnly(True): - debug("Manipulating screensaver seems to work well.") - else: - debug("Manipulating screensaver seems broken.") - - if isroot: - print "Trying to use Disk powermanagement and laptop_mode" - self.setDiskPM(True) - time.sleep(1) - self.setDiskPM(False) - print "...OK" - else: - print "Skipping DiskPM, not root." - - if self.hasLid: - if self.getLidClosedState(): - print "Lid is closed." - else: - print "Lid is currently open." - - def setDiskPM(self,on=True): - """ Switches on laptop_mode and sets disks to advanced powermanagement.""" - if self.USE_LAPTOP_MODE: - # Check if laptop_mode exists: - laptop_mode = "/proc/sys/vm/laptop_mode" - if not os.path.isfile(laptop_mode): - self.USE_LAPTOP_MODE = False - debug("Laptop mode not supported, no "+laptop_mode) - else: - fhandle = open(laptop_mode,"w") - if on: val = 1 - else: val = 0 - fhandle.write(str(val)) - fhandle.close() - - if self.USE_HDPARM: - # Set disks to advanced PM - for disk in self.disks: - if on: - # Switch on advanced powermanagement - cmd = "hdparm -B1 /dev/"+disk+" > /dev/null" - else: - # Switch off advanced powermanagement - cmd = "hdparm -B255 /dev/"+disk+" > /dev/null" - if os.system(cmd) != 0: - self.USE_HDPARM = False - print "Switching advanced powermanagement failed, not using hdparm anymore" - - def suspend(self): - """ Run a suspend command, either via HAL or script. """ - if SUSPEND_USE_HAL: - try: - self.computerObject.Suspend(0, dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") - except dbus.DBusException: - pass #we get a DBusException: No reply within specified time - else: - self._sleepMode(S3_COMMAND) - - def hibernate(self): - """ Implements suspend to disk (S4). """ - if SUSPEND_USE_HAL: - try: - self.computerObject.Hibernate(dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") - except dbus.DBusException: - pass #we get a DBusException: No reply within specified time - else: - self._sleepMode(S4_COMMAND) - - def _sleepMode(self, command): - """ Send the system into S3 or S4 not using HAL. """ - debug("Initiating a sleep cycle") - if os.system(command) != 0: - print "sleepmode failed. ("+command+")" - return False - debug("Everything is dandy") - return True - - def shutdown(self): - """ Shutdown the system via HAL. """ - self.computerObject.Shutdown(dbus_interface="org.freedesktop.Hal.Device.SystemPowerManagement") - - -if __name__ == "__main__": - """ Run some tests, used for debugging.""" - pman = PowerManage() - pman.showInfo() - pman.test() - |