Sunday, April 22, 2012

Windows Power Options, meet Python

According to Mac users, the world is divided into two main groups: those who use Macs and everyone else.

Not much of a fan of Apple’s products, but even I can’t deny they’re doing a great job with keeping a high uptime laptops using a precise power consumption control. Using power options built into drivers, with an operating system built from ground-up optimized for long use and with breakthrough battery technology, Macs today have the best energy efficient systems out there.

Although Windows lack a high level of power consumption, it offers a good infrastructure for developers.

My initial approach was to allow Windows to recognize some of the uses I make of my computer, and adapt itself accordingly.

There are two ways to accomplish this:

  1. Monitor processes via Windows Task Manager. If a known process was detected, act accordingly and change the power scheme.
  2. Monitor the currently active window by interacting with Windows GUI. If a known process was detected, act accordingly and change the power scheme.

Method 1

Advantages:

  1. See the big picture, If a user minimize the window for several seconds you’ll still be able to determine what’s running in the background.

Disadvantages:

  1. If a user minimize a known process, the code needs to be adjusted to detect the process is not in use.
  2. Additional coding is required to avoid conflicts between processes. If a user minimizes two known processes, the code should adjust itself.
  3. To efficiently scan the process list, the code should either enumerate every process which can take up the very same resources we’re trying to save, or query only for known processes, which can take up some memory maintaining such process list.

Method 2

Advantages:

  1. The code is always relevant to what the user is currently doing
  2. No need to enumerate the entire process list, only fetching the active window from the GUI using Windows API.

Disadvantages:

  1. In case a user minimizes a program, it can greatly affect its performance.
  2. Since the code doesn’t know the user intention, and since the user can minimize a program just for a couple of seconds, it is possible that switching several power schemes in a short time may affect your hardware in the long run.

Combining method 2 with a short grace period between fetching the active window, can eliminate disadvantage #2. Assuming enough power schemes will be created, it is possible to avoid disadvantage #1.

Let’s get busy
  1: #-------------------------------------------------------------------------
  2: # Name:        ActiveWindowSniffer
  3: # Author:      at0m
  4: # Created:     22/04/2012
  5: # Copyright:   (c) at0m 2012
  6: #-------------------------------------------------------------------------
  7: 
  8: #!/usr/bin/env python
  9: 
 10: import win32gui
 11: from time import sleep
 12: from subprocess import call
 13: from re import findall
 14: 
 15: w=win32gui
 16: powerschemes = {"Balanced":"381b4222-f694-41f0-9685-ff5bb260df2e",
 17:                 "Adobe Audition": "7a601a49-8d15-46d2-8160-55163f627070",
 18:                 "Internet":"8b12c7c4-a5e9-4e27-9283-338dc2138c2e",
 19:                 "Internet-Media":"b0e87387-1585-4351-894c-267adb53e563",
 20:                 "High Performance":"8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c",
 21:                 "Power Saver":"a1841308-3541-4fab-bc81-f71556f20b4a",
 22:                 "Balanced_TB_ON":"b18511ef-e34a-4f4b-85e7-2ea5cd1ac989",
 23:                 "Shuteye":"d7925c9e-bfc0-47d7-98c3-028edd2acb81",
 24:                 "Reading":"7c2951ff-7d0e-4609-9f68-d6428869cf5e",
 25:                 "Video Optimized":"e21061ef-9975-4822-9af5-6215c973a982"}
 26: 
 27: while True:
 28:     try:
 29:         sleep(15)
 30:         active_window = w.GetWindowText (w.GetForegroundWindow())
 31:         print_string = str(active_window) + " was detected, adjusting"
 32:         print print_string
 33: 
 34:         if "Mozilla Firefox" in active_window:
 35:             if "YouTube" in active_window or "Facebook" in active_window:
 36:                 call(["POWERCFG","-SETACTIVE",powerschemes["Internet-Media"]])
 37: 
 38:             elif "application/pdf Object" in active_window:
 39:                 call(["POWERCFG","-SETACTIVE",powerschemes["Reading"]])
 40: 
 41:             else:
 42:                 call(["POWERCFG","-SETACTIVE",powerschemes["Internet"]])
 43: 
 44:         elif "Adobe Audition" in active_window or "Saving" in active_window:
 45:             call(["POWERCFG","-SETACTIVE",powerschemes["Adobe Audition"]])
 46: 
 47:         elif "Torrent" in active_window:
 48:             call(["POWERCFG","-SETACTIVE",powerschemes["Shuteye"]])
 49: 
 50:         elif findall("\.(avi|wmv|mp4|mkv|mpg|mpeg)$", active_window) != None:
 51:             call(["POWERCFG", "-SETACTIVE", powerschemes["Video Optimized"]])
 52: 
 53:         else:
 54:             call(["POWERCFG","-SETACTIVE",powerschemes["Power Saver"]])
 55: 
 56:     except KeyboardInterrupt:
 57:         raise SystemExit

