From 5e4055bb6bd28de3b4f6852304b276e8320a0d7e Mon Sep 17 00:00:00 2001 From: Gilles Boccon-Gibod Date: Sun, 11 Aug 2024 09:33:53 -0700 Subject: [PATCH] fix attribute discovery and display --- apps/console.py | 39 +++++++++++++++++++++++++++++++++------ bumble/gatt_client.py | 1 + 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/apps/console.py b/apps/console.py index e942321..f7c8893 100644 --- a/apps/console.py +++ b/apps/console.py @@ -168,6 +168,7 @@ class ConsoleApp: 'remote-services': None, 'local-values': None, 'remote-values': None, + 'remote-attributes': None, }, 'filter': { 'address': None, @@ -216,6 +217,7 @@ class ConsoleApp: ) self.local_values_text = FormattedTextControl() self.remote_values_text = FormattedTextControl() + self.remote_attributes_text = FormattedTextControl() self.log_height = Dimension(min=7, weight=4) self.log_max_lines = 100 self.log_lines = [] @@ -242,6 +244,12 @@ class ConsoleApp: Frame(Window(self.remote_values_text), title='Remote Values'), filter=Condition(lambda: self.top_tab == 'remote-values'), ), + ConditionalContainer( + Frame( + Window(self.remote_attributes_text), title='Remote Attributes' + ), + filter=Condition(lambda: self.top_tab == 'remote-attributes'), + ), ConditionalContainer( Frame(Window(self.log_text, height=self.log_height), title='Log'), filter=Condition(lambda: self.top_tab == 'log'), @@ -504,6 +512,8 @@ class ConsoleApp: await self.connected_peer.discover_all() self.append_to_output('Service Discovery done!') + self.show_remote_services(self.connected_peer.services) + async def discover_attributes(self): if not self.connected_peer: self.show_error('not connected') @@ -514,7 +524,7 @@ class ConsoleApp: attributes = await self.connected_peer.discover_attributes() self.append_to_output(f'discovered {len(attributes)} attributes...') - self.show_attributes(attributes) + await self.show_remote_attributes(attributes) def find_remote_characteristic(self, param) -> Optional[CharacteristicProxy]: if not self.connected_peer: @@ -659,7 +669,6 @@ class ConsoleApp: connection_parameters_preferences=connection_parameters_preferences, timeout=DEFAULT_CONNECTION_TIMEOUT, ) - self.top_tab = 'services' except bumble.core.TimeoutError: self.show_error('connection timed out') @@ -730,19 +739,20 @@ class ConsoleApp: 'remote-services', 'local-values', 'remote-values', + 'remote-attributes', }: self.top_tab = params[0] self.ui.invalidate() while self.top_tab == 'local-values': - await self.do_show_local_values() + await self.show_local_values() await asyncio.sleep(1) while self.top_tab == 'remote-values': - await self.do_show_remote_values() + await self.show_remote_values() await asyncio.sleep(1) - async def do_show_local_values(self): + async def show_local_values(self): prettytable = PrettyTable() field_names = ["Service", "Characteristic", "Descriptor"] @@ -797,7 +807,7 @@ class ConsoleApp: self.local_values_text.text = prettytable.get_string() self.ui.invalidate() - async def do_show_remote_values(self): + async def show_remote_values(self): prettytable = PrettyTable( field_names=[ "Connection", @@ -831,6 +841,23 @@ class ConsoleApp: self.remote_values_text.text = prettytable.get_string() self.ui.invalidate() + async def show_remote_attributes(self, attributes): + lines = [] + for attribute in attributes: + lines.append(('ansimagenta', str(attribute) + "\n")) + try: + value = await attribute.read_value() + lines.append(('ansicyan', value.hex() + "\n")) + except bumble.core.ProtocolError as error: + lines.append(("ansired", f"!!! Protocol Error ({error})\n")) + except bumble.core.TimeoutError: + lines.append(("ansired", "!!! Timeout\n")) + except Exception as error: + lines.append(("ansired", f"!!! Error ({error})\n")) + + self.remote_attributes_text.text = lines + self.ui.invalidate() + async def do_get_phy(self, _): if not self.connected_peer: self.show_error('not connected') diff --git a/bumble/gatt_client.py b/bumble/gatt_client.py index 6d4dcf6..0cbb246 100644 --- a/bumble/gatt_client.py +++ b/bumble/gatt_client.py @@ -977,6 +977,7 @@ class Client: offset += len(part) self.cache_value(attribute_handle, attribute_value) + # Return the value as bytes return attribute_value