Only update unifiprotect ips from discovery when the console is offline (#73411)
parent
9ae713f128
commit
9159db4b4a
|
@ -8,6 +8,7 @@ from typing import Any
|
||||||
from aiohttp import CookieJar
|
from aiohttp import CookieJar
|
||||||
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
|
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
|
||||||
from pyunifiprotect.data import NVR
|
from pyunifiprotect.data import NVR
|
||||||
|
from unifi_discovery import async_console_is_alive
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
@ -22,7 +23,10 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
from homeassistant.helpers.aiohttp_client import (
|
||||||
|
async_create_clientsession,
|
||||||
|
async_get_clientsession,
|
||||||
|
)
|
||||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||||
from homeassistant.loader import async_get_integration
|
from homeassistant.loader import async_get_integration
|
||||||
from homeassistant.util.network import is_ip_address
|
from homeassistant.util.network import is_ip_address
|
||||||
|
@ -37,11 +41,17 @@ from .const import (
|
||||||
MIN_REQUIRED_PROTECT_V,
|
MIN_REQUIRED_PROTECT_V,
|
||||||
OUTDATED_LOG_MESSAGE,
|
OUTDATED_LOG_MESSAGE,
|
||||||
)
|
)
|
||||||
|
from .data import async_last_update_was_successful
|
||||||
from .discovery import async_start_discovery
|
from .discovery import async_start_discovery
|
||||||
from .utils import _async_resolve, _async_short_mac, _async_unifi_mac_from_hass
|
from .utils import _async_resolve, _async_short_mac, _async_unifi_mac_from_hass
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ENTRY_FAILURE_STATES = (
|
||||||
|
config_entries.ConfigEntryState.SETUP_ERROR,
|
||||||
|
config_entries.ConfigEntryState.SETUP_RETRY,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_local_user_documentation_url(hass: HomeAssistant) -> str:
|
async def async_local_user_documentation_url(hass: HomeAssistant) -> str:
|
||||||
"""Get the documentation url for creating a local user."""
|
"""Get the documentation url for creating a local user."""
|
||||||
|
@ -54,6 +64,25 @@ def _host_is_direct_connect(host: str) -> bool:
|
||||||
return host.endswith(".ui.direct")
|
return host.endswith(".ui.direct")
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_console_is_offline(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: config_entries.ConfigEntry,
|
||||||
|
) -> bool:
|
||||||
|
"""Check if a console is offline.
|
||||||
|
|
||||||
|
We define offline by the config entry
|
||||||
|
is in a failure/retry state or the updates
|
||||||
|
are failing and the console is unreachable
|
||||||
|
since protect may be updating.
|
||||||
|
"""
|
||||||
|
return bool(
|
||||||
|
entry.state in ENTRY_FAILURE_STATES
|
||||||
|
or not async_last_update_was_successful(hass, entry)
|
||||||
|
) and not await async_console_is_alive(
|
||||||
|
async_get_clientsession(hass, verify_ssl=False), entry.data[CONF_HOST]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a UniFi Protect config flow."""
|
"""Handle a UniFi Protect config flow."""
|
||||||
|
|
||||||
|
@ -111,6 +140,7 @@ class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
not entry_has_direct_connect
|
not entry_has_direct_connect
|
||||||
and is_ip_address(entry_host)
|
and is_ip_address(entry_host)
|
||||||
and entry_host != source_ip
|
and entry_host != source_ip
|
||||||
|
and await _async_console_is_offline(self.hass, entry)
|
||||||
):
|
):
|
||||||
new_host = source_ip
|
new_host = source_ip
|
||||||
if new_host:
|
if new_host:
|
||||||
|
|
|
@ -26,6 +26,16 @@ from .utils import async_get_adoptable_devices_by_type, async_get_devices
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_last_update_was_successful(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Check if the last update was successful for a config entry."""
|
||||||
|
return bool(
|
||||||
|
DOMAIN in hass.data
|
||||||
|
and entry.entry_id in hass.data[DOMAIN]
|
||||||
|
and hass.data[DOMAIN][entry.entry_id].last_update_success
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProtectData:
|
class ProtectData:
|
||||||
"""Coordinate updates."""
|
"""Coordinate updates."""
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "UniFi Protect",
|
"name": "UniFi Protect",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/unifiprotect",
|
"documentation": "https://www.home-assistant.io/integrations/unifiprotect",
|
||||||
"requirements": ["pyunifiprotect==3.9.2", "unifi-discovery==1.1.3"],
|
"requirements": ["pyunifiprotect==3.9.2", "unifi-discovery==1.1.4"],
|
||||||
"dependencies": ["http"],
|
"dependencies": ["http"],
|
||||||
"codeowners": ["@briis", "@AngellusMortis", "@bdraco"],
|
"codeowners": ["@briis", "@AngellusMortis", "@bdraco"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
|
|
|
@ -2355,7 +2355,7 @@ twitchAPI==2.5.2
|
||||||
uasiren==0.0.1
|
uasiren==0.0.1
|
||||||
|
|
||||||
# homeassistant.components.unifiprotect
|
# homeassistant.components.unifiprotect
|
||||||
unifi-discovery==1.1.3
|
unifi-discovery==1.1.4
|
||||||
|
|
||||||
# homeassistant.components.unifiled
|
# homeassistant.components.unifiled
|
||||||
unifiled==0.11
|
unifiled==0.11
|
||||||
|
|
|
@ -1552,7 +1552,7 @@ twitchAPI==2.5.2
|
||||||
uasiren==0.0.1
|
uasiren==0.0.1
|
||||||
|
|
||||||
# homeassistant.components.unifiprotect
|
# homeassistant.components.unifiprotect
|
||||||
unifi-discovery==1.1.3
|
unifi-discovery==1.1.4
|
||||||
|
|
||||||
# homeassistant.components.upb
|
# homeassistant.components.upb
|
||||||
upb_lib==0.4.12
|
upb_lib==0.4.12
|
||||||
|
|
|
@ -402,7 +402,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_usin
|
||||||
)
|
)
|
||||||
mock_config.add_to_hass(hass)
|
mock_config.add_to_hass(hass)
|
||||||
|
|
||||||
with _patch_discovery():
|
with _patch_discovery(), patch(
|
||||||
|
"homeassistant.components.unifiprotect.config_flow.async_console_is_alive",
|
||||||
|
return_value=False,
|
||||||
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
|
context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
|
||||||
|
@ -415,6 +418,41 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_usin
|
||||||
assert mock_config.data[CONF_HOST] == "127.0.0.1"
|
assert mock_config.data[CONF_HOST] == "127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovered_by_unifi_discovery_does_not_update_ip_when_console_is_still_online(
|
||||||
|
hass: HomeAssistant, mock_nvr: NVR
|
||||||
|
) -> None:
|
||||||
|
"""Test a discovery from unifi-discovery does not update the ip unless the console at the old ip is offline."""
|
||||||
|
mock_config = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
"host": "1.2.2.2",
|
||||||
|
"username": "test-username",
|
||||||
|
"password": "test-password",
|
||||||
|
"id": "UnifiProtect",
|
||||||
|
"port": 443,
|
||||||
|
"verify_ssl": False,
|
||||||
|
},
|
||||||
|
version=2,
|
||||||
|
unique_id=DEVICE_MAC_ADDRESS.replace(":", "").upper(),
|
||||||
|
)
|
||||||
|
mock_config.add_to_hass(hass)
|
||||||
|
|
||||||
|
with _patch_discovery(), patch(
|
||||||
|
"homeassistant.components.unifiprotect.config_flow.async_console_is_alive",
|
||||||
|
return_value=True,
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
|
||||||
|
data=UNIFI_DISCOVERY_DICT,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
assert mock_config.data[CONF_HOST] == "1.2.2.2"
|
||||||
|
|
||||||
|
|
||||||
async def test_discovered_host_not_updated_if_existing_is_a_hostname(
|
async def test_discovered_host_not_updated_if_existing_is_a_hostname(
|
||||||
hass: HomeAssistant, mock_nvr: NVR
|
hass: HomeAssistant, mock_nvr: NVR
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
Loading…
Reference in New Issue