Move BluetoothServiceInfoBleak to home_assistant_bluetooth (#82064)

This commit is contained in:
J. Nick Koston 2022-11-15 14:00:52 -06:00 committed by GitHub
parent c940ad9920
commit 682187541f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 56 additions and 49 deletions

View file

@ -3,7 +3,6 @@ from __future__ import annotations
import asyncio
from collections.abc import Callable, Iterable
from dataclasses import replace
from datetime import datetime, timedelta
import itertools
import logging
@ -442,7 +441,19 @@ class BluetoothManager:
# route any connection attempts to the connectable path, we
# mark the service_info as connectable so that the callbacks
# will be called and the device can be discovered.
service_info = replace(service_info, connectable=True)
service_info = BluetoothServiceInfoBleak(
name=service_info.name,
address=service_info.address,
rssi=service_info.rssi,
manufacturer_data=service_info.manufacturer_data,
service_data=service_info.service_data,
service_uuids=service_info.service_uuids,
source=service_info.source,
device=service_info.device,
advertisement=service_info.advertisement,
connectable=True,
time=service_info.time,
)
matched_domains = self._integration_matcher.match_domains(service_info)
_LOGGER.debug(

View file

@ -21,11 +21,14 @@ from bleak.backends.scanner import (
BaseBleakScanner,
)
from bleak_retry_connector import NO_RSSI_VALUE, freshen_ble_device
from home_assistant_bluetooth import BluetoothServiceInfoBleak
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.frame import report
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
from homeassistant.helpers.service_info.bluetooth import ( # noqa: F401 # pylint: disable=unused-import
BluetoothServiceInfo,
)
from homeassistant.util.dt import monotonic_time_coarse
from .const import FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS
@ -53,41 +56,6 @@ MANAGER: BluetoothManager | None = None
MONOTONIC_TIME: Final = monotonic_time_coarse
@dataclass
class BluetoothServiceInfoBleak(BluetoothServiceInfo):
"""BluetoothServiceInfo with bleak data.
Integrations may need BLEDevice and AdvertisementData
to connect to the device without having bleak trigger
another scan to translate the address to the system's
internal details.
"""
device: BLEDevice
advertisement: AdvertisementData
connectable: bool
time: float
def as_dict(self) -> dict[str, Any]:
"""Return as dict.
The dataclass asdict method is not used because
it will try to deepcopy pyobjc data which will fail.
"""
return {
"name": self.name,
"address": self.address,
"rssi": self.rssi,
"manufacturer_data": self.manufacturer_data,
"service_data": self.service_data,
"service_uuids": self.service_uuids,
"source": self.source,
"advertisement": self.advertisement,
"connectable": self.connectable,
"time": self.time,
}
class BluetoothScanningMode(Enum):
"""The mode of scanning for bluetooth devices."""

View file

@ -3,6 +3,7 @@ from __future__ import annotations
from abc import abstractmethod
import logging
from typing import cast
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
@ -69,7 +70,7 @@ class BasePassiveBluetoothCoordinator:
if service_info := async_last_service_info(
self.hass, self.address, self.connectable
):
return service_info.name
return cast(str, service_info.name) # for compat this can be a pyobjc
return self._last_name
@property

View file

@ -62,7 +62,7 @@ def async_name(
"""Return a name for the device."""
if service_info.address in (
service_info.name,
service_info.name.replace("_", ":"),
service_info.name.replace("-", ":"),
):
base_name = f"{ibeacon_advertisement.uuid}_{ibeacon_advertisement.major}_{ibeacon_advertisement.minor}"
else:

View file

@ -21,7 +21,7 @@ cryptography==38.0.3
dbus-fast==1.74.0
fnvhash==0.1.0
hass-nabucasa==0.56.0
home-assistant-bluetooth==1.6.0
home-assistant-bluetooth==1.8.0
home-assistant-frontend==20221108.0
httpx==0.23.0
ifaddr==0.1.7

View file

@ -36,7 +36,7 @@ dependencies = [
# When bumping httpx, please check the version pins of
# httpcore, anyio, and h11 in gen_requirements_all
"httpx==0.23.0",
"home-assistant-bluetooth==1.6.0",
"home-assistant-bluetooth==1.8.0",
"ifaddr==0.1.7",
"jinja2==3.1.2",
"lru-dict==1.1.8",

View file

@ -11,7 +11,7 @@ bcrypt==3.1.7
certifi>=2021.5.30
ciso8601==2.2.0
httpx==0.23.0
home-assistant-bluetooth==1.6.0
home-assistant-bluetooth==1.8.0
ifaddr==0.1.7
jinja2==3.1.2
lru-dict==1.1.8

View file

@ -227,6 +227,10 @@ async def test_diagnostics_macos(
-127,
[[]],
],
"device": {
"__type": "<class " "'bleak.backends.device.BLEDevice'>",
"repr": "BLEDevice(44:44:33:11:23:45, " "wohand)",
},
"connectable": True,
"manufacturer_data": {
"1": {"__type": "<class " "'bytes'>", "repr": "b'\\x01'"}
@ -251,6 +255,10 @@ async def test_diagnostics_macos(
-127,
[[]],
],
"device": {
"__type": "<class " "'bleak.backends.device.BLEDevice'>",
"repr": "BLEDevice(44:44:33:11:23:45, " "wohand)",
},
"connectable": True,
"manufacturer_data": {
"1": {"__type": "<class " "'bytes'>", "repr": "b'\\x01'"}

View file

@ -1,4 +1,6 @@
"""Tests for the ibeacon integration."""
from typing import Any
from bleak.backends.device import BLEDevice
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
@ -115,3 +117,18 @@ FEASY_BEACON_SERVICE_INFO_2 = BluetoothServiceInfo(
],
source="local",
)
def bluetooth_service_info_replace(
info: BluetoothServiceInfo, **kwargs: Any
) -> BluetoothServiceInfo:
"""Replace attributes of a BluetoothServiceInfoBleak."""
return BluetoothServiceInfo(
address=kwargs.get("address", info.address),
name=kwargs.get("name", info.name),
rssi=kwargs.get("rssi", info.rssi),
manufacturer_data=kwargs.get("manufacturer_data", info.manufacturer_data),
service_data=kwargs.get("service_data", info.service_data),
service_uuids=kwargs.get("service_uuids", info.service_uuids),
source=kwargs.get("source", info.source),
)

View file

@ -1,7 +1,6 @@
"""Test the ibeacon sensors."""
from dataclasses import replace
from datetime import timedelta
import time
@ -19,6 +18,7 @@ from . import (
BLUECHARM_BEACON_SERVICE_INFO_DBUS,
TESLA_TRANSIENT,
TESLA_TRANSIENT_BLE_DEVICE,
bluetooth_service_info_replace as replace,
)
from tests.common import MockConfigEntry, async_fire_time_changed
@ -145,16 +145,17 @@ async def test_ignore_default_name(hass):
assert len(hass.states.async_entity_ids()) == before_entity_count
async def test_rotating_major_minor_and_mac(hass):
async def test_rotating_major_minor_and_mac_with_name(hass):
"""Test the different uuid, major, minor from many addresses removes all associated entities."""
entry = MockConfigEntry(
domain=DOMAIN,
)
entry.add_to_hass(hass)
before_entity_count = len(hass.states.async_entity_ids("device_tracker"))
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
before_entity_count = len(hass.states.async_entity_ids("device_tracker"))
for i in range(100):
service_info = BluetoothServiceInfo(
name="BlueCharm_177999",
@ -186,9 +187,10 @@ async def test_rotating_major_minor_and_mac_no_name(hass):
)
entry.add_to_hass(hass)
before_entity_count = len(hass.states.async_entity_ids("device_tracker"))
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
before_entity_count = len(hass.states.async_entity_ids("device_tracker"))
for i in range(51):
service_info = BluetoothServiceInfo(
name=f"AA:BB:CC:DD:EE:{i:02X}",

View file

@ -1,7 +1,6 @@
"""Test the ibeacon device trackers."""
from dataclasses import replace
from datetime import timedelta
import time
from unittest.mock import patch
@ -22,6 +21,7 @@ from . import (
BEACON_RANDOM_ADDRESS_SERVICE_INFO,
BLUECHARM_BEACON_SERVICE_INFO,
BLUECHARM_BLE_DEVICE,
bluetooth_service_info_replace as replace,
)
from tests.common import MockConfigEntry, async_fire_time_changed

View file

@ -1,7 +1,6 @@
"""Test the ibeacon sensors."""
from dataclasses import replace
from datetime import timedelta
import pytest
@ -24,6 +23,7 @@ from . import (
FEASY_BEACON_SERVICE_INFO_1,
FEASY_BEACON_SERVICE_INFO_2,
NO_NAME_BEACON_SERVICE_INFO,
bluetooth_service_info_replace as replace,
)
from tests.common import MockConfigEntry, async_fire_time_changed