1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import os
18 import sys
19 import math
20
21 import dbus
22 from dbus.mainloop.glib import DBusGMainLoop
23 import gobject
24
25 import geoclue
26 from Signal import Signal
27
28 DBusGMainLoop(set_as_default=True)
29
31 """ Discovers the location form the best available provider
32
33 L{DiscoverLocation} is a object that provides a nice API interface
34 for Geoclue.
35 """
36
37 - def __init__(self, providers_path="/usr/share/geoclue-providers"):
38 """Construct a L{DiscoverLocation} object.
39
40 @param providers_path: The path to the providers. The default
41 path to the providers is /usr/share/geoclue-providers.
42 """
43 self.bus = dbus.SessionBus()
44
45 self.signal = Signal()
46
47
48 self.location_info = {}
49
50
51
52
53 self.providers = []
54
55 dir = os.listdir(providers_path)
56
57 for filename in dir:
58 (name, ext) = os.path.splitext(filename)
59
60 if ext == ".provider":
61 complete = os.path.join(providers_path, filename)
62 provider = geoclue.GeoclueProvider (complete)
63 self.providers.append([provider,
64 provider.name,
65 provider.interfaces & geoclue.INTERFACE_ADDRESS,
66 provider.interfaces & geoclue.INTERFACE_POSITION,
67 provider.interfaces & geoclue.INTERFACE_GEOCODE,
68 provider.interfaces & geoclue.INTERFACE_REVERSE_GEOCODE,
69 provider.service,
70 provider.path
71 ])
72
74 """Initializes Geoclue.
75
76 @param accuracy: The desired accuracy.
77 @param resource: The resource to be used.
78 """
79 self.accuracy = accuracy
80 self.resource = resource
81
82 try:
83 self.master = self.bus.get_object(geoclue.MASTER_IFACE, geoclue.MASTER_PATH)
84 self.client = self.bus.get_object(geoclue.MASTER_IFACE, self.master.Create())
85
86
87 self.client.connect_to_signal("AddressProviderChanged", self.on_address_provider_changed)
88 self.client.connect_to_signal("PositionProviderChanged", self.on_position_provider_changed)
89
90 self.address = dbus.Interface(self.client, dbus_interface=geoclue.ADDRESS_IFACE)
91 self.address.connect_to_signal("AddressChanged", self.on_address_changed)
92 self.client.AddressStart()
93
94 self.position = dbus.Interface(self.client, dbus_interface=geoclue.POSITION_IFACE)
95 self.position.connect_to_signal("PositionChanged", self.on_position_changed)
96 self.client.PositionStart()
97
98 self.client.SetRequirements(self.accuracy, 0, True, self.resource)
99
100 try:
101 self.on_address_changed(*self.address.GetAddress())
102 except Exception, e:
103 return False
104
105 try:
106 self.on_position_changed(*self.position.GetPosition())
107 except Exception, e:
108 return False
109
110 return True
111 except Exception, e:
112 print "Error: %s" % e
113 return False
114
134
136 """Returns the provider's Info.
137
138 @return: A dictionary with the provider's name and descripiton.
139 """
140 obj = dbus.Interface(provider.get_proxy(), dbus_interface=geoclue.GEOCLUE_IFACE)
141 info = obj.GetProviderInfo()
142 tmp = {}
143 tmp['name'] = str(info[0])
144 tmp['description'] = str(info[1])
145 return tmp
146
148 """Set the client requirements.
149
150 @param accuracy: The required minimum accuracy.
151 @param time: The minimum time between update signals.
152 @param require_updates: C{True} if updates are required or C{False} if updates
153 are not required.
154 @param resource: The resources that are allowed to be used.
155 """
156 self.accuracy = accuracy
157 self.resource = resource
158 self.client.SetRequirements(accuracy, time, require_updates, allowed_resources)
159
160
161
165
169
171 """Updates the the location's address with the given C{address}.
172
173 @address: The new address.
174 """
175 if address.has_key('street'):
176 self.location_info['street'] = address['street']
177
178
179
180 if address.has_key('area'):
181 self.locatio_infon['area'] = address['area']
182
183 if address.has_key('locality'):
184 self.location_info['locality'] = address['locality']
185
186 if address.has_key('country'):
187 self.location_info['country'] = address['country']
188
189 if address.has_key('region'):
190 self.location_info['region'] = address['region']
191
192 if address.has_key('countrycode'):
193 self.location_info['countrycode'] = address['countrycode']
194
196 """When the address changes the location info dictionary is updated.
197
198 @param timestamp: The timestamp.
199 @param address: The new address.
200 @accuracy: The accuracy.
201 """
202 self.location_info['address_timestamp'] = timestamp
203 self.update_location_address(address)
204 self.signal()
205
207 """When the position changes the location info dictionary is updated.
208
209 @param fields: The fields.
210 @param timestamp: The timestamp.
211 @param latitude: The new latitude.
212 @param longitude: The new longitude.
213 @param altitude: The new altitude.
214 @param accuracy: The accuracy.
215 """
216
217 self.location_info['position_timestamp'] = timestamp
218 self.location_info['latitude'] = latitude
219 self.location_info['longitude'] = longitude
220 self.location_info['altitude'] = altitude
221 self.signal()
222
223
225 """Returns the location info dictionary.
226
227 @return: The location info dictionary.
228 """
229 return self.location_info
230
232 """Returns the available providers.
233
234 @return: A list of dictionarys,
235 [PROVIDER, ADDRESS, POSITION, GEOCODING, REVERSE GEOCODING],
236 with the name and True of False for supporting each of them
237 """
238 current_providers = []
239 for provider in self.providers:
240 tmp = {}
241 tmp['name'] = provider[1]
242 if provider[2] != 0:
243 tmp['address'] = True
244 else:
245 tmp['address'] = False
246
247 if provider[3] != 0:
248 tmp['position'] = True
249 else:
250 tmp['position'] = False
251
252 if provider[4] != 0:
253 tmp['geocoding'] = True
254 else:
255 tmp['geocoding'] = False
256
257 if provider[5] != 0:
258 tmp['revgeocoding'] = True
259 else:
260 tmp['revgeocoding'] = False
261
262 tmp['object'] = provider[0]
263 tmp['service'] = provider[6]
264 tmp['path'] = provider[7]
265
266 current_providers.append(tmp)
267
268 return current_providers
269
271 """Set the position provider to a given C{provider_name} (if exists).
272
273 @param provider_name: The provider's name
274 @return: C{True} if the provider exists or C{False} if a provider
275 does not exist.
276 """
277 provider_exists = False
278 for provider in self.providers:
279 if provider[1].lower() == provider_name.lower() and provider[3] != 0:
280 current_provider = provider
281 provider_exists = True
282 break
283
284 if not provider_exists:
285 return False
286
287 try:
288 tmp_provider = current_provider[0].get_proxy()
289 self.position = dbus.Interface(tmp_provider, dbus_interface=geoclue.POSITION_IFACE)
290 except Exception, e:
291 print "D-Bus error: %s" % e
292 return False
293
294 try:
295 self.on_position_changed(*self.position.GetPosition())
296 except Exception, e:
297 print e
298
299 return True
300
302 """Receives the address and validates/corrects it.
303
304 @param address: The address dictionary.
305 @return: The address (with possible corrections).
306 """
307 tmp_address = {}
308 if address.has_key('street'):
309 tmp_address['street'] = address['street']
310 else:
311 tmp_address['street'] = ""
312
313
314
315 if address.has_key('area'):
316 tmp_address['area'] = address['area']
317 else:
318 tmp_address['area'] = ""
319
320 if address.has_key('locality'):
321 tmp_address['locality'] = address['locality']
322 else:
323 tmp_address['locality'] = ""
324
325 if address.has_key('country'):
326 tmp_address['country'] = address['country']
327 else:
328 tmp_address['country'] = ""
329
330 if address.has_key('region'):
331 tmp_address['region'] = address['region']
332 else:
333 tmp_address['region'] = ""
334
335 if address.has_key('countrycode'):
336 tmp_address['countrycode'] = address['countrycode']
337 else:
338 tmp_address['countrycode'] = ""
339
340 return tmp_address
341
342
344 """Set the address provider
345
346 @param provider_name: the provider's name
347 @param address: the new address (for Manual and Localnet providers)
348 @returns: C{True} if the provider exists or C{False} if a provider
349 does not exist.
350 """
351 provider_exists = False
352 for provider in self.providers:
353 if provider[1].lower() == provider_name.lower() and provider[2] != 0:
354 current_provider = provider
355 provider_exists = True
356 break
357
358 if not provider_exists:
359 return False
360
361 try:
362 if (provider_name.lower() == "manual" or provider_name.lower() == "localnet") and address != None:
363 tmp_provider = current_provider[0].get_proxy()
364 tmp_provider.SetAddress(0, self.validate_address(address))
365 self.address = dbus.Interface(tmp_provider, dbus_interface=geoclue.ADDRESS_IFACE)
366 elif (provider_name.lower() == "manual" or provider_name.lower() == "localnet") and address == None:
367 return False
368 else:
369 self.address = dbus.Interface(current_provider[0].get_proxy(), dbus_interface=geoclue.ADDRESS_IFACE)
370 except Exception, e:
371 print "D-Bus error: %s" % e
372 return False
373
374 try:
375 self.on_address_changed(*self.address.GetAddress())
376 except Exception, e:
377 print e
378
379 return True
380
382 """Returns the name of the current position provider.
383
384 @return: The name of the current position provider.
385 """
386 return self.client.GetPositionProvider()[0]
387
389 """Returns the name of the current address provider.
390
391 @return: The name of the current address provider.
392 """
393 return self.client.GetAddressProvider()[0]
394
396 """Compare the current position to a given position.
397
398 Note: ploum's contribution
399
400 @param latitude: latitude of the position
401 @param longitude: longitude of the position
402 @param proximity_factor: the near by proximity factor. ie, 0.5 is 500 meters
403 """
404 if proximity_factor == None:
405
406 dis_max = 0.5
407 else:
408 dis_max = proximity_factor
409
410
411
412
413
414
415
416 dl = self.location_info['latitude'] - latitude
417 dg = self.location_info['longitude'] - longitude
418 term1 = 111.08956 * (dl + 0.000001)
419 term2 = math.cos(self.location_info['latitude'] + (dl/2))
420 term3 = (dg + 0.000001) / (dl + 0.000001)
421 d = term1 / math.cos(math.atan(term2 * term3))
422 result = math.fabs(d) < dis_max
423 return result
424
426 """Returns an address that corresponds to a given position.
427
428 @param latitude: The position's latitude.
429 @param longitude: The position's longitude.
430 @param accuracy: The accuracy.
431 @return: An address.
432 """
433 provider_exists = False
434 for provider in self.providers:
435 if provider[1].lower() == "Geonames Provider".lower():
436 current_provider = provider
437 provider_exists = True
438 break
439
440 if not provider_exists:
441 return None
442
443 try:
444 revgeocoder = dbus.Interface(current_provider[0].get_proxy(), geoclue.REVERSE_IFACE)
445 revaddress = revgeocoder.PositionToAddress(float(latitude), float(longitude), (accuracy, 0, 0))
446
447
448 tmp_address = {}
449 for key, item in revaddress[0].items():
450 tmp_address[unicode(key)] = unicode(item)
451
452 return self.validate_address(tmp_address)
453 except Exception, e:
454 print "D-Bus error: %s" % e
455 return None
456
458 """Connects a given function to the signal.
459 The signal action if any change to the info location dictionary.
460
461 @param func: The function to connect to the signal.
462 """
463 self.signal.connect(func)
464
466 """Disconnects a given function from the signal.
467
468 @param func: The function to disconnect from the signal.
469 """
470 self.signal.disconnect(func)
471