diff --git a/homeassistant/components/adguard/.translations/en.json b/homeassistant/components/adguard/.translations/en.json index 6e3b5b58503..8bfb8516fd8 100644 --- a/homeassistant/components/adguard/.translations/en.json +++ b/homeassistant/components/adguard/.translations/en.json @@ -1,6 +1,8 @@ { "config": { "abort": { + "adguard_home_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}.", + "adguard_home_addon_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}. Please update your Hass.io AdGuard Home add-on.", "existing_instance_updated": "Updated existing configuration.", "single_instance_allowed": "Only a single configuration of AdGuard Home is allowed." }, diff --git a/homeassistant/components/adguard/__init__.py b/homeassistant/components/adguard/__init__.py index ba716ae0f9c..bb53d00aab8 100644 --- a/homeassistant/components/adguard/__init__.py +++ b/homeassistant/components/adguard/__init__.py @@ -1,8 +1,9 @@ """Support for AdGuard Home.""" +from distutils.version import LooseVersion import logging from typing import Any, Dict -from adguardhome import AdGuardHome, AdGuardHomeError +from adguardhome import AdGuardHome, AdGuardHomeConnectionError, AdGuardHomeError import voluptuous as vol from homeassistant.components.adguard.const import ( @@ -10,6 +11,7 @@ from homeassistant.components.adguard.const import ( DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERION, DOMAIN, + MIN_ADGUARD_HOME_VERSION, SERVICE_ADD_URL, SERVICE_DISABLE_URL, SERVICE_ENABLE_URL, @@ -27,6 +29,7 @@ from homeassistant.const import ( CONF_USERNAME, CONF_VERIFY_SSL, ) +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import Entity @@ -64,6 +67,17 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool hass.data.setdefault(DOMAIN, {})[DATA_ADGUARD_CLIENT] = adguard + try: + version = await adguard.version() + except AdGuardHomeConnectionError as exception: + raise ConfigEntryNotReady from exception + + if LooseVersion(MIN_ADGUARD_HOME_VERSION) > LooseVersion(version): + _LOGGER.error( + "This integration requires AdGuard Home v0.99.0 or higher to work correctly" + ) + raise ConfigEntryNotReady + for component in "sensor", "switch": hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, component) diff --git a/homeassistant/components/adguard/config_flow.py b/homeassistant/components/adguard/config_flow.py index 5a096aeceed..9f5645edb8d 100644 --- a/homeassistant/components/adguard/config_flow.py +++ b/homeassistant/components/adguard/config_flow.py @@ -1,11 +1,12 @@ """Config flow to configure the AdGuard Home integration.""" +from distutils.version import LooseVersion import logging from adguardhome import AdGuardHome, AdGuardHomeConnectionError import voluptuous as vol from homeassistant import config_entries -from homeassistant.components.adguard.const import DOMAIN +from homeassistant.components.adguard.const import DOMAIN, MIN_ADGUARD_HOME_VERSION from homeassistant.config_entries import ConfigFlow from homeassistant.const import ( CONF_HOST, @@ -83,11 +84,20 @@ class AdGuardHomeFlowHandler(ConfigFlow): ) try: - await adguard.version() + version = await adguard.version() except AdGuardHomeConnectionError: errors["base"] = "connection_error" return await self._show_setup_form(errors) + if LooseVersion(MIN_ADGUARD_HOME_VERSION) > LooseVersion(version): + return self.async_abort( + reason="adguard_home_outdated", + description_placeholders={ + "current_version": version, + "minimal_version": MIN_ADGUARD_HOME_VERSION, + }, + ) + return self.async_create_entry( title=user_input[CONF_HOST], data={ @@ -156,11 +166,20 @@ class AdGuardHomeFlowHandler(ConfigFlow): ) try: - await adguard.version() + version = await adguard.version() except AdGuardHomeConnectionError: errors["base"] = "connection_error" return await self._show_hassio_form(errors) + if LooseVersion(MIN_ADGUARD_HOME_VERSION) > LooseVersion(version): + return self.async_abort( + reason="adguard_home_addon_outdated", + description_placeholders={ + "current_version": version, + "minimal_version": MIN_ADGUARD_HOME_VERSION, + }, + ) + return self.async_create_entry( title=self._hassio_discovery["addon"], data={ diff --git a/homeassistant/components/adguard/const.py b/homeassistant/components/adguard/const.py index c77d76a70cf..eb12a9c163f 100644 --- a/homeassistant/components/adguard/const.py +++ b/homeassistant/components/adguard/const.py @@ -7,6 +7,8 @@ DATA_ADGUARD_VERION = "adguard_version" CONF_FORCE = "force" +MIN_ADGUARD_HOME_VERSION = "v0.99.0" + SERVICE_ADD_URL = "add_url" SERVICE_DISABLE_URL = "disable_url" SERVICE_ENABLE_URL = "enable_url" diff --git a/homeassistant/components/adguard/manifest.json b/homeassistant/components/adguard/manifest.json index f207e6dff09..45fd21f4fc8 100644 --- a/homeassistant/components/adguard/manifest.json +++ b/homeassistant/components/adguard/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/adguard", "requirements": [ - "adguardhome==0.2.1" + "adguardhome==0.3.0" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/adguard/strings.json b/homeassistant/components/adguard/strings.json index b3966bca820..d33ba2b397a 100644 --- a/homeassistant/components/adguard/strings.json +++ b/homeassistant/components/adguard/strings.json @@ -23,8 +23,10 @@ "connection_error": "Failed to connect." }, "abort": { - "single_instance_allowed": "Only a single configuration of AdGuard Home is allowed.", - "existing_instance_updated": "Updated existing configuration." + "adguard_home_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}.", + "adguard_home_addon_outdated": "This integration requires AdGuard Home {minimal_version} or higher, you have {current_version}. Please update your Hass.io AdGuard Home add-on.", + "existing_instance_updated": "Updated existing configuration.", + "single_instance_allowed": "Only a single configuration of AdGuard Home is allowed." } } -} +} \ No newline at end of file diff --git a/requirements_all.txt b/requirements_all.txt index d829377d8a2..d30d01f02c0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -115,7 +115,7 @@ adafruit-circuitpython-mcp230xx==1.1.2 adb-shell==0.0.7 # homeassistant.components.adguard -adguardhome==0.2.1 +adguardhome==0.3.0 # homeassistant.components.frontier_silicon afsapi==0.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cb0b56cb5ae..2a4fdf4eac7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -52,7 +52,7 @@ abodepy==0.16.6 adb-shell==0.0.7 # homeassistant.components.adguard -adguardhome==0.2.1 +adguardhome==0.3.0 # homeassistant.components.geonetnz_quakes aio_geojson_geonetnz_quakes==0.10 diff --git a/tests/components/adguard/test_config_flow.py b/tests/components/adguard/test_config_flow.py index ea5e5ad2276..dbda1e99a48 100644 --- a/tests/components/adguard/test_config_flow.py +++ b/tests/components/adguard/test_config_flow.py @@ -3,9 +3,9 @@ from unittest.mock import patch import aiohttp -from homeassistant import data_entry_flow, config_entries +from homeassistant import config_entries, data_entry_flow from homeassistant.components.adguard import config_flow -from homeassistant.components.adguard.const import DOMAIN +from homeassistant.components.adguard.const import DOMAIN, MIN_ADGUARD_HOME_VERSION from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, @@ -65,7 +65,7 @@ async def test_full_flow_implementation(hass, aioclient_mock): FIXTURE_USER_INPUT[CONF_HOST], FIXTURE_USER_INPUT[CONF_PORT], ), - json={"version": "1.0"}, + json={"version": "v0.99.0"}, headers={"Content-Type": "application/json"}, ) @@ -133,8 +133,19 @@ async def test_hassio_update_instance_not_running(hass): assert result["reason"] == "existing_instance_updated" -async def test_hassio_update_instance_running(hass): +async def test_hassio_update_instance_running(hass, aioclient_mock): """Test we only allow a single config flow.""" + aioclient_mock.get( + "http://mock-adguard-updated:3000/control/status", + json={"version": "v0.99.0"}, + headers={"Content-Type": "application/json"}, + ) + aioclient_mock.get( + "http://mock-adguard:3000/control/status", + json={"version": "v0.99.0"}, + headers={"Content-Type": "application/json"}, + ) + entry = MockConfigEntry( domain="adguard", data={ @@ -187,7 +198,7 @@ async def test_hassio_confirm(hass, aioclient_mock): """Test we can finish a config flow.""" aioclient_mock.get( "http://mock-adguard:3000/control/status", - json={"version": "1.0"}, + json={"version": "v0.99.0"}, headers={"Content-Type": "application/json"}, ) @@ -228,3 +239,54 @@ async def test_hassio_connection_error(hass, aioclient_mock): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "hassio_confirm" assert result["errors"] == {"base": "connection_error"} + + +async def test_outdated_adguard_version(hass, aioclient_mock): + """Test we show abort when connecting with unsupported AdGuard version.""" + aioclient_mock.get( + "{}://{}:{}/control/status".format( + "https" if FIXTURE_USER_INPUT[CONF_SSL] else "http", + FIXTURE_USER_INPUT[CONF_HOST], + FIXTURE_USER_INPUT[CONF_PORT], + ), + json={"version": "v0.98.0"}, + headers={"Content-Type": "application/json"}, + ) + + flow = config_flow.AdGuardHomeFlowHandler() + flow.hass = hass + result = await flow.async_step_user(user_input=None) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "user" + + result = await flow.async_step_user(user_input=FIXTURE_USER_INPUT) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "adguard_home_outdated" + assert result["description_placeholders"] == { + "current_version": "v0.98.0", + "minimal_version": MIN_ADGUARD_HOME_VERSION, + } + + +async def test_outdated_adguard_addon_version(hass, aioclient_mock): + """Test we show abort when connecting with unsupported AdGuard add-on version.""" + aioclient_mock.get( + "http://mock-adguard:3000/control/status", + json={"version": "v0.98.0"}, + headers={"Content-Type": "application/json"}, + ) + + result = await hass.config_entries.flow.async_init( + "adguard", + data={"addon": "AdGuard Home Addon", "host": "mock-adguard", "port": 3000}, + context={"source": "hassio"}, + ) + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "adguard_home_addon_outdated" + assert result["description_placeholders"] == { + "current_version": "v0.98.0", + "minimal_version": MIN_ADGUARD_HOME_VERSION, + }