Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bleak troubleshooting #70

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def get_options():
'-c', '--connection',
default='auto://',
help='''Specify connection URL to use, `protocol://mac?param=X` with protocol in:
"gatt","pygatt","gattlib","gattool", "bluepy","bluegiga"'''
"gatt", "pygatt", "gattlib", "gattool", "bluepy", "bluegiga", "bleak"'''
)
arg_parser.add_argument(
'-d', '--demo',
Expand Down Expand Up @@ -246,7 +246,7 @@ def connection_from_url(url):


if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, format='%(relativeCreated)d\t%(levelname)s\t%(name)s\t%(message)s')
logging.basicConfig(level=logging.DEBUG, format='%(relativeCreated)d\t%(levelname)s\t%(name)s\t%(message)s')
parser = get_options()
options = parser.parse_args()
parameters = {}
Expand All @@ -256,7 +256,7 @@ def connection_from_url(url):
except ValueError as err:
parser.error(err.args[0])

hub = MoveHub(**parameters)
hub = MoveHub(get_connection_bleak(hub_name='LEGO Move Hub'))
try:
demo = DEMO_CHOICES[options.demo]
demo(hub)
Expand Down
3 changes: 2 additions & 1 deletion pylgbst/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import traceback

from pylgbst.comms import DebugServer
from pylgbst.comms.cbleak import BleakConnection, BleakConnection2

log = logging.getLogger('pylgbst')

Expand Down Expand Up @@ -48,7 +49,7 @@ def get_connection_bleak(controller='hci0', hub_mac=None, hub_name=None):
del controller # to prevent code analysis warning
from pylgbst.comms.cbleak import BleakDriver

return BleakDriver(hub_mac, hub_name)
return BleakConnection2().connect(hub_mac, hub_name)


def get_connection_auto(controller='hci0', hub_mac=None, hub_name=None):
Expand Down
2 changes: 1 addition & 1 deletion pylgbst/comms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@


class Connection(object):
def connect(self, hub_mac=None):
def connect(self, hub_mac=None, hub_name=None):
pass

@abstractmethod
Expand Down
93 changes: 89 additions & 4 deletions pylgbst/comms/cbleak.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,91 @@
req_queue = queue.Queue()




class BleakConnection2(Connection):
"""
:type _client: BleakClient
"""

def __init__(self) -> None:
super().__init__()
self._abort = False
self._loop = asyncio.new_event_loop()
asyncio.set_event_loop(self._loop)
self._client = None # noqa
self._notify_queue = queue.Queue()

def connect(self, hub_mac=None, hub_name=None):
#logging.getLogger('bleak.backends.dotnet.client').setLevel(logging.WARNING)
#logging.getLogger('bleak.backends.bluezdbus.client').setLevel(logging.WARNING)
#logging.getLogger('bleak.backends.dotnet.discovery').setLevel(logging.WARNING)
#logging.getLogger('bleak.backends.bluezdbus.discovery').setLevel(logging.WARNING)

log.info("Discovering devices... Press green button on Hub")
for i in range(0, 30):
devices = self._loop.run_until_complete(discover(timeout=1))
log.debug("Devices: %s", devices)
for dev in devices:
log.debug(dev)
address = dev.address
name = dev.name
if self._is_device_matched(address, name, hub_mac, hub_name):
log.info('Device matched: %r', dev)
device = dev
break
else:
continue

break
else:
raise ConnectionError('Device not found.')

self._client = BleakClient(device.address, self._loop)
status = self._loop.run_until_complete(self._client.connect())
log.debug('Connection status: %s', status)

def enqueue(handle, data):
log.debug("Put into queue: %s", data)
self._notify_queue.put((handle, data))

self._loop.run_until_complete(self._client.start_notify(MOVE_HUB_HW_UUID_CHAR, enqueue))

return self

def disconnect(self):
self._abort = True
if self.is_alive():
log.debug("Disconnecting bleak connection")
self._loop.run_until_complete(self._client.disconnect())

def is_alive(self):
log.debug("Checking if bleak conn is alive")
return self._loop.run_until_complete(self._client.is_connected())

def write(self, handle, data):
desc = self._client.services.get_descriptor(handle)

if not isinstance(data, bytearray):
data = bytearray(data)

if desc is None:
# dedicated handle not found, try to send by using LEGO Move Hub default characteristic
self._loop.run_until_complete(self._client.write_gatt_char(MOVE_HUB_HW_UUID_CHAR, data))
else:
self._loop.run_until_complete(self._client.write_gatt_char(desc.characteristic_uuid, data))

def set_notify_handler(self, handler):
def _processing():
while not self._abort:
handle, data = self._notify_queue.get(block=True)
handler(handle, data)

log.info("Processing thread has exited")

threading.Thread(target=_processing, daemon=True).start()


class BleakDriver(object):
"""Driver that provides interface between API and Bleak."""

Expand Down Expand Up @@ -68,7 +153,7 @@ async def _bleak_thread(self):
data = req_queue.get()
await bleak.write(data[0], data[1])

logging.info("Communications thread has exited")
log.info("Communications thread has exited")

@staticmethod
def _safe_handler(handler, data):
Expand All @@ -81,7 +166,7 @@ def _processing(self):
self._handler(msg[0], msg[1])

time.sleep(0.01)
logging.info("Processing thread has exited")
log.info("Processing thread has exited")

def write(self, handle, data):
"""
Expand Down Expand Up @@ -122,7 +207,7 @@ class BleakConnection(Connection):

def __init__(self):
"""Initialize new instance of BleakConnection class."""
Connection.__init__(self)
super().__init__(self)
self.loop = asyncio.get_event_loop()

self._device = None
Expand Down Expand Up @@ -213,4 +298,4 @@ def is_alive(self):
This method does nothing.
:return: None.
"""
pass
return self._client.is_connected()
17 changes: 11 additions & 6 deletions pylgbst/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,8 @@ def _handle_device_change(self, msg):
log.info("Attached peripheral: %s", self.peripherals[msg.port])

if msg.event == msg.EVENT_ATTACHED:
hw_revision = reversed([usbyte(msg.payload, x) for x in range(2, 6)])
sw_revision = reversed([usbyte(msg.payload, x) for x in range(6, 10)])
# what to do with this info? it's useless, I guess
del hw_revision, sw_revision
self.peripherals[port].hw_revision = reversed([usbyte(msg.payload, x) for x in range(2, 6)])
self.peripherals[port].sw_revision = reversed([usbyte(msg.payload, x) for x in range(6, 10)])
elif msg.event == msg.EVENT_ATTACHED_VIRTUAL:
self.peripherals[port].virtual_ports = (usbyte(msg.payload, 2), usbyte(msg.payload, 3))

Expand Down Expand Up @@ -206,7 +204,6 @@ def __init__(self, connection=None):
self.info = {}

# shorthand fields
self.button = Button(self)
self.led = None
self.current = None
self.voltage = None
Expand All @@ -219,6 +216,14 @@ def __init__(self, connection=None):
self.port_C = None
self.port_D = None

self.info = {}

if connection is None:
connection = get_connection_auto(hub_name="LEGO Move Hub")

super(MoveHub, self).__init__(connection)
self.button = Button(self)

self._wait_for_devices()
self._report_status()

Expand All @@ -232,7 +237,7 @@ def _wait_for_devices(self, get_dev_set=None):
log.debug("All devices are present: %s", devices)
return
log.debug("Waiting for builtin devices to appear: %s", devices)
time.sleep(0.1)
time.sleep(0.2)
log.warning("Got only these devices: %s", get_dev_set())

def _report_status(self):
Expand Down
2 changes: 2 additions & 0 deletions pylgbst/peripherals.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def __init__(self, parent, port):
:type port: int
"""
super(Peripheral, self).__init__()
self.sw_revision = None
self.hw_revision = None
self.virtual_ports = ()
self.hub = parent
self.port = port
Expand Down