Advertisement
Guest User

Untitled

a guest
Sep 4th, 2015
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.67 KB | None | 0 0
  1. # coding=utf-8
  2. """
  3. iBeacon Scanner
  4. ===============
  5. This scanner works exclusively on iOS real devices, simulator don't support
  6. iBeacon ranging API at all.
  7. The usage is quite simple:
  8. 1. Create a scanner with `scanner = IBeaconScanner()`
  9. 2. Register your iBeacon using the ibeacon uuid like:
  10. scanner.register_beacon("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0")
  11. 3. Monitor the event you want
  12. scanner.bind(on_beacon_update=do_something)
  13. 4. Start the scanner
  14. scanner.start_monitoring()
  15. Output example captured from a test run:
  16. (('on_beacon_entered', <__main__.IBeaconScanner object at 0x1704bd238>), {'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  17. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -57, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  18. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -54, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  19. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -52, 'proximity': 'immediate', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  20. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -52, 'proximity': 'immediate', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  21. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -53, 'proximity': 'immediate', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  22. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -65, 'proximity': 'immediate', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  23. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -74, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  24. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -76, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  25. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -77, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  26. (('on_beacon_update', <__main__.IBeaconScanner object at 0x1704bd238>), {'rssi': -77, 'proximity': 'near', 'major': 4250, 'minor': 9865, 'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  27. (('on_beacon_leaved', <__main__.IBeaconScanner object at 0x1704bd238>), {'uuid': 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0'})
  28. """
  29. from kivy.event import EventDispatcher
  30. from pyobjus import autoclass, protocol
  31.  
  32. CLLocationManager = autoclass("CLLocationManager")
  33. CLBeaconRegion = autoclass("CLBeaconRegion")
  34. NSUUID = autoclass("NSUUID")
  35.  
  36.  
  37. class IBeaconScanner(EventDispatcher):
  38. """
  39. iBeacon Scanner class that works exclusively on iOS real device.
  40. """
  41.  
  42. PROXIMITY = ["unknown", "immediate", "near", "far"]
  43. __events__ = ("on_beacon_entered", "on_beacon_update", "on_beacon_leaved",
  44. "on_error")
  45.  
  46. def __init__(self):
  47. super(IBeaconScanner, self).__init__()
  48. self._regions = {}
  49. self._regions_nsuuid = {}
  50. self._regions_seen = []
  51. self._region_activated = False
  52.  
  53. def start_monitoring(self):
  54. """Start the scanner monitoring"""
  55. print "start monitoring"
  56. self._clm = CLLocationManager.alloc().init()
  57. self._clm.delegate = self
  58. self._clm.requestAlwaysAuthorization()
  59.  
  60. def stop_monitoring(self):
  61. """Stop the scanner monitoring"""
  62. self._deactivate_ibeacons()
  63. self._regions_seen = []
  64. self._clm.delegate = None
  65. del self._clm
  66.  
  67. def register_beacon(self, uuid, name=None):
  68. """Register a beacon to be tracked, using the ibeacon `uuid`"""
  69. assert(len(uuid) == 36)
  70. uuid = uuid.upper()
  71. nsuuid = NSUUID.alloc().initWithUUIDString_(uuid)
  72. self._regions[uuid] = CLBeaconRegion.alloc(
  73. ).initWithProximityUUID_identifier_(nsuuid, name or uuid)
  74. self._regions_nsuuid[uuid] = nsuuid
  75.  
  76. def unregister_beacon(self, uuid):
  77. """Unregister a beacon to be tracked."""
  78. if uuid not in self._regions:
  79. return
  80. self._regions_nsuuid.pop(uuid)
  81. region = self._regions.pop(uuid)
  82. if self._region_activated:
  83. self._clm.stopRangingBeaconsInRegion_(region)
  84. if uuid in self._regions_seen:
  85. self._regions_seen.remove(uuid)
  86. self.dispatch("on_beacon_leaved", uuid=uuid)
  87.  
  88. def on_beacon_entered(self, uuid):
  89. """Event fired when a beacon just entered in the sight of the device"""
  90. print 'entered:', uuid
  91. pass
  92.  
  93. def on_beacon_leaved(self, uuid):
  94. """Event fired when a beacon is not in the sight of the device"""
  95. pass
  96.  
  97. def on_beacon_update(self, uuid, major, minor, proximity, rssi):
  98. """Event fired when we got information about a beacon"""
  99. print uuid, major, minor, proximity, rssi
  100. pass
  101.  
  102. def on_error(self, uuid, msg):
  103. """Event fired when a beacon have an issue / monitoring issues"""
  104. pass
  105.  
  106. # (implementation internal)
  107.  
  108. @protocol("CLLocationManagerDelegate")
  109. def locationManager_didChangeAuthorizationStatus_(self, manager, status):
  110. if status == 3: # kCLAuthorizationStatusAuthorized
  111. self._activate_ibeacons()
  112. elif status == 2: # kCLAuthorizationStatusDenied
  113. pass
  114. elif status == 1: # kCLAuthorizationStatusRestricted
  115. pass
  116. else: # kCLAuthorizationStatusNotDetermined
  117. pass
  118.  
  119. @protocol("CLLocationManagerDelegate")
  120. def locationManager_didRangeBeacons_inRegion_(self, manager, beacons,
  121. region):
  122. uuid = region.proximityUUID.UUIDString().UTF8String()
  123. if uuid not in self._regions:
  124. return
  125.  
  126. beacon = None
  127. count = beacons.count()
  128. if count:
  129. beacon = beacons.objectAtIndex_(0)
  130. if beacon.rssi == 0:
  131. beacon = None
  132.  
  133. if beacon:
  134. if uuid not in self._regions_seen:
  135. self._regions_seen.append(uuid)
  136. self.dispatch("on_beacon_entered", uuid=uuid)
  137. self.dispatch("on_beacon_update",
  138. uuid=uuid,
  139. major=beacon.major.integerValue(),
  140. minor=beacon.minor.integerValue(),
  141. proximity=self.PROXIMITY[beacon.proximity],
  142. rssi=beacon.rssi)
  143. else:
  144. if uuid in self._regions_seen:
  145. self._regions_seen.remove(uuid)
  146. self.dispatch("on_beacon_leaved", uuid=uuid)
  147.  
  148. @protocol("CLLocationManagerDelegate")
  149. def locationManager_rangingBeaconsDidFailForRegion_withError_(
  150. self, manager, region, error
  151. ):
  152. uuid = region.proximityUUID.UUIDString().UTF8String()
  153. msg = error.localizedDescription.UTF8String()
  154. self.dispatch("on_error", uuid=uuid, msg=msg)
  155.  
  156. def _activate_ibeacons(self):
  157. for region in self._regions.values():
  158. self._clm.startRangingBeaconsInRegion_(region)
  159. self._region_activated = True
  160.  
  161. def _deactivate_ibeacons(self):
  162. for region in self._regions.values():
  163. self._clm.stopRangingBeaconsInRegion_(region)
  164. self._region_activated = False
  165.  
  166.  
  167. if __name__ == "__main__":
  168. from kivy.app import App
  169. from kivy.uix.button import Button
  170.  
  171. def dprint(*args, **kwargs):
  172. print(args, kwargs)
  173.  
  174. class IbeaconScanner(App):
  175. def build(self):
  176. print 'here'
  177. self._scanner = IBeaconScanner()
  178. # self._scanner.register_beacon(
  179. # "E2C56DB5-DFFB-48D2-B060-D0F5A71096E0")
  180. self._scanner.register_beacon(
  181. "C4C8A2C0-E38B-11E4-B571-0025BFBA50C3")
  182. from functools import partial
  183. self._scanner.bind(
  184. on_beacon_entered=partial(dprint, "on_beacon_entered"),
  185. on_beacon_update=partial(dprint, "on_beacon_update"),
  186. on_beacon_leaved=partial(dprint, "on_beacon_leaved"),
  187. on_error=partial(dprint, "on_error"))
  188. return Button(text="Start Scanner", on_release=self.start_scanner)
  189.  
  190. def start_scanner(self, *args):
  191. print 'start scanner'
  192. self._scanner.start_monitoring()
  193.  
  194. def on_pause(self):
  195. return True
  196.  
  197. IbeaconScanner().run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement