mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add dhcp discovery to Roborock (#141148)
* Add discovery to Roborock * Update homeassistant/components/roborock/config_flow.py Co-authored-by: Allen Porter <allen.porter@gmail.com> * MR comments * go back to removing the ":" * change method of getting devices --------- Co-authored-by: Allen Porter <allen.porter@gmail.com>
This commit is contained in:
parent
ddd67a7e58
commit
e2e80a850c
@ -28,7 +28,9 @@ from homeassistant.config_entries import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import CONF_USERNAME
|
from homeassistant.const import CONF_USERNAME
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_BASE_URL,
|
CONF_BASE_URL,
|
||||||
@ -137,6 +139,22 @@ class RoborockFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_step_dhcp(
|
||||||
|
self, discovery_info: DhcpServiceInfo
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle a flow started by a dhcp discovery."""
|
||||||
|
device_registry = dr.async_get(self.hass)
|
||||||
|
device = device_registry.async_get_device(
|
||||||
|
connections={
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, dr.format_mac(discovery_info.macaddress))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if device is not None and any(
|
||||||
|
identifier[0] == DOMAIN for identifier in device.identifiers
|
||||||
|
):
|
||||||
|
return self.async_abort(reason="already_configured")
|
||||||
|
return await self.async_step_user()
|
||||||
|
|
||||||
async def async_step_reauth(
|
async def async_step_reauth(
|
||||||
self, entry_data: Mapping[str, Any]
|
self, entry_data: Mapping[str, Any]
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
|
@ -129,7 +129,9 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
|
|||||||
self.current_map: int | None = None
|
self.current_map: int | None = None
|
||||||
|
|
||||||
if mac := self.roborock_device_info.network_info.mac:
|
if mac := self.roborock_device_info.network_info.mac:
|
||||||
self.device_info[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, mac)}
|
self.device_info[ATTR_CONNECTIONS] = {
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, dr.format_mac(mac))
|
||||||
|
}
|
||||||
# Maps from map flag to map name
|
# Maps from map flag to map name
|
||||||
self.maps: dict[int, RoborockMapInfo] = {}
|
self.maps: dict[int, RoborockMapInfo] = {}
|
||||||
self._home_data_rooms = {str(room.id): room.name for room in home_data_rooms}
|
self._home_data_rooms = {str(room.id): room.name for room in home_data_rooms}
|
||||||
|
@ -3,6 +3,17 @@
|
|||||||
"name": "Roborock",
|
"name": "Roborock",
|
||||||
"codeowners": ["@Lash-L", "@allenporter"],
|
"codeowners": ["@Lash-L", "@allenporter"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
|
"dhcp": [
|
||||||
|
{
|
||||||
|
"macaddress": "249E7D*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"macaddress": "B04A39*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostname": "roborock-*"
|
||||||
|
}
|
||||||
|
],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/roborock",
|
"documentation": "https://www.home-assistant.io/integrations/roborock",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["roborock"],
|
"loggers": ["roborock"],
|
||||||
|
@ -34,9 +34,7 @@ rules:
|
|||||||
# Gold
|
# Gold
|
||||||
devices: done
|
devices: done
|
||||||
diagnostics: done
|
diagnostics: done
|
||||||
discovery:
|
discovery: done
|
||||||
status: todo
|
|
||||||
comment: Determine if these devices can support discovery
|
|
||||||
discovery-update-info:
|
discovery-update-info:
|
||||||
status: exempt
|
status: exempt
|
||||||
comment: Devices do not support discovery.
|
comment: Devices do not support discovery.
|
||||||
|
12
homeassistant/generated/dhcp.py
generated
12
homeassistant/generated/dhcp.py
generated
@ -498,6 +498,18 @@ DHCP: Final[list[dict[str, str | bool]]] = [
|
|||||||
"hostname": "ring*",
|
"hostname": "ring*",
|
||||||
"macaddress": "341513*",
|
"macaddress": "341513*",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"domain": "roborock",
|
||||||
|
"macaddress": "249E7D*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "roborock",
|
||||||
|
"macaddress": "B04A39*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "roborock",
|
||||||
|
"hostname": "roborock-*",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"domain": "roomba",
|
"domain": "roomba",
|
||||||
"hostname": "irobot-*",
|
"hostname": "irobot-*",
|
||||||
|
@ -229,7 +229,13 @@ async def setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
async def cleanup_map_storage(
|
async def cleanup_map_storage(cleanup_map_storage_manual) -> Generator[pathlib.Path]:
|
||||||
|
"""Test cleanup, remove any map storage persisted during the test."""
|
||||||
|
return cleanup_map_storage_manual
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def cleanup_map_storage_manual(
|
||||||
hass: HomeAssistant, mock_roborock_entry: MockConfigEntry
|
hass: HomeAssistant, mock_roborock_entry: MockConfigEntry
|
||||||
) -> Generator[pathlib.Path]:
|
) -> Generator[pathlib.Path]:
|
||||||
"""Test cleanup, remove any map storage persisted during the test."""
|
"""Test cleanup, remove any map storage persisted during the test."""
|
||||||
|
@ -1120,10 +1120,10 @@ PROP = DeviceProp(
|
|||||||
)
|
)
|
||||||
|
|
||||||
NETWORK_INFO = NetworkInfo(
|
NETWORK_INFO = NetworkInfo(
|
||||||
ip="123.232.12.1", ssid="wifi", mac="ac:cc:cc:cc:cc", bssid="bssid", rssi=90
|
ip="123.232.12.1", ssid="wifi", mac="ac:cc:cc:cc:cc:cc", bssid="bssid", rssi=90
|
||||||
)
|
)
|
||||||
NETWORK_INFO_2 = NetworkInfo(
|
NETWORK_INFO_2 = NetworkInfo(
|
||||||
ip="123.232.12.2", ssid="wifi", mac="ac:cc:cc:cc:cd", bssid="bssid", rssi=90
|
ip="123.232.12.2", ssid="wifi", mac="ac:cc:cc:cc:cd:cc", bssid="bssid", rssi=90
|
||||||
)
|
)
|
||||||
|
|
||||||
MULTI_MAP_LIST = MultiMapsList.from_dict(
|
MULTI_MAP_LIST = MultiMapsList.from_dict(
|
||||||
|
@ -19,8 +19,9 @@ from homeassistant.components.roborock.const import CONF_ENTRY_CODE, DOMAIN, DRA
|
|||||||
from homeassistant.const import CONF_USERNAME
|
from homeassistant.const import CONF_USERNAME
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||||
|
|
||||||
from .mock_data import MOCK_CONFIG, USER_DATA, USER_EMAIL
|
from .mock_data import MOCK_CONFIG, NETWORK_INFO, USER_DATA, USER_EMAIL
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
@ -281,3 +282,68 @@ async def test_account_already_configured(
|
|||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "already_configured_account"
|
assert result["reason"] == "already_configured_account"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_not_setup(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
bypass_api_fixture,
|
||||||
|
) -> None:
|
||||||
|
"""Handle the config flow and make sure it succeeds."""
|
||||||
|
with (
|
||||||
|
patch("homeassistant.components.roborock.async_setup_entry", return_value=True),
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
|
data=DhcpServiceInfo(
|
||||||
|
ip=NETWORK_INFO.ip,
|
||||||
|
macaddress=NETWORK_INFO.mac.replace(":", ""),
|
||||||
|
hostname="roborock-vacuum-a72",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.roborock.config_flow.RoborockApiClient.request_code"
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {CONF_USERNAME: USER_EMAIL}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "code"
|
||||||
|
assert result["errors"] == {}
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.roborock.config_flow.RoborockApiClient.code_login",
|
||||||
|
return_value=USER_DATA,
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_ENTRY_CODE: "123456"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == USER_EMAIL
|
||||||
|
assert result["data"] == MOCK_CONFIG
|
||||||
|
assert result["result"]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_already_setup(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
bypass_api_fixture,
|
||||||
|
mock_roborock_entry: MockConfigEntry,
|
||||||
|
cleanup_map_storage_manual,
|
||||||
|
) -> None:
|
||||||
|
"""Handle aborting if the device is already setup."""
|
||||||
|
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
|
data=DhcpServiceInfo(
|
||||||
|
ip=NETWORK_INFO.ip,
|
||||||
|
macaddress=NETWORK_INFO.mac.replace(":", ""),
|
||||||
|
hostname="roborock-vacuum-a72",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user