mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 02:24:51 -05:00
casper_glow: reject non-Casper Glow Bluetooth discoveries before config-flow handshake (#174242)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
co-authored by
Joost Lekkerkerker
parent
da7f25b244
commit
2fc167204c
@@ -20,6 +20,16 @@ from .const import DOMAIN, LOCAL_NAMES
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _is_casper_glow_discovery(discovery_info: BluetoothServiceInfoBleak) -> bool:
|
||||
"""Return whether the Bluetooth discovery looks like a Casper Glow."""
|
||||
return bool(
|
||||
discovery_info.name
|
||||
and any(
|
||||
discovery_info.name.startswith(local_name) for local_name in LOCAL_NAMES
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class CasperGlowConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Casper Glow."""
|
||||
|
||||
@@ -36,6 +46,9 @@ class CasperGlowConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
self, discovery_info: BluetoothServiceInfoBleak
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle the bluetooth discovery step."""
|
||||
if not _is_casper_glow_discovery(discovery_info):
|
||||
return self.async_abort(reason="not_supported")
|
||||
|
||||
await self.async_set_unique_id(format_mac(discovery_info.address))
|
||||
self._abort_if_unique_id_configured()
|
||||
self._discovery_info = discovery_info
|
||||
@@ -118,13 +131,7 @@ class CasperGlowConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if (
|
||||
format_mac(discovery.address) in current_addresses
|
||||
or discovery.address in self._discovered_devices
|
||||
or not (
|
||||
discovery.name
|
||||
and any(
|
||||
discovery.name.startswith(local_name)
|
||||
for local_name in LOCAL_NAMES
|
||||
)
|
||||
)
|
||||
or not _is_casper_glow_discovery(discovery)
|
||||
):
|
||||
continue
|
||||
self._discovered_devices[discovery.address] = discovery
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
|
||||
"not_supported": "Device not supported",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"error": {
|
||||
|
||||
@@ -27,6 +27,49 @@ CASPER_GLOW_DISCOVERY_INFO = BluetoothServiceInfoBleak(
|
||||
tx_power=-127,
|
||||
)
|
||||
|
||||
SAMSUNG_EARBUDS_ADDRESS = "72:B3:56:C4:12:B7"
|
||||
SAMSUNG_EARBUDS_NAME = "Evilpigs's Buds2 Pro"
|
||||
SAMSUNG_EARBUDS_MANUFACTURER_DATA = {
|
||||
117: bytes.fromhex(
|
||||
"020901000000150300000000000000000000000000000000000000030146015b4865616470686f6e655d20"
|
||||
)
|
||||
}
|
||||
SAMSUNG_EARBUDS_SERVICE_UUIDS = [
|
||||
"0000184e-0000-1000-8000-00805f9b34fb",
|
||||
"0000184f-0000-1000-8000-00805f9b34fb",
|
||||
"00001850-0000-1000-8000-00805f9b34fb",
|
||||
"00001844-0000-1000-8000-00805f9b34fb",
|
||||
"0000184d-0000-1000-8000-00805f9b34fb",
|
||||
]
|
||||
SAMSUNG_EARBUDS_SERVICE_DATA = {
|
||||
"00002b51-0000-1000-8000-00805f9b34fb": bytes.fromhex("2a00"),
|
||||
"00001853-0000-1000-8000-00805f9b34fb": bytes.fromhex("00"),
|
||||
"0000184e-0000-1000-8000-00805f9b34fb": bytes.fromhex("006f006b0000"),
|
||||
"a7a473e9-19c6-491b-aea6-7ea92b8f043a": bytes.fromhex("014652e70e"),
|
||||
}
|
||||
|
||||
SAMSUNG_EARBUDS_DISCOVERY_INFO = BluetoothServiceInfoBleak(
|
||||
name=SAMSUNG_EARBUDS_NAME,
|
||||
address=SAMSUNG_EARBUDS_ADDRESS,
|
||||
rssi=-82,
|
||||
manufacturer_data=SAMSUNG_EARBUDS_MANUFACTURER_DATA,
|
||||
service_uuids=SAMSUNG_EARBUDS_SERVICE_UUIDS,
|
||||
service_data=SAMSUNG_EARBUDS_SERVICE_DATA,
|
||||
source="local",
|
||||
device=generate_ble_device(
|
||||
address=SAMSUNG_EARBUDS_ADDRESS, name=SAMSUNG_EARBUDS_NAME
|
||||
),
|
||||
advertisement=generate_advertisement_data(
|
||||
local_name=SAMSUNG_EARBUDS_NAME,
|
||||
manufacturer_data=SAMSUNG_EARBUDS_MANUFACTURER_DATA,
|
||||
service_uuids=SAMSUNG_EARBUDS_SERVICE_UUIDS,
|
||||
service_data=SAMSUNG_EARBUDS_SERVICE_DATA,
|
||||
),
|
||||
time=0,
|
||||
connectable=True,
|
||||
tx_power=-127,
|
||||
)
|
||||
|
||||
|
||||
async def setup_integration(hass: HomeAssistant, entry: MockConfigEntry) -> None:
|
||||
"""Set up the Casper Glow integration."""
|
||||
|
||||
@@ -14,7 +14,11 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
|
||||
from . import CASPER_GLOW_DISCOVERY_INFO, NOT_CASPER_GLOW_DISCOVERY_INFO
|
||||
from . import (
|
||||
CASPER_GLOW_DISCOVERY_INFO,
|
||||
NOT_CASPER_GLOW_DISCOVERY_INFO,
|
||||
SAMSUNG_EARBUDS_DISCOVERY_INFO,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.bluetooth import (
|
||||
@@ -80,6 +84,21 @@ async def test_bluetooth_confirm_error(
|
||||
assert result["reason"] == reason
|
||||
|
||||
|
||||
async def test_bluetooth_step_ignores_unrecognized_device(
|
||||
hass: HomeAssistant, mock_casper_glow: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery aborts before handshaking with unsupported devices."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_BLUETOOTH},
|
||||
data=SAMSUNG_EARBUDS_DISCOVERY_INFO,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "not_supported"
|
||||
mock_casper_glow.handshake.assert_not_called()
|
||||
|
||||
|
||||
async def test_user_step_success(
|
||||
hass: HomeAssistant, mock_casper_glow: MagicMock
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user