lib_ble_client.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2019 Espressif Systems (Shanghai) PTE LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. # DBus-Bluez BLE library
  18. from __future__ import print_function
  19. import sys
  20. import time
  21. try:
  22. import dbus
  23. import dbus.mainloop.glib
  24. from gi.repository import GLib
  25. except ImportError as e:
  26. if 'linux' not in sys.platform:
  27. raise e
  28. print(e)
  29. print('Install packages `libgirepository1.0-dev gir1.2-gtk-3.0 libcairo2-dev libdbus-1-dev libdbus-glib-1-dev` for resolving the issue')
  30. print('Run `pip install -r $IDF_PATH/tools/ble/requirements.txt` for resolving the issue')
  31. raise
  32. from . import lib_gap, lib_gatt
  33. BLUEZ_SERVICE_NAME = 'org.bluez'
  34. DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
  35. DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
  36. ADAPTER_IFACE = 'org.bluez.Adapter1'
  37. DEVICE_IFACE = 'org.bluez.Device1'
  38. GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
  39. LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
  40. GATT_SERVICE_IFACE = 'org.bluez.GattService1'
  41. GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
  42. class DBusException(dbus.exceptions.DBusException):
  43. pass
  44. class Characteristic:
  45. def __init__(self):
  46. self.iface = None
  47. self.path = None
  48. self.props = None
  49. class Service:
  50. def __init__(self):
  51. self.iface = None
  52. self.path = None
  53. self.props = None
  54. self.chars = []
  55. class Device:
  56. def __init__(self):
  57. self.iface = None
  58. self.path = None
  59. self.props = None
  60. self.name = None
  61. self.addr = None
  62. self.services = []
  63. class Adapter:
  64. def __init__(self):
  65. self.iface = None
  66. self.path = None
  67. self.props = None
  68. class BLE_Bluez_Client:
  69. def __init__(self, iface=None):
  70. self.bus = None
  71. self.hci_iface = iface
  72. self.adapter = Adapter()
  73. self.device = None
  74. self.gatt_app = None
  75. self.gatt_mgr = None
  76. self.mainloop = None
  77. self.loop_cnt = 0
  78. try:
  79. dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  80. self.bus = dbus.SystemBus()
  81. except dbus.exceptions.DBusException as dbus_err:
  82. raise DBusException('Failed to initialise client: {}'.format(dbus_err))
  83. except Exception as err:
  84. raise Exception('Failed to initialise client: {}'.format(err))
  85. def __del__(self):
  86. try:
  87. # Cleanup
  88. self.disconnect()
  89. print('Test Exit')
  90. except Exception as e:
  91. print(e)
  92. def set_adapter(self):
  93. '''
  94. Discover Bluetooth Adapter
  95. Power On Bluetooth Adapter
  96. '''
  97. try:
  98. print('discovering adapter')
  99. dbus_obj_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
  100. dbus_objs = dbus_obj_mgr.GetManagedObjects()
  101. for path, interfaces in dbus_objs.items():
  102. adapter = interfaces.get(ADAPTER_IFACE)
  103. if adapter is not None and path.endswith(self.hci_iface):
  104. self.adapter.iface = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), ADAPTER_IFACE)
  105. self.adapter.props = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE)
  106. self.adapter.path = path
  107. break
  108. if self.adapter.iface is None:
  109. print('bluetooth adapter not found')
  110. return False
  111. print('bluetooth adapter discovered')
  112. print('checking if bluetooth adapter is already powered on')
  113. # Check if adapter is already powered on
  114. powered = self.adapter.props.Get(ADAPTER_IFACE, 'Powered')
  115. if powered == 1:
  116. print('adapter already powered on')
  117. return True
  118. # Power On Adapter
  119. print('powering on adapter')
  120. self.adapter.props.Set(ADAPTER_IFACE, 'Powered', dbus.Boolean(1))
  121. # Check if adapter is powered on
  122. print('checking if adapter is powered on')
  123. for cnt in range(10, 0, -1):
  124. time.sleep(5)
  125. powered_on = self.adapter.props.Get(ADAPTER_IFACE, 'Powered')
  126. if powered_on == 1:
  127. # Set adapter props again with powered on value
  128. self.adapter.props = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, self.adapter.path), DBUS_PROP_IFACE)
  129. print('bluetooth adapter powered on')
  130. return True
  131. print('number of retries left({})'.format(cnt - 1))
  132. # Adapter not powered on
  133. print('bluetooth adapter not powered on')
  134. return False
  135. except Exception as err:
  136. raise Exception('Failed to set adapter: {}'.format(err))
  137. def connect(self, devname=None, devaddr=None):
  138. '''
  139. Start Discovery and Connect to the device
  140. '''
  141. try:
  142. device_found = None
  143. start_discovery = False
  144. self.device = Device()
  145. discovery_val = self.adapter.props.Get(ADAPTER_IFACE, 'Discovering')
  146. # Start Discovery
  147. if discovery_val == 0:
  148. print('starting discovery')
  149. self.adapter.iface.StartDiscovery()
  150. start_discovery = True
  151. for cnt in range(10, 0, -1):
  152. time.sleep(5)
  153. discovery_val = self.adapter.props.Get(ADAPTER_IFACE, 'Discovering')
  154. if discovery_val == 1:
  155. print('start discovery successful')
  156. break
  157. print('number of retries left ({})'.format(cnt - 1))
  158. if discovery_val == 0:
  159. print('start discovery failed')
  160. return False
  161. # Get device
  162. for cnt in range(10, 0, -1):
  163. # Wait for device to be discovered
  164. time.sleep(5)
  165. device_found = self.get_device(
  166. devname=devname,
  167. devaddr=devaddr)
  168. if device_found:
  169. break
  170. # Retry
  171. print('number of retries left ({})'.format(cnt - 1))
  172. if not device_found:
  173. print('expected device {} [ {} ] not found'.format(devname, devaddr))
  174. return False
  175. # Connect to expected device found
  176. print('connecting to device {} [ {} ] '.format(self.device.name, self.device.addr))
  177. self.device.iface.Connect(dbus_interface=DEVICE_IFACE)
  178. for cnt in range(10, 0, -1):
  179. time.sleep(5)
  180. connected = self.device.props.Get(DEVICE_IFACE, 'Connected')
  181. if connected == 1:
  182. # Set device props again with connected on value
  183. self.device.props = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, self.device.path), DBUS_PROP_IFACE)
  184. print('connected to device with iface {}'.format(self.device.path))
  185. return True
  186. print('number of retries left({})'.format(cnt - 1))
  187. # Device not connected
  188. print('connection to device failed')
  189. return False
  190. except Exception as err:
  191. raise Exception('Connect to device failed : {}'.format(err))
  192. finally:
  193. try:
  194. if start_discovery:
  195. print('stopping discovery')
  196. self.adapter.iface.StopDiscovery()
  197. for cnt in range(10, 0, -1):
  198. time.sleep(5)
  199. discovery_val = self.adapter.props.Get(ADAPTER_IFACE, 'Discovering')
  200. if discovery_val == 0:
  201. print('stop discovery successful')
  202. break
  203. print('number of retries left ({})'.format(cnt - 1))
  204. if discovery_val == 1:
  205. print('stop discovery failed')
  206. except dbus.exceptions.DBusException as dbus_err:
  207. print('Warning: Failure during cleanup for device connection : {}'.format(dbus_err))
  208. def get_device(self, devname=None, devaddr=None):
  209. '''
  210. Get device based on device name
  211. and device address and connect to device
  212. '''
  213. dev_path = None
  214. expected_device_addr = devaddr.lower()
  215. expected_device_name = devname.lower()
  216. print('checking if expected device {} [ {} ] is present'.format(devname, devaddr))
  217. dbus_obj_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
  218. dbus_objs = dbus_obj_mgr.GetManagedObjects()
  219. # Check if expected device is present
  220. for path, interfaces in dbus_objs.items():
  221. if DEVICE_IFACE not in interfaces.keys():
  222. continue
  223. # Check expected device address is received device address
  224. received_device_addr_path = (path.replace('_', ':')).lower()
  225. if expected_device_addr not in received_device_addr_path:
  226. continue
  227. device_props = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, path), DBUS_PROP_IFACE)
  228. received_device_name = device_props.Get(DEVICE_IFACE, 'Name').lower()
  229. # Check expected device name is received device name
  230. if expected_device_name == received_device_name:
  231. # Set device iface path
  232. dev_path = path
  233. break
  234. if not dev_path:
  235. print('\nBLE device not found')
  236. return False
  237. print('device {} [ {} ] found'.format(devname, devaddr))
  238. # Set device details
  239. self.device.iface = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path), DEVICE_IFACE)
  240. self.device.props = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, dev_path), DBUS_PROP_IFACE)
  241. self.device.path = dev_path
  242. self.device.name = devname
  243. self.device.addr = devaddr
  244. return True
  245. def get_services(self):
  246. '''
  247. Retrieve Services found in the device connected
  248. '''
  249. try:
  250. # Get current dbus objects
  251. dbus_obj_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
  252. dbus_objs = dbus_obj_mgr.GetManagedObjects()
  253. # Get services
  254. for path, interfaces in dbus_objs.items():
  255. if GATT_SERVICE_IFACE in interfaces.keys():
  256. if not path.startswith(self.device.path):
  257. continue
  258. received_service = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  259. # Retrieve all services on device iface path
  260. # and set each service received
  261. service = Service()
  262. service.path = path
  263. service.iface = dbus.Interface(received_service, GATT_SERVICE_IFACE)
  264. service.props = dbus.Interface(received_service, DBUS_PROP_IFACE)
  265. self.device.services.append(service)
  266. if not self.device.services:
  267. print('no services found for device: {}'.format(self.device.path))
  268. return False
  269. return True
  270. except Exception as err:
  271. raise Exception('Failed to get services: {}'.format(err))
  272. def get_chars(self):
  273. '''
  274. Get characteristics of the services set for the device connected
  275. '''
  276. try:
  277. if not self.device.services:
  278. print('No services set for device: {}'.format(self.device.path))
  279. return
  280. # Read chars for all the services received for device
  281. for service in self.device.services:
  282. char_found = False
  283. dbus_obj_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
  284. dbus_objs = dbus_obj_mgr.GetManagedObjects()
  285. for path, interfaces in dbus_objs.items():
  286. if GATT_CHRC_IFACE in interfaces.keys():
  287. if not path.startswith(self.device.path):
  288. continue
  289. if not path.startswith(service.path):
  290. continue
  291. # Set characteristics
  292. received_char = self.bus.get_object(BLUEZ_SERVICE_NAME, path)
  293. char = Characteristic()
  294. char.path = path
  295. char.iface = dbus.Interface(received_char, GATT_CHRC_IFACE)
  296. char.props = dbus.Interface(received_char, DBUS_PROP_IFACE)
  297. service.chars.append(char)
  298. char_found = True
  299. if not char_found:
  300. print('Characteristic not found for service: {}'.format(service.iface))
  301. except Exception as err:
  302. raise Exception('Failed to get characteristics : {}'.format(err))
  303. def read_chars(self):
  304. '''
  305. Read value of characteristics
  306. '''
  307. try:
  308. if not self.device.services:
  309. print('No services set for device: {}'.format(self.device.path))
  310. return
  311. # Read chars for all services of device
  312. for service in self.device.services:
  313. # Read properties of characteristic
  314. for char in service.chars:
  315. # Print path
  316. print('Characteristic: {}'.format(char.path))
  317. # Print uuid
  318. uuid = char.props.Get(GATT_CHRC_IFACE, 'UUID')
  319. print('UUID: {}'.format(uuid))
  320. # Print flags
  321. flags = [flag for flag in char.props.Get(GATT_CHRC_IFACE, 'Flags')]
  322. print('Flags: {}'.format(flags))
  323. # Read value if `read` flag is present
  324. if 'read' in flags:
  325. value = char.iface.ReadValue({}, dbus_interface=GATT_CHRC_IFACE)
  326. print('Value: {}'.format(value))
  327. except Exception as err:
  328. raise Exception('Failed to read characteristics : {}'.format(err))
  329. def write_chars(self, new_value):
  330. '''
  331. Write to characteristics
  332. '''
  333. try:
  334. if not self.device.services:
  335. print('No services set for device: {}'.format(self.device.path))
  336. return False
  337. print('writing data to characteristics with read and write permission')
  338. # Read chars of all services of device
  339. for service in self.device.services:
  340. if not service.chars:
  341. print('No chars found for service: {}'.format(service.path))
  342. continue
  343. for char in service.chars:
  344. flags = [flag.lower() for flag in char.props.Get(GATT_CHRC_IFACE, 'Flags')]
  345. if not ('read' in flags and 'write' in flags):
  346. continue
  347. # Write new value to characteristic
  348. curr_value = char.iface.ReadValue({}, dbus_interface=GATT_CHRC_IFACE)
  349. print('current value: {}'.format(curr_value))
  350. print('writing {} to characteristic {}'.format(new_value, char.path))
  351. char.iface.WriteValue(new_value, {}, dbus_interface=GATT_CHRC_IFACE)
  352. time.sleep(5)
  353. updated_value = char.iface.ReadValue({}, dbus_interface=GATT_CHRC_IFACE)
  354. print('updated value: {}'.format(updated_value))
  355. if not (ord(new_value) == int(updated_value[0])):
  356. print('write operation to {} failed'.format(char.path))
  357. return False
  358. print('write operation to {} successful'.format(char.path))
  359. return True
  360. except Exception as err:
  361. raise Exception('Failed to write to characteristics: {}'.format(err))
  362. def get_char_if_exists(self, char_uuid):
  363. '''
  364. Get char if exists for given uuid
  365. '''
  366. try:
  367. for service in self.device.services:
  368. for char in service.chars:
  369. curr_uuid = char.props.Get(GATT_CHRC_IFACE, 'UUID')
  370. if char_uuid.lower() in curr_uuid.lower():
  371. return char
  372. print('char {} not found'.format(char_uuid))
  373. return False
  374. except Exception as err:
  375. raise Exception('Failed to get char based on uuid {} - {}'.format(char_uuid, err))
  376. def get_service_if_exists(self, service_uuid):
  377. try:
  378. for service in self.device.services:
  379. uuid = service.props.Get(GATT_SERVICE_IFACE, 'UUID')
  380. if service_uuid.lower() in uuid.lower():
  381. return service
  382. print('service {} not found'.format(service_uuid))
  383. return False
  384. except Exception as err:
  385. raise Exception('Failed to get service based on uuid {} - {}'.format(service_uuid, err))
  386. def start_notify(self, char):
  387. try:
  388. notify_started = 0
  389. notifying = char.props.Get(GATT_CHRC_IFACE, 'Notifying')
  390. if notifying == 0:
  391. # Start Notify
  392. char.iface.StartNotify()
  393. notify_started = 1
  394. # Check notify started
  395. for _ in range(10, 0, -1):
  396. notifying = char.props.Get(GATT_CHRC_IFACE, 'Notifying')
  397. if notifying == 1:
  398. print('subscribe to notifications: on')
  399. break
  400. if notifying == 0:
  401. print('Failed to start notifications')
  402. return False
  403. # Get updated value
  404. for _ in range(10, 0, -1):
  405. time.sleep(1)
  406. char_value = char.props.Get(GATT_CHRC_IFACE, 'Value')
  407. print(char_value)
  408. return None
  409. except Exception as err:
  410. raise Exception('Failed to perform notification operation: {}'.format(err))
  411. finally:
  412. try:
  413. if notify_started == 1:
  414. # Stop notify
  415. char.iface.StopNotify()
  416. for _ in range(10, 0, -1):
  417. notifying = char.props.Get(GATT_CHRC_IFACE, 'Notifying')
  418. if notifying == 0:
  419. print('subscribe to notifications: off')
  420. break
  421. if notifying == 1:
  422. print('Failed to stop notifications')
  423. except dbus.exceptions.DBusException as dbus_err:
  424. print('Warning: Failure during cleanup for start notify : {}'.format(dbus_err))
  425. def _create_mainloop(self):
  426. '''
  427. Create GLibMainLoop
  428. '''
  429. if not self.mainloop:
  430. self.mainloop = GLib.MainLoop()
  431. def register_gatt_app(self):
  432. '''
  433. Create Gatt Application
  434. Register Gatt Application
  435. '''
  436. try:
  437. # Create mainloop, if does not exist
  438. self._create_mainloop()
  439. # Create Gatt Application
  440. self.gatt_app = lib_gatt.AlertNotificationApp(self.bus, self.adapter.path)
  441. print('GATT Application created')
  442. self.gatt_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, self.adapter.path), GATT_MANAGER_IFACE)
  443. # Register Gatt Application
  444. self.gatt_mgr.RegisterApplication(
  445. self.gatt_app, {},
  446. reply_handler=self.gatt_app_success_handler,
  447. error_handler=self.gatt_app_error_handler)
  448. self.mainloop.run()
  449. except dbus.exceptions.DBusException as dbus_err:
  450. raise DBusException('Failed to create GATT Application : {}'.format(dbus_err))
  451. except Exception as err:
  452. raise Exception('Failed to register Gatt Application: {}'.format(err))
  453. def gatt_app_success_handler(self):
  454. print('GATT Application successfully registered')
  455. self.mainloop.quit()
  456. def gatt_app_error_handler(self):
  457. raise DBusException('Failed to register GATT Application')
  458. def check_le_iface(self):
  459. '''
  460. Check if LEAdvertisingManager1 interface exists
  461. '''
  462. try:
  463. dbus_obj_mgr = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
  464. dbus_objs = dbus_obj_mgr.GetManagedObjects()
  465. for path, iface in dbus_objs.items():
  466. if LE_ADVERTISING_MANAGER_IFACE in iface:
  467. le_adv_iface_path = path
  468. break
  469. # Check LEAdvertisingManager1 interface is found
  470. assert le_adv_iface_path, '\n Cannot start advertising. LEAdvertisingManager1 Interface not found'
  471. return le_adv_iface_path
  472. except AssertionError:
  473. raise
  474. except Exception as err:
  475. raise Exception('Failed to find LEAdvertisingManager1 interface: {}'.format(err))
  476. def register_adv(self, adv_host_name, adv_type, adv_uuid):
  477. try:
  478. # Gatt Application is expected to be registered
  479. if not self.gatt_app:
  480. print('No Gatt Application is registered')
  481. return
  482. adv_iface_index = 0
  483. # Create mainloop, if does not exist
  484. self._create_mainloop()
  485. # Check LEAdvertisingManager1 interface exists
  486. le_iface_path = self.check_le_iface()
  487. # Create Advertisement data
  488. leadv_obj = lib_gap.Advertisement(
  489. self.bus,
  490. adv_iface_index,
  491. adv_type,
  492. adv_uuid,
  493. adv_host_name)
  494. print('Advertisement registered')
  495. # Register Advertisement
  496. leadv_mgr_iface_obj = dbus.Interface(self.bus.get_object(BLUEZ_SERVICE_NAME, le_iface_path), LE_ADVERTISING_MANAGER_IFACE)
  497. leadv_mgr_iface_obj.RegisterAdvertisement(
  498. leadv_obj.get_path(), {},
  499. reply_handler=self.adv_success_handler,
  500. error_handler=self.adv_error_handler)
  501. # Handler to read events received and exit from mainloop
  502. GLib.timeout_add_seconds(3, self.check_adv)
  503. self.mainloop.run()
  504. except AssertionError:
  505. raise
  506. except dbus.exceptions.DBusException as dbus_err:
  507. raise DBusException('Failure during registering advertisement : {}'.format(dbus_err))
  508. except Exception as err:
  509. raise Exception('Failure during registering advertisement : {}'.format(err))
  510. else:
  511. try:
  512. try:
  513. # Stop Notify if not already stopped
  514. chars = self.gatt_app.service.get_characteristics()
  515. for char in chars:
  516. if char.uuid == lib_gatt.CHAR_UUIDS['UNREAD_ALERT_STATUS_UUID']:
  517. if char.notifying:
  518. char.StopNotify()
  519. except dbus.exceptions.DBusException as dbus_err:
  520. print('Warning: {}'.format(dbus_err))
  521. try:
  522. # Unregister Advertisement
  523. leadv_mgr_iface_obj.UnregisterAdvertisement(leadv_obj.get_path())
  524. except dbus.exceptions.DBusException as dbus_err:
  525. print('Warning: {}'.format(dbus_err))
  526. try:
  527. # Remove advertising data
  528. dbus.service.Object.remove_from_connection(leadv_obj)
  529. except LookupError as err:
  530. print('Warning: Failed to remove connection from dbus for advertisement object: {} - {}'.format(leadv_obj, err))
  531. try:
  532. # Unregister Gatt Application
  533. self.gatt_mgr.UnregisterApplication(self.gatt_app.get_path())
  534. except dbus.exceptions.DBusException as dbus_err:
  535. print('Warning: {}'.format(dbus_err))
  536. try:
  537. # Remove Gatt Application
  538. dbus.service.Object.remove_from_connection(self.gatt_app)
  539. except LookupError as err:
  540. print('Warning: Failed to remove connection from dbus for Gatt application object: {} - {}'.format(self.gatt_app, err))
  541. except RuntimeError as err:
  542. print('Warning: Failure during cleanup of Advertisement: {}'.format(err))
  543. def adv_success_handler(self):
  544. print('Registered Advertisement successfully')
  545. def adv_error_handler(self, err):
  546. raise DBusException('{}'.format(err))
  547. def check_adv(self):
  548. '''
  549. Handler to check for events triggered (read/write/subscribe)
  550. for advertisement registered for AlertNotificationApp
  551. '''
  552. try:
  553. retry = 10
  554. # Exit loop if read and write and subscribe is successful
  555. if self.gatt_app.service.get_char_status(lib_gatt.CHAR_UUIDS['SUPPORT_NEW_ALERT_UUID'], 'read') and \
  556. self.gatt_app.service.get_char_status(lib_gatt.CHAR_UUIDS['ALERT_NOTIF_UUID'], 'write') and \
  557. self.gatt_app.service.get_char_status(lib_gatt.CHAR_UUIDS['UNREAD_ALERT_STATUS_UUID'], 'notify'):
  558. if self.mainloop.is_running():
  559. self.mainloop.quit()
  560. # return False to stop polling
  561. return False
  562. self.loop_cnt += 1
  563. print('Check read/write/subscribe events are received...Retry {}'.format(self.loop_cnt))
  564. # Exit loop if max retry value is reached and
  565. # all three events (read and write and subscribe) have not yet passed
  566. # Retry total 10 times
  567. if self.loop_cnt == (retry - 1):
  568. if self.mainloop.is_running():
  569. self.mainloop.quit()
  570. # return False to stop polling
  571. return False
  572. # return True to continue polling
  573. return True
  574. except RuntimeError as err:
  575. print('Failure in advertisment handler: {}'.format(err))
  576. if self.mainloop.is_running():
  577. self.mainloop.quit()
  578. # return False to stop polling
  579. return False
  580. def disconnect(self):
  581. '''
  582. Disconnect device
  583. '''
  584. try:
  585. if not self.device or not self.device.iface:
  586. return
  587. print('disconnecting device')
  588. # Disconnect device
  589. device_conn = self.device.props.Get(DEVICE_IFACE, 'Connected')
  590. if device_conn == 1:
  591. self.device.iface.Disconnect(dbus_interface=DEVICE_IFACE)
  592. for cnt in range(10, 0, -1):
  593. time.sleep(5)
  594. device_conn = self.device.props.Get(DEVICE_IFACE, 'Connected')
  595. if device_conn == 0:
  596. print('device disconnected')
  597. break
  598. print('number of retries left ({})'.format(cnt - 1))
  599. if device_conn == 1:
  600. print('failed to disconnect device')
  601. self.adapter.iface.RemoveDevice(self.device.iface)
  602. self.device = None
  603. except dbus.exceptions.DBusException as dbus_err:
  604. print('Warning: {}'.format(dbus_err))
  605. except Exception as err:
  606. raise Exception('Failed to disconnect device: {}'.format(err))