forked from Bluetooth-Devices/bluetooth-data-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
63 lines (44 loc) · 2.13 KB
/
Copy pathutils.py
File metadata and controls
63 lines (44 loc) · 2.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"""Bluetooth utils."""
from __future__ import annotations
from functools import lru_cache
from struct import Struct
try:
from ._utils_impl import ( # noqa: F811 F401
_int_to_bluetooth_address,
_mac_to_int,
)
except ImportError:
def _int_to_bluetooth_address(address: int) -> str:
"""Convert an integer to a bluetooth address."""
mac_hex = f"{address:012X}"
return f"{mac_hex[0:2]}:{mac_hex[2:4]}:{mac_hex[4:6]}:{mac_hex[6:8]}:{mac_hex[8:10]}:{mac_hex[10:12]}" # noqa: E501
def _mac_to_int(address: str) -> int:
"""Convert a mac address to an integer."""
length = len(address)
if length != 17 and length != 12:
raise ValueError(f"Invalid MAC address: {address!r}")
return int(address.replace(":", "").replace("-", ""), 16)
int_to_bluetooth_address = lru_cache(maxsize=256)(_int_to_bluetooth_address)
mac_to_int = lru_cache(maxsize=256)(_mac_to_int)
def short_address(address: str) -> str:
"""Convert a Bluetooth address to a short address."""
results = address.replace("-", ":").split(":")
last: str = results[-1]
second_last: str = results[-2]
return f"{second_last.upper()}{last.upper()}"[-4:]
@lru_cache(maxsize=512)
def human_readable_name(name: str | None, local_name: str, address: str) -> str:
"""Return a human readable name for the given name, local_name, and address."""
return f"{name or local_name} ({short_address(address)})"
def newest_manufacturer_data(manufacturer_data: dict[int, bytes]) -> bytes | None:
"""Return the raw data from manufacturer data."""
if not manufacturer_data:
return None
return manufacturer_data[next(reversed(manufacturer_data))]
# Two pad bytes followed by a little-endian uint16 manufacturer ID.
# Mirrors the on-the-wire MSD AD prefix so callers can splice the body in
# without a separate concatenation step.
_pack_manufacturer_prefix = Struct("<2xH").pack
def manufacturer_data_to_raw(manufacturer_id: int, manufacturer_data: bytes) -> bytes:
"""Return the raw data from manufacturer data."""
return _pack_manufacturer_prefix(manufacturer_id) + manufacturer_data