Python Library Bluetooth Socket
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

__init__.py 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. """
  5. bluetooth_socket (Bluetooth Socket)
  6. ===================================
  7. **Author:**
  8. * Dirk Alders <sudo-dirk@mount-mockery.de>
  9. **Description:**
  10. This Module support bluetooth communication
  11. **Submodules:**
  12. * :mod:`mmod.module.sub1`
  13. * :class:`mmod.module.sub2`
  14. * :func:`mmod.module.sub2`
  15. **Unittest:**
  16. See also the :download:`unittest <../../bluetooth_socket/_testresults_/unittest.pdf>` documentation.
  17. """
  18. import stringtools
  19. import bluetooth
  20. import logging
  21. import time
  22. BT_TIMEOUT = 0.1
  23. def nearby_devices():
  24. return bluetooth.discover_devices()
  25. def services(bt_id):
  26. return bluetooth.find_service(address=bt_id)
  27. class bt_base(object):
  28. def send(self, data, logger=None, log=True):
  29. logit = logger or self.logger
  30. if self.connected():
  31. if log:
  32. logit.debug('BT: TX -> %s', ' '.join(['%02x' % ord(byte) for byte in data]))
  33. try:
  34. self._client_sock.send(data)
  35. except bluetooth.btcommon.BluetoothError, e:
  36. if e.message == 'timed out':
  37. logit.debug('BT: On send - timeout')
  38. return False
  39. else:
  40. logit.warning('BT: On send - %s', str(e))
  41. self._connection_established = False
  42. return False
  43. else:
  44. return False
  45. return True
  46. def receive(self, length=4096, logger=None, log=True):
  47. logit = logger or self.logger
  48. if self.connected():
  49. try:
  50. data = self._client_sock.recv(length)
  51. except bluetooth.btcommon.BluetoothError, e:
  52. if e.message == 'timed out':
  53. # logit.debug('BT: On receive - timeout')
  54. return None
  55. else:
  56. logit.warning('BT: On receive - %s', str(e))
  57. self._connection_established = False
  58. return None
  59. else:
  60. if log:
  61. logit.debug('BT: RX <- %s', ' '.join(['%02x' % ord(byte) for byte in data]))
  62. return data
  63. def connected(self):
  64. return self._connection_established
  65. class stp_bt_base(object):
  66. def send(self, data, logger=None):
  67. logit = logger or self.logger
  68. logit.debug('BT: TX(ETP) -> %s', ' '.join(['%02x' % ord(byte) for byte in data]))
  69. self._bt.send(self, stringtools.stp.build_frame(data), log=False)
  70. def receive(self, timeout=5, logger=None):
  71. logit = logger or self.logger
  72. max_time = time.time() + timeout
  73. while self.connected() and (timeout is None or time.time() < max_time):
  74. data = self._bt.receive(self, 1, log=False)
  75. if data is not None:
  76. max_time += BT_TIMEOUT
  77. msg = self._stp.process(data)
  78. if msg is not None:
  79. logit.debug('BT: RX(ETP) <- %s', ' '.join(['%02x' % ord(byte) for byte in msg]))
  80. return msg
  81. class bt_server(bt_base):
  82. def __init__(self, uuid, port=2, name='BT-RFCOM-Server', logger=None):
  83. self._connection_established = False
  84. self._uuid = uuid
  85. self._name = name
  86. self._server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
  87. self._server_sock.bind(("Python", port))
  88. self._server_sock.listen(1)
  89. bluetooth.advertise_service(self._server_sock,
  90. name,
  91. service_classes=[self._uuid, bluetooth.SERIAL_PORT_CLASS],
  92. profiles=[bluetooth.SERIAL_PORT_PROFILE]
  93. )
  94. def listen(self, logger=None):
  95. logit = logger or self.logger
  96. logit.info('BT: %s waiting for a connection on RFCOMM "%s", port=%d, uuid=%s', '??:??:??:??:??', self._name, self._server_sock.getsockname()[1], self._uuid)
  97. # TODO: find method to get my bt_id and use it instead of '??:??:??:??:??'
  98. self._client_sock, client_info = self._server_sock.accept()
  99. self._client_sock.settimeout(BT_TIMEOUT)
  100. logit.info("BT: Accepted connection from %s, port=%d", client_info[0], client_info[1])
  101. self._connection_established = True
  102. def listen_receive_loop(self, callback=None, logger=None):
  103. while True:
  104. self.listen()
  105. while self.connected():
  106. data = self.receive()
  107. if callback is not None:
  108. callback(self, data, logger)
  109. def close(self, logger=None):
  110. if self._client_sock is not None:
  111. self._client_sock.close()
  112. self._client_sock = None
  113. if self._server_sock is not None:
  114. self._server_sock.close()
  115. self._server_sock = None
  116. def __del__(self):
  117. self.close()
  118. class stp_bt_server(stp_bt_base, bt_server):
  119. def __init__(self, *args, **kwargs):
  120. bt_server.__init__(self, *args, **kwargs)
  121. self._stp = stringtools.stp.stp()
  122. self._bt = bt_server
  123. class bt_client(bt_base):
  124. def __init__(self, bt_id, uuid, logger=None):
  125. self.logger = logger or logging.getLogger('%s' % (self.__class__.__name__))
  126. self._connection_established = False
  127. self._bt_id = bt_id
  128. self._uuid = uuid
  129. self._client_sock = None
  130. self._connected = False
  131. def connect(self, logger=None):
  132. logit = logger or self.logger
  133. service_matches = bluetooth.find_service(uuid=self._uuid, address=self._bt_id)
  134. # TODO: find_named_service and remove service_id from classes
  135. if len(service_matches) == 0:
  136. logit.debug("BT: couldn't find the RFCOM service %s", self._uuid)
  137. else:
  138. first_match = service_matches[0]
  139. port = first_match["port"]
  140. name = first_match["name"]
  141. host = first_match["host"]
  142. # Create the client socket
  143. logit.debug("connecting to \"%s\" on %s", name, host)
  144. self._client_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
  145. try:
  146. self._client_sock.connect((host, port))
  147. except bluetooth.btcommon.BluetoothError, e:
  148. if e.message == "(111, 'Connection refused')":
  149. logit.warning('BT: Connection refused')
  150. else:
  151. raise e
  152. else:
  153. self._client_sock.settimeout(0.1)
  154. logit.debug("connection established")
  155. self._connection_established = True
  156. return True
  157. return False
  158. def close(self, logger=None):
  159. if self._client_sock is not None:
  160. self._client_sock.close()
  161. self._client_sock = None
  162. def __del__(self):
  163. self.close()
  164. class stp_bt_client(stp_bt_base, bt_client):
  165. def __init__(self, *args, **kwargs):
  166. bt_client.__init__(self, *args, **kwargs)
  167. self._stp = stringtools.stp.stp()
  168. self._bt = bt_client