Skip to content

Commit 11a51b0

Browse files
Show vendor of Bluetooth address if it has a known OUI (#37)
1 parent 25bdc48 commit 11a51b0

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

src/humble_explorer/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def add_advertisement_to_table(
252252
now,
253253
device_address,
254254
rich_advertisement,
255-
height=rich_advertisement.height(),
255+
height=max(device_address.height(), rich_advertisement.height()),
256256
)
257257
self.scroll_if_autoscroll()
258258

src/humble_explorer/renderables.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
from uuid import UUID
77

88
from bleak.backends.scanner import AdvertisementData
9-
from bluetooth_numbers import company, service
10-
from bluetooth_numbers.exceptions import UnknownCICError, UnknownUUIDError
9+
from bluetooth_numbers import company, oui, service
10+
from bluetooth_numbers.exceptions import (
11+
UnknownCICError,
12+
UnknownOUIError,
13+
UnknownUUIDError,
14+
WrongOUIFormatError,
15+
)
1116
from rich._palettes import EIGHT_BIT_PALETTE
1217
from rich.style import Style
1318
from rich.table import Table
@@ -50,7 +55,7 @@ def __rich__(self) -> Text:
5055

5156

5257
class RichDeviceAddress:
53-
"""Rich renderable that shows a Bluetooth device address.
58+
"""Rich renderable that shows a Bluetooth device address aand OUI description.
5459
5560
Every address is rendered in its own color.
5661
"""
@@ -63,13 +68,28 @@ def __init__(self, address: str) -> None:
6368
"""
6469
self.address = address
6570
self.style = Style(color=EIGHT_BIT_PALETTE[hash8(self.address)].hex)
71+
try:
72+
self.oui = oui[self.address[:8]]
73+
except (UnknownOUIError, WrongOUIFormatError):
74+
# This could be macOS that returns a UUID instead of Bluetooth address
75+
self.oui = ""
76+
77+
def height(self) -> int:
78+
"""Return the number of lines this Rich renderable uses."""
79+
height = 1
80+
if self.oui:
81+
height += 1
82+
return height # noqa: R504
6683

6784
def __rich__(self) -> Text:
6885
"""Render the RichDeviceAddress object.
6986
7087
Returns:
7188
Text: The rendering of the RichDeviceAddress object.
7289
"""
90+
if self.oui:
91+
return Text.assemble(Text(self.address, style=self.style), f"\n{self.oui}")
92+
7393
return Text(self.address, style=self.style)
7494

7595

tests/test_renderables.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,20 @@ def test_device_address() -> None:
3636
device_address = RichDeviceAddress(address_string)
3737
device_address2 = RichDeviceAddress(address_string)
3838
assert str(device_address.__rich__()) == address_string
39+
assert device_address.height() == 1
3940

4041
# Devices with the same address should have the same color
4142
assert device_address.style == device_address2.style
4243

44+
# Address with known OUI should show company description
45+
address_string_qingping = "58:2D:34:54:2D:2C"
46+
full_address_string_qingping = (
47+
"58:2D:34:54:2D:2C\nQingping Electronics (Suzhou) Co., Ltd"
48+
)
49+
device_address_qingping = RichDeviceAddress(address_string_qingping)
50+
assert str(device_address_qingping.__rich__()) == full_address_string_qingping
51+
assert device_address_qingping.height() == 2
52+
4353

4454
def test_rssi() -> None:
4555
"""Test RichRSSI class."""

0 commit comments

Comments
 (0)