diff --git a/jc/parsers/bluetoothctl.py b/jc/parsers/bluetoothctl.py index 84de1528..2fabd41b 100644 --- a/jc/parsers/bluetoothctl.py +++ b/jc/parsers/bluetoothctl.py @@ -28,6 +28,8 @@ Controller: [ { + "manufacturer": string, + "version": string, "name": string, "is_default": boolean, "is_public": boolean, @@ -127,6 +129,8 @@ class info(): Controller = TypedDict( "Controller", { + "manufacturer": str, + "version": str, "name": str, "is_default": bool, "is_public": bool, @@ -175,7 +179,9 @@ class info(): _controller_head_pattern = r"Controller (?P
([0-9A-F]{2}:){5}[0-9A-F]{2}) (?P.+)" _controller_line_pattern = ( - r"(\s*Name:\s*(?P.+)" + r"(\s*Manufacturer:\s*(?P.+)" + + r"|\s*Version:\s*(?P.+)" + + r"|\s*Name:\s*(?P.+)" + r"|\s*Alias:\s*(?P.+)" + r"|\s*Class:\s*(?P.+)" + r"|\s*Powered:\s*(?P.+)" @@ -203,6 +209,8 @@ def _parse_controller(next_lines: List[str]) -> Optional[Controller]: return None controller: Controller = { + "manufacturer": '', + "version": '', "name": '', "is_default": False, "is_public": False, @@ -241,7 +249,11 @@ def _parse_controller(next_lines: List[str]) -> Optional[Controller]: matches = result.groupdict() - if matches["name"]: + if matches["manufacturer"]: + controller["manufacturer"] = matches["manufacturer"] + elif matches["version"]: + controller["version"] = matches["version"] + elif matches["name"]: controller["name"] = matches["name"] elif matches["alias"]: controller["alias"] = matches["alias"] diff --git a/tests/fixtures/generic/bluetoothctl_controller_with_manufacturer.out b/tests/fixtures/generic/bluetoothctl_controller_with_manufacturer.out new file mode 100644 index 00000000..6b46fd96 --- /dev/null +++ b/tests/fixtures/generic/bluetoothctl_controller_with_manufacturer.out @@ -0,0 +1,37 @@ +Controller 48:A4:72:3C:96:63 (public) + Manufacturer: 0x0002 (2) + Version: 0x08 (8) + Name: ubuntu + Alias: ubuntu + Class: 0x007c0104 (8126724) + Powered: yes + Discoverable: yes + DiscoverableTimeout: 0x000000b4 (180) + Pairable: yes + UUID: Message Notification Se.. (00001133-0000-1000-8000-00805f9b34fb) + UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb) + UUID: OBEX Object Push (00001105-0000-1000-8000-00805f9b34fb) + UUID: Message Access Server (00001132-0000-1000-8000-00805f9b34fb) + UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb) + UUID: IrMC Sync (00001104-0000-1000-8000-00805f9b34fb) + UUID: Vendor specific (00005005-0000-1000-8000-0002ee000001) + UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb) + UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb) + UUID: Phonebook Access Server (0000112f-0000-1000-8000-00805f9b34fb) + UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb) + UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb) + UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb) + UUID: Handsfree Audio Gateway (0000111f-0000-1000-8000-00805f9b34fb) + UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb) + UUID: OBEX File Transfer (00001106-0000-1000-8000-00805f9b34fb) + UUID: Handsfree (0000111e-0000-1000-8000-00805f9b34fb) + Modalias: usb:v1D6Bp0246d0548 + Discovering: yes + Roles: central + Roles: peripheral +Advertising Features: + ActiveInstances: 0x00 (0) + SupportedInstances: 0x05 (5) + SupportedIncludes: tx-power + SupportedIncludes: appearance + SupportedIncludes: local-name diff --git a/tests/test_bluetoothctl.py b/tests/test_bluetoothctl.py index f573f950..1df04213 100644 --- a/tests/test_bluetoothctl.py +++ b/tests/test_bluetoothctl.py @@ -104,6 +104,58 @@ def test_bluetoothctl_controller(self): if actual: for k, v in expected.items(): self.assertEqual(v, actual[0][k], f"Controller regex failed on {k}") + + def test_bluetoothctl_controller_with_manufacturer(self): + """ + Test 'bluetoothctl' with controller having manufacturer attr + """ + + with open("tests/fixtures/generic/bluetoothctl_controller_with_manufacturer.out", "r") as f: + output = f.read() + + actual = parse(output, quiet=True) + + self.assertIsNotNone(actual) + self.assertIsNotNone(actual[0]) + + expected = { + "manufacturer": "0x0002 (2)", + "version": "0x08 (8)", + "address": "48:A4:72:3C:96:63", + "is_public": True, + "name": "ubuntu", + "alias": "ubuntu", + "class": "0x007c0104 (8126724)", + "powered": "yes", + "discoverable": "yes", + "discoverable_timeout": "0x000000b4 (180)", + "pairable": "yes", + "uuids": [ + "Message Notification Se.. (00001133-0000-1000-8000-00805f9b34fb)", + "A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)", + "OBEX Object Push (00001105-0000-1000-8000-00805f9b34fb)", + "Message Access Server (00001132-0000-1000-8000-00805f9b34fb)", + "PnP Information (00001200-0000-1000-8000-00805f9b34fb)", + "IrMC Sync (00001104-0000-1000-8000-00805f9b34fb)", + "Vendor specific (00005005-0000-1000-8000-0002ee000001)", + "A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)", + "Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)", + "Phonebook Access Server (0000112f-0000-1000-8000-00805f9b34fb)", + "Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)", + "Device Information (0000180a-0000-1000-8000-00805f9b34fb)", + "Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)", + "Handsfree Audio Gateway (0000111f-0000-1000-8000-00805f9b34fb)", + "Audio Source (0000110a-0000-1000-8000-00805f9b34fb)", + "OBEX File Transfer (00001106-0000-1000-8000-00805f9b34fb)", + "Handsfree (0000111e-0000-1000-8000-00805f9b34fb)" + ], + "modalias": "usb:v1D6Bp0246d0548", + "discovering": "yes" + } + + if actual: + for k, v in expected.items(): + self.assertEqual(v, actual[0][k], f"Controller regex failed on {k}") def test_bluetoothctl_controllers(self): """