A more clever logic of parsing the manufacturer for BLE devices.

1. Check the manufacturer parsed via Bleak/Theengs
2. Check the MAC address prefix in the oui numbers table
3. Check from the reported `manufacturer_data`
This commit is contained in:
Fabio Manganiello 2023-03-22 14:16:00 +01:00
parent f7e8cfe5a7
commit f6e09d34e4
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774

View file

@ -5,7 +5,7 @@ from typing import Any, Callable, Dict, List, Optional
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
from bluetooth_numbers import company
from bluetooth_numbers import company, oui
from TheengsDecoder import decodeBLE, getAttribute, getProperties
@ -228,10 +228,7 @@ def device_to_entity(device: BLEDevice, data: AdvertisementData) -> BluetoothDev
theengs_entity = _parse_advertisement_data(data)
props = (device.details or {}).get('props', {})
manufacturer = theengs_entity.manufacturer or company.get(
next(iter(key for key in device.metadata['manufacturer_data']), 0xFFFF)
)
manufacturer = _parse_manufacturer(device, theengs_entity)
parent_entity = BluetoothDevice(
id=device.address,
model=theengs_entity.model,
@ -278,6 +275,32 @@ def device_to_entity(device: BLEDevice, data: AdvertisementData) -> BluetoothDev
return parent_entity
def _parse_manufacturer(device: BLEDevice, entity: TheengsEntity) -> Optional[str]:
"""
:param device: The target device.
:param entity: The entity that maps the received beacon data.
:return: The parsed manufacturer name.
"""
# If the manufacturer has already been parsed, return it.
if entity.manufacturer:
return entity.manufacturer
# Otherwise, infer it from the first three bytes of the MAC address.
manufacturer = oui.get(':'.join(device.address.split(':')[:3]).upper())
if manufacturer:
return manufacturer
# Otherwise, infer it from the reported manufacturer_data.
for key in device.metadata.get('manufacturer_data', {}):
manufacturer = company.get(key)
if manufacturer:
return manufacturer
# Otherwise, we couldn't parse the manufacturer.
return None
def _parse_advertisement_data(data: AdvertisementData) -> TheengsEntity:
"""
:param data: The data received from a Bluetooth advertisement packet.