source: trunk/LocationDo/LocationDo.py@ 196

Last change on this file since 196 was 196, checked in by Nicholas Riley, 18 years ago

LocationDo

File size: 7.7 KB
Line 
1#!/usr/bin/pythonw
2# -*- coding: utf-8 -*-
3
4from AppKit import NSApplication, NSBeep, NSSystemDefined, NSURL, NSWorkspace
5from Foundation import NSDistributedNotificationCenter, NSLog
6from PyObjCTools import AppHelper
7from Carbon.CarbonEvt import RegisterEventHotKey, GetApplicationEventTarget
8from SystemConfiguration import *
9from appscript import app
10import re
11import sets
12
13import action
14
15GROWL_APP_NAME = 'LocationDo'
16NOTIFICATION_LOCATION = 'Location'
17NOTIFICATION_ARRIVE = 'Arrive'
18NOTIFICATION_DEPART = 'Depart'
19NOTIFICATION_CURRENT = 'Current location'
20NOTIFICATION_UNKNOWN = 'Unknown location'
21NOTIFICATION_READY = 'Ready'
22NOTIFICATIONS_ALL = [NOTIFICATION_LOCATION, NOTIFICATION_ARRIVE,
23 NOTIFICATION_DEPART, NOTIFICATION_CURRENT,
24 NOTIFICATION_UNKNOWN, NOTIFICATION_READY]
25
26DEBUG = True
27
28kEventHotKeyPressedSubtype = 6
29kEventHotKeyReleasedSubtype = 9
30
31RE_AIRPORT_STATUS = '/'.join([kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompInterface, kSCCompAnyRegex, kSCEntNetAirPort])
32
33growl = app('GrowlHelperApp')
34
35growl.register(
36 as_application=GROWL_APP_NAME,
37 all_notifications=NOTIFICATIONS_ALL,
38 default_notifications=NOTIFICATIONS_ALL)
39
40def growlNotify(name, title, description, **kw):
41 params = dict(with_name=name,
42 title=title,
43 description=unicode(description),
44 application_name=GROWL_APP_NAME,
45 image_from_location='/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericNetworkIcon.icns')
46 params.update(kw)
47 if not params.get('sticky', False):
48 params['identifier'] = name
49 if DEBUG:
50 NSLog("%s: %s" % (title, description))
51 growl.notify(**params)
52
53class Location(sets.Set):
54 def __str__(self):
55 if not self: return '(unknown)'
56 return ', '.join(self)
57
58currentLocation = Location()
59
60def arriveAtLocation(location):
61 growlNotify(NOTIFICATION_ARRIVE, 'Arriving at location', location)
62 if 'Siebel' in location:
63 action.ensureKerberosPrincipalsValid(['njriley@ACM.UIUC.EDU',
64 'njriley@AD.UIUC.EDU'])
65 action.setVolumePercent(0.15)
66 if '1115 SC' in location:
67 action.openInBackground('~/Documents/CS 423/CS 423 to do.oo3')
68 action.setDisplayBrightnessPercent(0.2)
69 action.setAdiumStatus('Working in 1115 SC')
70 if '4111 SC' in location:
71 action.openInBackground('~/Documents/MSSP/MSSP progress.oo3')
72 action.setDisplayBrightnessPercent(0.9)
73 action.setAdiumStatus('Working in 4111 SC')
74 if 'ACM office' in location:
75 action.setDisplayBrightnessPercent(0.2)
76 action.setAdiumStatus('At ACM')
77 if 'Champaign' in location:
78 action.openInBackground('~/Documents/To do.oo3')
79 action.setDisplayBrightnessPercent(0.2)
80 action.setVolumePercent(0.5)
81 action.setAdiumStatus('At home')
82 if '1320 DCL' in location:
83 action.setDisplayBrightnessPercent(0.2)
84 action.setVolumePercent(0)
85 action.setAdiumStatus('In 1320 DCL')
86 if 'UIUCnet' in location:
87 action.startVPNC('UIUCnet-oncampus')
88 if 'CSL' in location:
89 action.setDisplayBrightnessPercent(0.1)
90 action.setVolumePercent(0)
91 action.setAdiumStatus('At CSL')
92 action.openURL('http://wireless.csl.uiuc.edu/authenticate.html')
93 growlNotify(NOTIFICATION_ARRIVE, 'Arrived at location',
94 location)
95
96def departLocation(location):
97 growlNotify(NOTIFICATION_DEPART, 'Departing location', location)
98 if 'UIUCnet' in location:
99 # XXX should handle this more symmetrically
100 action.stopVPNC()
101 growlNotify(NOTIFICATION_DEPART, 'Departed location', location)
102
103def locationChanged(location):
104 if not location: return # unknown
105 global currentLocation
106 oldLocation = currentLocation - location
107 newLocation = location - currentLocation
108 if DEBUG:
109 NSLog("new %s | was %s | departing %s | arriving %s" % \
110 (location, currentLocation, oldLocation, newLocation))
111 if oldLocation:
112 departLocation(oldLocation)
113 currentLocation = location
114 if newLocation:
115 currentLocation = location
116 arriveAtLocation(newLocation)
117
118def formatMACAddress(data):
119 return ':'.join(re.findall('..', data.bytes()[:].encode('hex')))
120
121# XXX watch battery status, too, for display brightness
122
123airPortStatus = {'BSSID': None, 'SSID': None}
124
125class SCWatcher(NSObject):
126 def keysChanged_inDynamicStore_(self, changed, store):
127 location = Location()
128 for key in changed:
129 if re.match(RE_AIRPORT_STATUS, key):
130 st = store.valueForKey_(key)
131 bssid = formatMACAddress(st['BSSID'])
132 if airPortStatus['BSSID'] != bssid:
133 airPortStatus['BSSID'] = bssid
134 if bssid in ['00:0e:83:05:77:22', '00:0e:83:05:77:20',
135 '00:0e:83:05:75:d2']:
136 location.add('4111 SC')
137 elif bssid in ['00:0e:83:05:76:82', '00:0e:83:05:76:80']:
138 location.add('ACM office')
139 elif bssid == '00:11:24:0f:23:69':
140 location.add('Champaign')
141 elif bssid == '00:13:c4:ce:66:a0':
142 location.add('1320 DCL')
143 elif bssid in ['00:14:1c:ad:5c:80', '00:14:1c:ad:64:50']:
144 location.add('MEB')
145 elif bssid == '00:02:2d:2c:cb:34':
146 location.add('B02 CSL')
147 elif bssid == '44:44:44:44:44:44':
148 location.add('No AirPort network')
149 else:
150 growlNotify(NOTIFICATION_UNKNOWN, 'Unknown BSSID', bssid,
151 sticky=True)
152 NSLog('Unknown BSSID %s' % bssid)
153 ssid = st['SSID']
154 if airPortStatus['SSID'] != ssid:
155 airPortStatus['SSID'] = ssid
156 if ssid == '':
157 pass
158 elif ssid == 'dcs-wpa':
159 location.add('Siebel')
160 elif ssid == 'DCSnet':
161 location.add('Siebel')
162 location.add('UIUCnet')
163 elif ssid == 'UIUCnet':
164 location.add('UIUCnet')
165 elif ssid == 'ACME Acres':
166 location.add('Champaign')
167 elif ssid == 'CSL Wireless':
168 location.add('CSL')
169 else:
170 growlNotify(NOTIFICATION_UNKNOWN, 'Unknown SSID', ssid,
171 sticky=True)
172 locationChanged(location)
173
174class LocationDo(NSApplication):
175
176 hotKeyRef = None
177
178 def displayLocation(self):
179 growlNotify(NOTIFICATION_CURRENT, 'Current location', currentLocation)
180
181 def finishLaunching(self):
182 super(LocationDo, self).finishLaunching()
183 hotKeyRef = RegisterEventHotKey(98, 0, (0, 0),
184 GetApplicationEventTarget(), 0) # F7
185 growlNotify(NOTIFICATION_READY, 'LocationDo ready', '')
186
187 def sendEvent_(self, theEvent):
188 if theEvent.type() == NSSystemDefined and \
189 theEvent.subtype() == kEventHotKeyPressedSubtype:
190 self.displayLocation()
191 super(LocationDo, self).sendEvent_(theEvent)
192
193store = None
194
195if __name__ == "__main__":
196 store = UNSystemConfigurationDynamicStore.alloc().initWithName_('LocationDo')
197 watcher = SCWatcher.alloc().init()
198 store.setDelegate_(watcher)
199 store.notifyValuesForKeys_matchingPatterns_(None, [RE_AIRPORT_STATUS])
200 store.addToCurrentRunLoop()
201 AppHelper.runEventLoop()
Note: See TracBrowser for help on using the repository browser.