Package Geoclue :: Module Base
[hide private]
[frames] | no frames]

Source Code for Module Geoclue.Base

  1  # -*- coding: utf-8 -*- 
  2  # Copyright (c) 2009 - Paulo Cabido <paulo.cabido@gmail.com> 
  3  # 
  4  # This program is free software: you can redistribute it and/or modify it under 
  5  # the terms of the GNU General Public License as published by the Free Software 
  6  # Foundation, either version 3 of the License, or (at your option) any later 
  7  # version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, but WITHOUT 
 10  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 11  # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 
 12  # details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License along with 
 15  # this program.  If not, see <http://www.gnu.org/licenses/>. 
 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   
30 -class DiscoverLocation:
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 # stores the location info 48 self.location_info = {} 49 50 # Insipered by Pierre-Luc Beaudoin - geoclue_properties.py 51 # TODO: add an exception to this part of the code in case of the wrong 52 # or nonexisting dir 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
73 - def init(self, accuracy=geoclue.ACCURACY_LEVEL_COUNTRY, resource=geoclue.RESOURCE_NETWORK):
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 # connects to detect changes on the address and position providers 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
115 - def provider_status(self, provider):
116 """Checks a provider's status. 117 118 @param provider: A provider instance. 119 @return: The status. 120 """ 121 obj = dbus.Interface(provider.get_proxy(), dbus_interface=geoclue.GEOCLUE_IFACE) 122 status = obj.GetStatus() 123 124 if status == geoclue.STATUS_ERROR: 125 return "error" 126 elif status == geoclue.STATUS_UNAVAILABLE: 127 return "unavailable" 128 elif status == geoclue.STATUS_ACQUIRING: 129 return "acquiring" 130 elif status == geoclue.STATUS_AVAILABLE: 131 return "available" 132 else: 133 return "error"
134
135 - def provider_info(self, provider):
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
147 - def set_requirements(self, accuracy, time, require_updates, resource):
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 # provider changed methods, not really being used but it's useful to have 161 # them here just in case
162 - def on_address_provider_changed(self, name, description, service, path):
163 #print "Address provider changed" 164 pass
165
166 - def on_position_provider_changed(self, name, description, service, path):
167 #print "Position provider changed" 168 pass
169
170 - def update_location_address(self, address):
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 # TODO: postalcode ? 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
195 - def on_address_changed(self, timestamp, address, accuracy):
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
206 - def on_position_changed(self, fields, timestamp, latitude, longitude, altitude, accuracy):
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 #print accuracy # I used this print to check the accuracy format 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 # returns the current values for location and position
224 - def get_location_info(self):
225 """Returns the location info dictionary. 226 227 @return: The location info dictionary. 228 """ 229 return self.location_info
230
231 - def get_available_providers(self):
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
270 - def set_position_provider(self, provider_name):
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
301 - def validate_address(self, address):
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 # TODO: postalcode ? 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 # TODO: add "valid-for" to continue to use the given provider
343 - def set_address_provider(self, provider_name, address=None):
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
381 - def get_position_provider(self):
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
388 - def get_address_provider(self):
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
395 - def compare_position(self, latitude, longitude, proximity_factor=None):
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 # 500 meters 406 dis_max = 0.5 407 else: 408 dis_max = proximity_factor 409 410 # todo_later : (calibration must be done with a well known distance ) 411 #This method assumes a spheroidal model for the earth with 412 #an average radius of 6364.963 km. 413 #The formula is estimated to have an accuracy of about 200 metres 414 #over 50 km, but may deteriorate with longer distances. 415 #source : http://www.ga.gov.au/geodesy/datums/distance.jsp 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
425 - def reverse_position(self, latitude, longitude, accuracy):
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 #add the values to the address of the location variable 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
457 - def connect(self, func):
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
465 - def disconnect(self, func):
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