mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Fix ElkM1 systems that do not use password authentication (#67194)
This commit is contained in:
parent
4dc6aab17e
commit
00c6e30988
@ -228,7 +228,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
_LOGGER.debug("Setting up elkm1 %s", conf["host"])
|
||||
|
||||
if not entry.unique_id or ":" not in entry.unique_id and is_ip_address(host):
|
||||
if (not entry.unique_id or ":" not in entry.unique_id) and is_ip_address(host):
|
||||
_LOGGER.debug(
|
||||
"Unique id for %s is missing during setup, trying to fill from discovery",
|
||||
host,
|
||||
)
|
||||
if device := await async_discover_device(hass, host):
|
||||
async_update_entry_from_discovery(hass, entry, device)
|
||||
|
||||
@ -276,7 +280,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
try:
|
||||
if not await async_wait_for_elk_to_sync(
|
||||
elk, LOGIN_TIMEOUT, SYNC_TIMEOUT, conf[CONF_HOST]
|
||||
elk, LOGIN_TIMEOUT, SYNC_TIMEOUT, bool(conf[CONF_USERNAME])
|
||||
):
|
||||
return False
|
||||
except asyncio.TimeoutError as exc:
|
||||
@ -327,7 +331,10 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
|
||||
async def async_wait_for_elk_to_sync(
|
||||
elk: elkm1.Elk, login_timeout: int, sync_timeout: int, conf_host: str
|
||||
elk: elkm1.Elk,
|
||||
login_timeout: int,
|
||||
sync_timeout: int,
|
||||
password_auth: bool,
|
||||
) -> bool:
|
||||
"""Wait until the elk has finished sync. Can fail login or timeout."""
|
||||
|
||||
@ -353,15 +360,21 @@ async def async_wait_for_elk_to_sync(
|
||||
success = True
|
||||
elk.add_handler("login", login_status)
|
||||
elk.add_handler("sync_complete", sync_complete)
|
||||
events = ((login_event, login_timeout), (sync_event, sync_timeout))
|
||||
events = []
|
||||
if password_auth:
|
||||
events.append(("login", login_event, login_timeout))
|
||||
events.append(("sync_complete", sync_event, sync_timeout))
|
||||
|
||||
for event, timeout in events:
|
||||
for name, event, timeout in events:
|
||||
_LOGGER.debug("Waiting for %s event for %s seconds", name, timeout)
|
||||
try:
|
||||
async with async_timeout.timeout(timeout):
|
||||
await event.wait()
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.debug("Timed out waiting for %s event", name)
|
||||
elk.disconnect()
|
||||
raise
|
||||
_LOGGER.debug("Received %s event", name)
|
||||
|
||||
return success
|
||||
|
||||
|
@ -24,6 +24,7 @@ from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.util.network import is_ip_address
|
||||
|
||||
from . import async_wait_for_elk_to_sync
|
||||
from .const import CONF_AUTO_CONFIGURE, DISCOVER_SCAN_TIMEOUT, DOMAIN, LOGIN_TIMEOUT
|
||||
@ -80,7 +81,9 @@ async def validate_input(data: dict[str, str], mac: str | None) -> dict[str, str
|
||||
)
|
||||
elk.connect()
|
||||
|
||||
if not await async_wait_for_elk_to_sync(elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT, url):
|
||||
if not await async_wait_for_elk_to_sync(
|
||||
elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT, bool(userid)
|
||||
):
|
||||
raise InvalidAuth
|
||||
|
||||
short_mac = _short_mac(mac) if mac else None
|
||||
@ -124,6 +127,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._discovered_device = ElkSystem(
|
||||
discovery_info.macaddress, discovery_info.ip, 0
|
||||
)
|
||||
_LOGGER.debug("Elk discovered from dhcp: %s", self._discovered_device)
|
||||
return await self._async_handle_discovery()
|
||||
|
||||
async def async_step_integration_discovery(
|
||||
@ -135,6 +139,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
discovery_info["ip_address"],
|
||||
discovery_info["port"],
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"Elk discovered from integration discovery: %s", self._discovered_device
|
||||
)
|
||||
return await self._async_handle_discovery()
|
||||
|
||||
async def _async_handle_discovery(self) -> FlowResult:
|
||||
@ -304,11 +311,22 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def async_step_import(self, user_input):
|
||||
"""Handle import."""
|
||||
if device := await async_discover_device(
|
||||
self.hass, urlparse(user_input[CONF_HOST]).hostname
|
||||
_LOGGER.debug("Elk is importing from yaml")
|
||||
url = _make_url_from_data(user_input)
|
||||
|
||||
if self._url_already_configured(url):
|
||||
return self.async_abort(reason="address_already_configured")
|
||||
|
||||
host = urlparse(url).hostname
|
||||
_LOGGER.debug(
|
||||
"Importing is trying to fill unique id from discovery for %s", host
|
||||
)
|
||||
if is_ip_address(host) and (
|
||||
device := await async_discover_device(self.hass, host)
|
||||
):
|
||||
await self.async_set_unique_id(dr.format_mac(device.mac_address))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return (await self._async_create_or_error(user_input, True))[1]
|
||||
|
||||
def _url_already_configured(self, url):
|
||||
|
@ -9,7 +9,7 @@ from homeassistant.const import ATTR_CODE, CONF_ZONE
|
||||
|
||||
DOMAIN = "elkm1"
|
||||
|
||||
LOGIN_TIMEOUT = 15
|
||||
LOGIN_TIMEOUT = 20
|
||||
|
||||
CONF_AUTO_CONFIGURE = "auto_configure"
|
||||
CONF_AREA = "area"
|
||||
|
@ -29,9 +29,11 @@ def async_update_entry_from_discovery(
|
||||
) -> bool:
|
||||
"""Update a config entry from a discovery."""
|
||||
if not entry.unique_id or ":" not in entry.unique_id:
|
||||
_LOGGER.debug("Adding unique id from discovery: %s", device)
|
||||
return hass.config_entries.async_update_entry(
|
||||
entry, unique_id=dr.format_mac(device.mac_address)
|
||||
)
|
||||
_LOGGER.debug("Unique id is already present from discovery: %s", device)
|
||||
return False
|
||||
|
||||
|
||||
|
@ -652,6 +652,50 @@ async def test_form_import_device_discovered(hass):
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_import_existing(hass):
|
||||
"""Test we abort on existing import."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: f"elks://{MOCK_IP_ADDRESS}"},
|
||||
unique_id="cc:cc:cc:cc:cc:cc",
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_IMPORT},
|
||||
data={
|
||||
"host": f"elks://{MOCK_IP_ADDRESS}",
|
||||
"username": "friend",
|
||||
"password": "love",
|
||||
"temperature_unit": "C",
|
||||
"auto_configure": False,
|
||||
"keypad": {
|
||||
"enabled": True,
|
||||
"exclude": [],
|
||||
"include": [[1, 1], [2, 2], [3, 3]],
|
||||
},
|
||||
"output": {"enabled": False, "exclude": [], "include": []},
|
||||
"counter": {"enabled": False, "exclude": [], "include": []},
|
||||
"plc": {"enabled": False, "exclude": [], "include": []},
|
||||
"prefix": "ohana",
|
||||
"setting": {"enabled": False, "exclude": [], "include": []},
|
||||
"area": {"enabled": False, "exclude": [], "include": []},
|
||||
"task": {"enabled": False, "exclude": [], "include": []},
|
||||
"thermostat": {"enabled": False, "exclude": [], "include": []},
|
||||
"zone": {
|
||||
"enabled": True,
|
||||
"exclude": [[15, 15], [28, 208]],
|
||||
"include": [],
|
||||
},
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "address_already_configured"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source, data",
|
||||
[
|
||||
|
Loading…
x
Reference in New Issue
Block a user