At lines 10-13 we’re importing the modules we need, amongst them is win32gui which is the heart of this all program.


At line 15, we’re allocating the Windows GUI to an object.


At line 16, I’ve created a dictionary to allow me to fetch my power schemes quickly. You can see your power schemes by using launching POWERCFG –L from the command line.


At line 29, we’re adding the 15 seconds grace period, you can change it to suit your needs.


Line 30 is the heart of this program, and using the GetForegroundWindow() function, Windows will retrieve the currently active window from Windows GUI API


Line 34-55, if a pattern was detected, activate the power scheme corresponding to the pattern using POWERCFG –SETACTIVE <power_scheme_GUID>


Cheers,


at0m q[^_^]p

Tuesday, April 10, 2012

Playing around with Bluetooth and Python

For those of you who don’t know Python, Python is a relatively new computer language that was quickly adopted by software giants such as Google, Microsoft, Red-Hat. Since Python has a very clear (almost algorithmic) syntax, anyone can learn it quickly, and if you have a little background in computer programing, it’s even easier. Because of those reasons, M.I.T had chosen Python in their introduction to computer programming.

If you’d like to get your hands a bit dirty, IronPython has a great tutorial with some hands on, highly recommended.

Since most of my work around computers involves Python for the past two years or so, I’ve decided to open a new section called the Python Challenge.

This week I was presented with a cool challenge: find a way to make your computer screen lock while you’re away from the computer.

My initial thought, Bluetooth! It has a short range, and Microsoft provides a nice interface to the Bluetooth stack. The only “disadvantage” is that you have to initially pair the device using Windows. This actually works for my advantage since it prevents possible malicious use.

The code below works only for locking the screen while away, and as a security precaution I’ve chosen not to include the section where the computer immediately logs on while you’re close to the computer.

Let’s get busy
  1: #!/usr/bin/env python
  2: 
  3: # Importing modules
  4: from bluetooth import *
  5: import time
  6: import subprocess
  7: 
  8: print "\nPlease wait while discovering devices...\n"
  9: 
 10: # Discovering devices
 11: devices = discover_devices(lookup_names=True)
 12: counter = 0
 13: for i,j in devices:
 14:     counter+=1
 15:     print "%d) %s - %s" % (counter,i,j)
 16: 
 17: device_num = raw_input("\n\nPlease select a device: ")
 18: selected_device =str(devices[int(device_num) - 1][0])
 19: print "Please wait, pairing with %s" % i
 20: 
 21: # Create the client socket
 22: client_socket=BluetoothSocket( RFCOMM )
 23: 
 24: # Attempt to pair
 25: try:
 26:     client_socket.connect((selected_device, 3))
 27: 
 28: except IOError:
 29:     print "Bluetooth error, check your settings"
 30:     raise SystemExit
 31: 
 32: except KeyboardInterrupt:
 33:     raise SystemExit
 34: 
 35: else:
 36:     print "Paired with %s... monitoring" % j
 37:     connected = True
 38:     locked = False
 39: 
 40: # Send Hi every second, and detect when connection is broken
 41: while 1:
 42:     try:
 43:         client_socket.send("Hi")
 44: 
 45:     except IOError:
 46:         if locked !=True:
 47:             locked = True
 48:             connected = False
 49:             subprocess.call("rundll32.exe user32.dll,LockWorkStation")
 50: 
 51:         if connected == False:
 52:             try:
 53:                 client_socket=BluetoothSocket( RFCOMM )
 54:                 client_socket.connect((selected_device, 3))
 55: 
 56:             except IOError:
 57:                 continue
 58: 
 59:             else:
 60:                 connected = True
 61: 
 62:     except KeyboardInterrupt:
 63:         client_socket.close()
 64: 
 65:     else:
 66:         locked = False
 67:         time.sleep(1)

Cheers,


at0m q[^_^]p