Add LED BLE integration (#77489)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
J. Nick Koston 2022-08-29 11:38:18 -05:00 committed by GitHub
parent af9910d143
commit 8e0c26bf86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 796 additions and 0 deletions

View file

@ -0,0 +1,51 @@
"""Tests for the LED BLE Bluetooth integration."""
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
LED_BLE_DISCOVERY_INFO = BluetoothServiceInfoBleak(
name="Triones:F30200000152C",
address="AA:BB:CC:DD:EE:FF",
rssi=-60,
manufacturer_data={},
service_uuids=[],
service_data={},
source="local",
device=BLEDevice(address="AA:BB:CC:DD:EE:FF", name="Triones:F30200000152C"),
advertisement=AdvertisementData(),
time=0,
connectable=True,
)
UNSUPPORTED_LED_BLE_DISCOVERY_INFO = BluetoothServiceInfoBleak(
name="LEDnetWFF30200000152C",
address="AA:BB:CC:DD:EE:FF",
rssi=-60,
manufacturer_data={},
service_uuids=[],
service_data={},
source="local",
device=BLEDevice(address="AA:BB:CC:DD:EE:FF", name="LEDnetWFF30200000152C"),
advertisement=AdvertisementData(),
time=0,
connectable=True,
)
NOT_LED_BLE_DISCOVERY_INFO = BluetoothServiceInfoBleak(
name="Not",
address="AA:BB:CC:DD:EE:FF",
rssi=-60,
manufacturer_data={
33: b"\x00\x00\xd1\xf0b;\xd8\x1dE\xd6\xba\xeeL\xdd]\xf5\xb2\xe9",
21: b"\x061\x00Z\x8f\x93\xb2\xec\x85\x06\x00i\x00\x02\x02Q\xed\x1d\xf0",
},
service_uuids=[],
service_data={},
source="local",
device=BLEDevice(address="AA:BB:CC:DD:EE:FF", name="Aug"),
advertisement=AdvertisementData(),
time=0,
connectable=True,
)

View file

@ -0,0 +1,8 @@
"""led_ble session fixtures."""
import pytest
@pytest.fixture(autouse=True)
def mock_bluetooth(enable_bluetooth):
"""Auto mock bluetooth."""

View file

@ -0,0 +1,229 @@
"""Test the LED BLE Bluetooth config flow."""
from unittest.mock import patch
from bleak import BleakError
from homeassistant import config_entries
from homeassistant.components.led_ble.const import DOMAIN
from homeassistant.const import CONF_ADDRESS
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from . import (
LED_BLE_DISCOVERY_INFO,
NOT_LED_BLE_DISCOVERY_INFO,
UNSUPPORTED_LED_BLE_DISCOVERY_INFO,
)
from tests.common import MockConfigEntry
async def test_user_step_success(hass: HomeAssistant) -> None:
"""Test user step success path."""
with patch(
"homeassistant.components.led_ble.config_flow.async_discovered_service_info",
return_value=[NOT_LED_BLE_DISCOVERY_INFO, LED_BLE_DISCOVERY_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
with patch("homeassistant.components.led_ble.config_flow.LEDBLE.update",), patch(
"homeassistant.components.led_ble.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result2["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == LED_BLE_DISCOVERY_INFO.name
assert result2["data"] == {
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
}
assert result2["result"].unique_id == LED_BLE_DISCOVERY_INFO.address
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_step_no_devices_found(hass: HomeAssistant) -> None:
"""Test user step with no devices found."""
with patch(
"homeassistant.components.led_ble.config_flow.async_discovered_service_info",
return_value=[NOT_LED_BLE_DISCOVERY_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "no_unconfigured_devices"
async def test_user_step_no_new_devices_found(hass: HomeAssistant) -> None:
"""Test user step with only existing devices found."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
unique_id=LED_BLE_DISCOVERY_INFO.address,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.led_ble.config_flow.async_discovered_service_info",
return_value=[LED_BLE_DISCOVERY_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "no_unconfigured_devices"
async def test_user_step_cannot_connect(hass: HomeAssistant) -> None:
"""Test user step and we cannot connect."""
with patch(
"homeassistant.components.led_ble.config_flow.async_discovered_service_info",
return_value=[LED_BLE_DISCOVERY_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
with patch(
"homeassistant.components.led_ble.config_flow.LEDBLE.update",
side_effect=BleakError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result2["type"] == FlowResultType.FORM
assert result2["step_id"] == "user"
assert result2["errors"] == {"base": "cannot_connect"}
with patch("homeassistant.components.led_ble.config_flow.LEDBLE.update",), patch(
"homeassistant.components.led_ble.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result3["type"] == FlowResultType.CREATE_ENTRY
assert result3["title"] == LED_BLE_DISCOVERY_INFO.name
assert result3["data"] == {
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
}
assert result3["result"].unique_id == LED_BLE_DISCOVERY_INFO.address
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_step_unknown_exception(hass: HomeAssistant) -> None:
"""Test user step with an unknown exception."""
with patch(
"homeassistant.components.led_ble.config_flow.async_discovered_service_info",
return_value=[NOT_LED_BLE_DISCOVERY_INFO, LED_BLE_DISCOVERY_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
with patch(
"homeassistant.components.led_ble.config_flow.LEDBLE.update",
side_effect=RuntimeError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result2["type"] == FlowResultType.FORM
assert result2["step_id"] == "user"
assert result2["errors"] == {"base": "unknown"}
with patch("homeassistant.components.led_ble.config_flow.LEDBLE.update",), patch(
"homeassistant.components.led_ble.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result3["type"] == FlowResultType.CREATE_ENTRY
assert result3["title"] == LED_BLE_DISCOVERY_INFO.name
assert result3["data"] == {
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
}
assert result3["result"].unique_id == LED_BLE_DISCOVERY_INFO.address
assert len(mock_setup_entry.mock_calls) == 1
async def test_bluetooth_step_success(hass: HomeAssistant) -> None:
"""Test bluetooth step success path."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=LED_BLE_DISCOVERY_INFO,
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
with patch("homeassistant.components.led_ble.config_flow.LEDBLE.update",), patch(
"homeassistant.components.led_ble.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
},
)
await hass.async_block_till_done()
assert result2["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == LED_BLE_DISCOVERY_INFO.name
assert result2["data"] == {
CONF_ADDRESS: LED_BLE_DISCOVERY_INFO.address,
}
assert result2["result"].unique_id == LED_BLE_DISCOVERY_INFO.address
assert len(mock_setup_entry.mock_calls) == 1
async def test_bluetooth_unsupported_model(hass: HomeAssistant) -> None:
"""Test bluetooth step with an unsupported model path."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=UNSUPPORTED_LED_BLE_DISCOVERY_INFO,
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "not_supported"