mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add broadlink dhcp discovery (#48408)
This commit is contained in:
parent
fbc3f97097
commit
388815b81a
@ -13,6 +13,7 @@ from broadlink.exceptions import (
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries, data_entry_flow
|
from homeassistant import config_entries, data_entry_flow
|
||||||
|
from homeassistant.components.dhcp import IP_ADDRESS, MAC_ADDRESS
|
||||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_TIMEOUT, CONF_TYPE
|
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_TIMEOUT, CONF_TYPE
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ from .const import ( # pylint: disable=unused-import
|
|||||||
DOMAIN,
|
DOMAIN,
|
||||||
DOMAINS_AND_TYPES,
|
DOMAINS_AND_TYPES,
|
||||||
)
|
)
|
||||||
from .helpers import format_mac
|
from .helpers import format_mac, mac_address
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,6 +60,29 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
"host": device.host[0],
|
"host": device.host[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async def async_step_dhcp(self, dhcp_discovery):
|
||||||
|
"""Handle dhcp discovery."""
|
||||||
|
host = dhcp_discovery[IP_ADDRESS]
|
||||||
|
await self.async_set_unique_id(
|
||||||
|
format_mac(mac_address(dhcp_discovery[MAC_ADDRESS]))
|
||||||
|
)
|
||||||
|
self._abort_if_unique_id_configured(updates={CONF_HOST: host})
|
||||||
|
try:
|
||||||
|
hello = partial(blk.discover, discover_ip_address=host)
|
||||||
|
device = (await self.hass.async_add_executor_job(hello))[0]
|
||||||
|
except IndexError:
|
||||||
|
return self.async_abort(reason="cannot_connect")
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.ENETUNREACH:
|
||||||
|
return self.async_abort(reason="cannot_connect")
|
||||||
|
return self.async_abort(reason="invalid_host")
|
||||||
|
except Exception as ex: # pylint: disable=broad-except
|
||||||
|
_LOGGER.error("Failed to connect to the device at %s", host, exc_info=ex)
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
|
||||||
|
await self.async_set_device(device)
|
||||||
|
return await self.async_step_auth()
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
"""Handle a flow initiated by the user."""
|
"""Handle a flow initiated by the user."""
|
||||||
errors = {}
|
errors = {}
|
||||||
|
@ -4,5 +4,11 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/broadlink",
|
"documentation": "https://www.home-assistant.io/integrations/broadlink",
|
||||||
"requirements": ["broadlink==0.17.0"],
|
"requirements": ["broadlink==0.17.0"],
|
||||||
"codeowners": ["@danielhiversen", "@felipediel"],
|
"codeowners": ["@danielhiversen", "@felipediel"],
|
||||||
"config_flow": true
|
"config_flow": true,
|
||||||
|
"dhcp": [
|
||||||
|
{"macaddress": "34EA34*"},
|
||||||
|
{"macaddress": "24DFA7*"},
|
||||||
|
{"macaddress": "A043B0*"},
|
||||||
|
{"macaddress": "B4430D*"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,22 @@ DHCP = [
|
|||||||
"hostname": "blink*",
|
"hostname": "blink*",
|
||||||
"macaddress": "B85F98*"
|
"macaddress": "B85F98*"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"domain": "broadlink",
|
||||||
|
"macaddress": "34EA34*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "broadlink",
|
||||||
|
"macaddress": "24DFA7*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "broadlink",
|
||||||
|
"macaddress": "A043B0*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "broadlink",
|
||||||
|
"macaddress": "B4430D*"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"domain": "flume",
|
"domain": "flume",
|
||||||
"hostname": "flume-gw-*",
|
"hostname": "flume-gw-*",
|
||||||
|
@ -6,8 +6,9 @@ from unittest.mock import call, patch
|
|||||||
import broadlink.exceptions as blke
|
import broadlink.exceptions as blke
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries, setup
|
||||||
from homeassistant.components.broadlink.const import DOMAIN
|
from homeassistant.components.broadlink.const import DOMAIN
|
||||||
|
from homeassistant.components.dhcp import HOSTNAME, IP_ADDRESS, MAC_ADDRESS
|
||||||
|
|
||||||
from . import get_device
|
from . import get_device
|
||||||
|
|
||||||
@ -819,3 +820,143 @@ async def test_flow_reauth_valid_host(hass):
|
|||||||
assert mock_entry.data["host"] == device.host
|
assert mock_entry.data["host"] == device.host
|
||||||
assert mock_discover.call_count == 1
|
assert mock_discover.call_count == 1
|
||||||
assert mock_api.auth.call_count == 1
|
assert mock_api.auth.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_can_finish(hass):
|
||||||
|
"""Test DHCP discovery flow can finish right away."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
|
||||||
|
device = get_device("Living Room")
|
||||||
|
device.host = "1.2.3.4"
|
||||||
|
mock_api = device.get_mock_api()
|
||||||
|
|
||||||
|
with patch(DEVICE_DISCOVERY, return_value=[mock_api]):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "finish"
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result2["type"] == "create_entry"
|
||||||
|
assert result2["title"] == "Living Room"
|
||||||
|
assert result2["data"] == {
|
||||||
|
"host": "1.2.3.4",
|
||||||
|
"mac": "34ea34b43b5a",
|
||||||
|
"timeout": 10,
|
||||||
|
"type": 24374,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_fails_to_connect(hass):
|
||||||
|
"""Test DHCP discovery flow that fails to connect."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
with patch(DEVICE_DISCOVERY, side_effect=IndexError()):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "cannot_connect"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_unreachable(hass):
|
||||||
|
"""Test DHCP discovery flow that fails to connect."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
with patch(DEVICE_DISCOVERY, side_effect=OSError(errno.ENETUNREACH, None)):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "cannot_connect"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_connect_einval(hass):
|
||||||
|
"""Test DHCP discovery flow that fails to connect with EINVAL."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
with patch(DEVICE_DISCOVERY, side_effect=OSError(errno.EINVAL, None)):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "invalid_host"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_connect_unknown_error(hass):
|
||||||
|
"""Test DHCP discovery flow that fails to connect with an unknown error."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
with patch(DEVICE_DISCOVERY, side_effect=ValueError("Unknown failure")):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_already_exists(hass):
|
||||||
|
"""Test DHCP discovery flow that fails to connect."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
device = get_device("Living Room")
|
||||||
|
mock_entry = device.get_mock_entry()
|
||||||
|
mock_entry.add_to_hass(hass)
|
||||||
|
device.host = "1.2.3.4"
|
||||||
|
mock_api = device.get_mock_api()
|
||||||
|
|
||||||
|
with patch(DEVICE_DISCOVERY, return_value=[mock_api]):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": "dhcp"},
|
||||||
|
data={
|
||||||
|
HOSTNAME: "broadlink",
|
||||||
|
IP_ADDRESS: "1.2.3.4",
|
||||||
|
MAC_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user