mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add dhcp discovery to senseme (#64894)
This commit is contained in:
parent
dfb7ab5c30
commit
e28b5aee77
@ -8,6 +8,7 @@ from aiosenseme import SensemeDevice, async_get_device_by_ip_address
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.const import CONF_DEVICE, CONF_HOST, CONF_ID
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||
@ -28,6 +29,19 @@ class SensemeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._discovered_devices: list[SensemeDevice] | None = None
|
||||
self._discovered_device: SensemeDevice | None = None
|
||||
|
||||
async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowResult:
|
||||
"""Handle discovery via dhcp."""
|
||||
# If discovery is already running, it takes precedence since its more efficient
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason="already_configured")
|
||||
if device := await async_get_device_by_ip_address(discovery_info.ip):
|
||||
device.stop()
|
||||
if device is None or not device.uuid:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
await self.async_set_unique_id(device.uuid)
|
||||
self._discovered_device = device
|
||||
return await self.async_step_discovery_confirm()
|
||||
|
||||
async def async_step_discovery(
|
||||
self, discovery_info: DiscoveryInfoType
|
||||
) -> FlowResult:
|
||||
|
@ -9,5 +9,6 @@
|
||||
"codeowners": [
|
||||
"@mikelawrence", "@bdraco"
|
||||
],
|
||||
"dhcp": [{"macaddress":"20F85E*"}],
|
||||
"iot_class": "local_push"
|
||||
}
|
||||
|
@ -19,7 +19,8 @@
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
},
|
||||
"error": {
|
||||
"invalid_host": "[%key:common::config_flow::error::invalid_host%]",
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
"already_configured": "Device is already configured",
|
||||
"cannot_connect": "Failed to connect"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
|
@ -290,6 +290,10 @@ DHCP = [
|
||||
"hostname": "sense-*",
|
||||
"macaddress": "A4D578*"
|
||||
},
|
||||
{
|
||||
"domain": "senseme",
|
||||
"macaddress": "20F85E*"
|
||||
},
|
||||
{
|
||||
"domain": "simplisafe",
|
||||
"hostname": "simplisafe*",
|
||||
|
@ -10,6 +10,7 @@ from homeassistant.components.senseme import config_flow
|
||||
MOCK_NAME = "Haiku Fan"
|
||||
MOCK_UUID = "77a6b7b3-925d-4695-a415-76d76dca4444"
|
||||
MOCK_ADDRESS = "127.0.0.1"
|
||||
MOCK_MAC = "20:F8:5E:92:5A:75"
|
||||
|
||||
device = MagicMock(auto_spec=SensemeDevice)
|
||||
device.async_update = AsyncMock()
|
||||
@ -29,7 +30,7 @@ device.address = MOCK_ADDRESS
|
||||
device.get_device_info = {
|
||||
"name": MOCK_NAME,
|
||||
"uuid": MOCK_UUID,
|
||||
"mac": "20:F8:5E:92:5A:75",
|
||||
"mac": MOCK_ADDRESS,
|
||||
"address": MOCK_ADDRESS,
|
||||
"base_model": "FAN,HAIKU,HSERIES",
|
||||
"has_light": False,
|
||||
@ -94,9 +95,14 @@ device2.get_device_info = {
|
||||
"is_light": False,
|
||||
}
|
||||
|
||||
device_no_uuid = MagicMock(auto_spec=SensemeDevice)
|
||||
device_no_uuid.uuid = None
|
||||
|
||||
|
||||
MOCK_DEVICE = device
|
||||
MOCK_DEVICE_ALTERNATE_IP = device_alternate_ip
|
||||
MOCK_DEVICE2 = device2
|
||||
MOCK_DEVICE_NO_UUID = device_no_uuid
|
||||
|
||||
|
||||
def _patch_discovery(device=None, no_device=None):
|
||||
|
@ -2,6 +2,7 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.components.senseme.const import DOMAIN
|
||||
from homeassistant.const import CONF_HOST, CONF_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -16,12 +17,20 @@ from . import (
|
||||
MOCK_DEVICE,
|
||||
MOCK_DEVICE2,
|
||||
MOCK_DEVICE_ALTERNATE_IP,
|
||||
MOCK_DEVICE_NO_UUID,
|
||||
MOCK_MAC,
|
||||
MOCK_UUID,
|
||||
_patch_discovery,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
DHCP_DISCOVERY = dhcp.DhcpServiceInfo(
|
||||
hostname="any",
|
||||
ip=MOCK_ADDRESS,
|
||||
macaddress=MOCK_MAC,
|
||||
)
|
||||
|
||||
|
||||
async def test_form_user(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form as a user."""
|
||||
@ -280,3 +289,77 @@ async def test_discovery_existing_device_ip_change(hass: HomeAssistant) -> None:
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert entry.data["info"]["address"] == "127.0.0.8"
|
||||
|
||||
|
||||
async def test_dhcp_discovery_existing_config_entry(hass: HomeAssistant) -> None:
|
||||
"""Test dhcp discovery is aborted if there is an existing config entry."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
"info": MOCK_DEVICE2.get_device_info,
|
||||
},
|
||||
unique_id=MOCK_DEVICE2.uuid,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_dhcp_discovery(hass: HomeAssistant) -> None:
|
||||
"""Test we can setup a dhcp discovered device."""
|
||||
with _patch_discovery(), patch(
|
||||
"homeassistant.components.senseme.config_flow.async_get_device_by_ip_address",
|
||||
return_value=MOCK_DEVICE,
|
||||
), patch(
|
||||
"homeassistant.components.senseme.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert not result["errors"]
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"device": MOCK_UUID,
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result2["title"] == "Haiku Fan"
|
||||
assert result2["data"] == {
|
||||
"info": MOCK_DEVICE.get_device_info,
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_dhcp_discovery_cannot_connect(hass: HomeAssistant) -> None:
|
||||
"""Test we abort if we cannot cannot to a dhcp discovered device."""
|
||||
with _patch_discovery(), patch(
|
||||
"homeassistant.components.senseme.config_flow.async_get_device_by_ip_address",
|
||||
return_value=None,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
|
||||
async def test_dhcp_discovery_cannot_connect_no_uuid(hass: HomeAssistant) -> None:
|
||||
"""Test we abort if the discovered device has no uuid."""
|
||||
with _patch_discovery(), patch(
|
||||
"homeassistant.components.senseme.config_flow.async_get_device_by_ip_address",
|
||||
return_value=MOCK_DEVICE_NO_UUID,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
Loading…
x
Reference in New Issue
Block a user