diff --git a/README.md b/README.md index e801c6b..54ae7b8 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Compatibility with +200 GATT characteristics following [GATT Specifications](htt `char --> Temperature Characteristic` -``` +```python from bleak_sigspec.utils import get_char_value [...] 37 @@ -38,7 +38,7 @@ from bleak_sigspec.utils import get_char_value ``` -``` +```bash $ python3 service_explorer.py [...] Characteristic Name: Temperature, Bytes Value: b'Z\x16', Formatted Value: {'Temperature': {'Quantity': 'thermodynamic temperature', @@ -47,9 +47,43 @@ Characteristic Name: Temperature, Bytes Value: b'Z\x16', Formatted Value: {'Temp 'Value': 57.22}} ``` +### See characteristic metadata + +```python +Python 3.7.6 (v3.7.6:43364a7ae0, Dec 18 2019, 14:18:50) +[Clang 6.0 (clang-600.0.57)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> from bleak_sigspec.utils import get_xml_char +>>> temp = get_xml_char('Temperature') +>>> temp +Characteristic Metadata: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + - NAME: Temperature + - UUID: 2A6E + - ABSTRACT: None + - SUMMARY: None + - FIELDS: + - Temperature: + - InformativeText: Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius + - Requirement: Mandatory + - Format: sint16 + - Ctype: h + - Unit_id: org.bluetooth.unit.thermodynamic_temperature.degree_celsius + - Quantity: thermodynamic temperature + - Unit: degree celsius + - Symbol: °C + - DecimalExponent: -2 + - TYPE: org.bluetooth.characteristic.temperature + - INFO TEXT: Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius + - DESCRIPTION: None + - NOTE: None +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +>>> + +``` ### Documentation See the documentation at [https://bleak-sigspec.readthedocs.io](https://bleak-sigspec.readthedocs.io) - diff --git a/bleak_sigspec/utils.py b/bleak_sigspec/utils.py index acc8d4c..b1fd907 100644 --- a/bleak_sigspec/utils.py +++ b/bleak_sigspec/utils.py @@ -11,6 +11,7 @@ from bleak_sigspec.formatter import SuperStruct from bleak.backends.characteristic import BleakGATTCharacteristic import bleak_sigspec +import textwrap CHARS_XML_DIR = os.path.join(bleak_sigspec.__path__[0], @@ -169,6 +170,11 @@ def __init__(self, xml_file, path=CHARS_XML_DIR): self.name = None self.char_type = None self.uuid = None + self.abstract = None + self.summary = None + self.description = None + self.info_text = None + self.note = None self.xml_tags = {} self.fields = {} self._actual_field = None @@ -176,9 +182,87 @@ def __init__(self, xml_file, path=CHARS_XML_DIR): self._actual_bitfield = None self._actual_bit = None self._nr = 0 + self._metadata_string = '' + self._wrapper = textwrap.TextWrapper(initial_indent=" "*4,) self._get_data() self._get_fields() + def __repr__(self): + self._metadata_string = '' + self._metadata_string += 'Characteristic Metadata:\n' + self._metadata_string += '━'*50 + '\n' + self._pretty_print_metadata() + self._metadata_string += '━'*50 + '\n' + return self._metadata_string + + def _get_metadata_string(self): + self._metadata_string = '' + self._metadata_string += 'Characteristic Metadata:\n' + self._metadata_string += '━'*50 + '\n' + self._pretty_print_metadata() + self._metadata_string += '━'*50 + '\n' + return self._metadata_string + + def _pretty_print_metadata(self): + self._print_wrp('- NAME: {}'.format(self.name)) + self._print_wrp('- UUID: {}'.format(self.uuid)) + self._print_wrp('- ABSTRACT: {}'.format(self.abstract), + indent=4 + len('- ABSTRACT: ')) + self._print_wrp('- SUMMARY: {}'.format(self.summary), + indent=4 + len('- SUMMARY: ')) + self._print_wrp('- FIELDS:') + for field in self.fields: + self._print_wrp('- {}: '.format(field), f_indent=8) + for key in self.fields[field]: + if key == 'BitField': + self._print_wrp('- {}:'.format(key), f_indent=12) + for bit in self.fields[field][key]: + self._print_wrp('- {}: '.format(bit), f_indent=16) + for keybit in self.fields[field][key][bit].keys(): + if keybit == 'Enumerations': + self._print_wrp( + '- {}:'.format(keybit), f_indent=20) + for k, v in self.fields[field][key][bit][keybit].items(): + + self._print_wrp( + '- {}: {}'.format(k, v), f_indent=24) + else: + self._print_wrp( + '- {}: {}'.format(keybit, self.fields[field][key][bit][keybit]), f_indent=20) + else: + if key == 'Enumerations': + if 'BitField' not in self.fields[field].keys(): + self._print_wrp('- {}:'.format(key), f_indent=12) + for k, v in self.fields[field][key].items(): + + self._print_wrp( + '- {}: {}'.format(k, v), f_indent=16) + else: + self._print_wrp( + '- {}: {}'.format(key, self.fields[field][key]), f_indent=12, indent=12) + + self._print_wrp('- TYPE: {}'.format(self.char_type)) + self._print_wrp('- INFO TEXT: {}'.format(self.info_text), + indent=4 + len('- INFO TEXT: ')) + self._print_wrp('- DESCRIPTION: {}'.format(self.description), + indent=4 + len('- DESCRIPTION: ')) + self._print_wrp('- NOTE: {}'.format(self.note), + indent=4 + len('- NOTE: ')) + + def _print_wrp(self, text, mg=3, f_indent=4, indent=0, + f_indent_char='', r_indent_char=' ', s_indent=' '): + try: + columns, rows = os.get_terminal_size(0) + except Exception as e: + columns = 143 + if f_indent_char != '': + f_indent += -1 + self._wrapper.initial_indent = f_indent_char + r_indent_char * f_indent + self._wrapper.subsequent_indent = s_indent + ' ' * indent + self._wrapper.width = columns-mg + # print('\n'.join(self._wrapper.wrap(text))) + self._metadata_string += '\n'.join(self._wrapper.wrap(text)) + '\n' + def _get_data(self): for val in self._root.iter(): try: @@ -191,6 +275,31 @@ def _get_data(self): self.name = self.char_metadata["name"] self.char_type = self.char_metadata["type"] self.uuid = self.char_metadata["uuid"] + if val.tag == 'Summary': + if hasattr(val.text, 'strip'): + self.summary = val.text.strip() + else: + self.summary = val.text + if val.tag == 'Description': + if hasattr(val.text, 'strip'): + self.description = val.text.strip() + else: + self.description = val.text + if val.tag == 'InformativeText': + if hasattr(val.text, 'strip'): + self.info_text = val.text.strip() + else: + self.info_text = val.text + if val.tag == 'Note': + if hasattr(val.text, 'strip'): + self.note = val.text.strip() + else: + self.note = val.text + if val.tag == 'p': + if hasattr(val.text, 'strip'): + if self.note is None: + self.note = '' + self.note += val.text.strip() + '\n' except Exception as e: print(traceback.format_exc()) diff --git a/changelog.md b/changelog.md index c613b42..25d2b8e 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.0.3] Unreleased [Github Repo] + +### Added +- xml characteristic `__repr__` method modified to include readable metadata ## [0.0.2] 2020-08-27 ## [0.0.1] 2020-08-27 diff --git a/docs/source/index.rst b/docs/source/index.rst index b35103d..c0dd389 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -69,6 +69,38 @@ Usage 'Value': 57.22}} +*Example:* See characteristic metadata + +.. code-block:: python + + >>> from bleak_sigspec.utils import get_xml_char + >>> temp = get_xml_char('Temperature') + >>> temp + Characteristic Metadata: + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + - NAME: Temperature + - UUID: 2A6E + - ABSTRACT: None + - SUMMARY: None + - FIELDS: + - Temperature: + - InformativeText: Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius + - Requirement: Mandatory + - Format: sint16 + - Ctype: h + - Unit_id: org.bluetooth.unit.thermodynamic_temperature.degree_celsius + - Quantity: thermodynamic temperature + - Unit: degree celsius + - Symbol: °C + - DecimalExponent: -2 + - TYPE: org.bluetooth.characteristic.temperature + - INFO TEXT: Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius + - DESCRIPTION: None + - NOTE: None + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + >>> + Contribute ---------- diff --git a/setup.py b/setup.py index 366098d..edf2443 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ def readme(): setup(name='bleak_sigspec', - version='0.0.2', + version='0.0.3', description='Bleak SIG Bluetooth Low Energy Characteristics Specification Formatter', long_description=readme(), long_description_content_type='text/markdown',