source: trunk/LocationDo/LocationDo.py@ 207

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

LocationDo.py: Add a bunch of TODOs, and some more locations and
actions.

action.py: Add a TODO.

SCNetworkReachabilitymodule.c: Add a TODO.

File size: 9.0 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
33# XXX switch to Cocoa interface for Growl
34growl = app('GrowlHelperApp')
35
36growl.register(
37 as_application=GROWL_APP_NAME,
38 all_notifications=NOTIFICATIONS_ALL,
39 default_notifications=NOTIFICATIONS_ALL)
40
41def growlNotify(name, title, description, **kw):
42 params = dict(with_name=name,
43 title=title,
44 description=unicode(description),
45 application_name=GROWL_APP_NAME,
46 image_from_location='/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericNetworkIcon.icns')
47 params.update(kw)
48 if not params.get('sticky', False):
49 params['identifier'] = name
50 if DEBUG:
51 NSLog("%s: %s" % (title, description))
52 growl.notify(**params)
53
54class Location(sets.Set):
55 def __str__(self):
56 if not self: return '(unknown)'
57 return ', '.join(self)
58
59currentLocation = Location()
60
61# XXX attach actions to location tag; something like:
62# locations['Siebel'].onArrive.ensureKerberosPrincipalsValid(...)
63
64def arriveAtLocation(location):
65 growlNotify(NOTIFICATION_ARRIVE, 'Arriving at location', location)
66 if 'Siebel' in location:
67 action.ensureKerberosPrincipalsValid(['njriley@ACM.UIUC.EDU',
68 'njriley@AD.UIUC.EDU'])
69 action.setVolumePercent(0.15)
70 if '1115 SC' in location:
71 action.openInBackground('~/Documents/CS 423/CS 423 to do.oo3')
72 action.setDisplayBrightnessPercent(0.2)
73 action.setAdiumStatus('Working in 1115 SC')
74 if '1404 SC' in location:
75 action.setDisplayBrightnessPercent(0.4)
76 action.setVolumePercent(0)
77 action.setAdiumStatus('In 1404 SC')
78 if '4111 SC' in location:
79 action.openInBackground('~/Documents/Research/Research progress.oo3')
80 # XXX wait for yt to be accessible
81 # XXX start NX
82 # XXX move windows
83 action.terminalDo('kswitch -p njriley@ACM.UIUC.EDU;(sleep 10;kswitch -p njriley@AD.UIUC.EDU)&! ;clear;ssh yt')
84 action.setDisplayBrightnessPercent(0.9)
85 action.setAdiumStatus('Working in 4111 SC')
86 if 'ACM office' in location:
87 action.setDisplayBrightnessPercent(0.2)
88 action.setVolumePercent(0.5)
89 action.setAdiumStatus('At ACM')
90 if 'Champaign' in location:
91 action.openInBackground('~/Documents/To do.oo3')
92 action.setDisplayBrightnessPercent(0.2)
93 action.setVolumePercent(0.5)
94 action.setAdiumStatus('At home')
95 if '13[12]0 DCL' in location:
96 action.setDisplayBrightnessPercent(0.2)
97 action.setVolumePercent(0)
98 action.setAdiumStatus('In 13[12]0 DCL')
99 if 'UIUCnet' in location:
100 action.startVPNC('UIUCnet-oncampus')
101 if 'CSL' in location:
102 action.setDisplayBrightnessPercent(0.1)
103 action.setVolumePercent(0)
104 action.setAdiumStatus('At CSL')
105 action.openURL('http://wireless.csl.uiuc.edu/authenticate.html')
106 growlNotify(NOTIFICATION_ARRIVE, 'Arrived at location',
107 location)
108
109def departLocation(location):
110 growlNotify(NOTIFICATION_DEPART, 'Departing location', location)
111 if 'UIUCnet' in location:
112 # XXX should handle this more symmetrically
113 action.stopVPNC()
114 growlNotify(NOTIFICATION_DEPART, 'Departed location', location)
115
116def locationChanged(location):
117 if not location: return # unknown
118 global currentLocation
119 oldLocation = currentLocation - location
120 newLocation = location - currentLocation
121 if DEBUG:
122 NSLog("new %s | was %s | departing %s | arriving %s" % \
123 (location, currentLocation, oldLocation, newLocation))
124 if oldLocation:
125 departLocation(oldLocation)
126 currentLocation = location
127 if newLocation:
128 currentLocation = location
129 arriveAtLocation(newLocation)
130
131def formatMACAddress(data):
132 return ':'.join(re.findall('..', data.bytes()[:].encode('hex')))
133
134# XXX watch battery status, too, for display brightness
135# XXX look at display configuration to tell difference between 4111 and 4124
136# XXX need concept of ambiguity, ask user which location they're in (ACM/1115)
137
138airPortStatus = {'BSSID': None, 'SSID': None}
139
140class SCWatcher(NSObject):
141 def keysChanged_inDynamicStore_(self, changed, store):
142 location = Location()
143 for key in changed:
144 if re.match(RE_AIRPORT_STATUS, key):
145 st = store.valueForKey_(key)
146 bssid = formatMACAddress(st['BSSID'])
147 if airPortStatus['BSSID'] != bssid:
148 airPortStatus['BSSID'] = bssid
149 if bssid in ['00:0e:83:05:77:22', '00:0e:83:05:77:20',
150 '00:0e:83:05:75:d2']:
151 location.add('4111 SC')
152 elif bssid in ['00:0e:83:05:75:a2', '00:0e:83:05:75:a0']:
153 location.add('1404 SC')
154 elif bssid in ['00:0e:83:05:76:82', '00:0e:83:05:76:80']:
155 location.add('ACM office')
156 elif bssid == '00:11:24:0f:23:69':
157 location.add('Champaign')
158 elif bssid == '00:13:c4:ce:66:a0':
159 location.add('13[12]0 DCL')
160 elif bssid in ['00:14:1c:ad:5c:80', '00:14:1c:ad:64:50']:
161 location.add('MEB')
162 elif bssid == '00:02:2d:2c:cb:34':
163 location.add('B02 CSL')
164 elif bssid == '00:13:c4:78:e1:a0':
165 location.add('Engineering Hall')
166 elif bssid == '00:0d:93:ed:e0:bc':
167 location.add('340 Marlborough St.')
168 elif bssid == '00:40:96:5a:5e:0f':
169 location.add('BMI baggage claim')
170 elif bssid == '44:44:44:44:44:44':
171 location.add('No AirPort network')
172 else:
173 growlNotify(NOTIFICATION_UNKNOWN, 'Unknown BSSID', bssid,
174 sticky=True)
175 NSLog('Unknown BSSID %s' % bssid)
176 ssid = st['SSID']
177 if airPortStatus['SSID'] != ssid:
178 airPortStatus['SSID'] = ssid
179 if ssid == '':
180 pass
181 elif ssid == 'dcs-wpa':
182 location.add('Siebel')
183 elif ssid == 'DCSnet':
184 location.add('Siebel')
185 location.add('UIUCnet')
186 elif ssid == 'UIUCnet':
187 location.add('UIUCnet')
188 elif ssid == 'ACME Acres':
189 location.add('Champaign')
190 elif ssid == 'CSL Wireless':
191 location.add('CSL')
192 elif ssid == 'Wackyland':
193 location.add('340 Marlborough St.')
194 elif ssid == 'CIRA':
195 location.add('BMI')
196 else:
197 growlNotify(NOTIFICATION_UNKNOWN, 'Unknown SSID', ssid,
198 sticky=True)
199 locationChanged(location)
200
201class LocationDo(NSApplication):
202
203 hotKeyRef = None
204
205 def displayLocation(self):
206 growlNotify(NOTIFICATION_CURRENT, 'Current location', currentLocation)
207
208 def finishLaunching(self):
209 super(LocationDo, self).finishLaunching()
210 hotKeyRef = RegisterEventHotKey(98, 0, (0, 0),
211 GetApplicationEventTarget(), 0) # F7
212 growlNotify(NOTIFICATION_READY, 'LocationDo ready', '')
213
214 def sendEvent_(self, theEvent):
215 if theEvent.type() == NSSystemDefined and \
216 theEvent.subtype() == kEventHotKeyPressedSubtype:
217 self.displayLocation()
218 super(LocationDo, self).sendEvent_(theEvent)
219
220store = None
221
222if __name__ == "__main__":
223 store = UNSystemConfigurationDynamicStore.alloc().initWithName_('LocationDo')
224 watcher = SCWatcher.alloc().init()
225 store.setDelegate_(watcher)
226 store.notifyValuesForKeys_matchingPatterns_(None, [RE_AIRPORT_STATUS])
227 store.addToCurrentRunLoop()
228 AppHelper.runEventLoop()
Note: See TracBrowser for help on using the repository browser.