diff --git a/homeassistant/components/adguard/__init__.py b/homeassistant/components/adguard/__init__.py index 0f10d20ec59..be465b1e1a7 100644 --- a/homeassistant/components/adguard/__init__.py +++ b/homeassistant/components/adguard/__init__.py @@ -10,7 +10,7 @@ import voluptuous as vol from homeassistant.components.adguard.const import ( CONF_FORCE, DATA_ADGUARD_CLIENT, - DATA_ADGUARD_VERION, + DATA_ADGUARD_VERSION, DOMAIN, SERVICE_ADD_URL, SERVICE_DISABLE_URL, @@ -61,16 +61,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: session=session, ) - hass.data.setdefault(DOMAIN, {})[DATA_ADGUARD_CLIENT] = adguard + hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {DATA_ADGUARD_CLIENT: adguard} try: await adguard.version() except AdGuardHomeConnectionError as exception: raise ConfigEntryNotReady from exception - for platform in PLATFORMS: + for component in PLATFORMS: hass.async_create_task( - hass.config_entries.async_forward_entry_setup(entry, platform) + hass.config_entries.async_forward_entry_setup(entry, component) ) async def add_url(call) -> None: @@ -126,8 +126,8 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.services.async_remove(DOMAIN, SERVICE_DISABLE_URL) hass.services.async_remove(DOMAIN, SERVICE_REFRESH) - for platform in PLATFORMS: - await hass.config_entries.async_forward_entry_unload(entry, platform) + for component in PLATFORMS: + await hass.config_entries.async_forward_entry_unload(entry, component) del hass.data[DOMAIN] @@ -138,13 +138,19 @@ class AdGuardHomeEntity(Entity): """Defines a base AdGuard Home entity.""" def __init__( - self, adguard, name: str, icon: str, enabled_default: bool = True + self, + adguard: AdGuardHome, + entry: ConfigEntry, + name: str, + icon: str, + enabled_default: bool = True, ) -> None: """Initialize the AdGuard Home entity.""" self._available = True self._enabled_default = enabled_default self._icon = icon self._name = name + self._entry = entry self.adguard = adguard @property @@ -200,6 +206,8 @@ class AdGuardHomeDeviceEntity(AdGuardHomeEntity): }, "name": "AdGuard Home", "manufacturer": "AdGuard Team", - "sw_version": self.hass.data[DOMAIN].get(DATA_ADGUARD_VERION), + "sw_version": self.hass.data[DOMAIN][self._entry.entry_id].get( + DATA_ADGUARD_VERSION + ), "entry_type": "service", } diff --git a/homeassistant/components/adguard/config_flow.py b/homeassistant/components/adguard/config_flow.py index d5ec79d788f..d8e657dfc76 100644 --- a/homeassistant/components/adguard/config_flow.py +++ b/homeassistant/components/adguard/config_flow.py @@ -63,12 +63,17 @@ class AdGuardHomeFlowHandler(ConfigFlow, domain=DOMAIN): self, user_input: dict[str, Any] | None = None ) -> dict[str, Any]: """Handle a flow initiated by the user.""" - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - if user_input is None: return await self._show_setup_form(user_input) + entries = self._async_current_entries() + for entry in entries: + if ( + entry.data[CONF_HOST] == user_input[CONF_HOST] + and entry.data[CONF_PORT] == user_input[CONF_PORT] + ): + return self.async_abort(reason="single_instance_allowed") + errors = {} session = async_get_clientsession(self.hass, user_input[CONF_VERIFY_SSL]) diff --git a/homeassistant/components/adguard/const.py b/homeassistant/components/adguard/const.py index c77d76a70cf..8bfa5b49fc6 100644 --- a/homeassistant/components/adguard/const.py +++ b/homeassistant/components/adguard/const.py @@ -3,7 +3,7 @@ DOMAIN = "adguard" DATA_ADGUARD_CLIENT = "adguard_client" -DATA_ADGUARD_VERION = "adguard_version" +DATA_ADGUARD_VERSION = "adguard_version" CONF_FORCE = "force" diff --git a/homeassistant/components/adguard/sensor.py b/homeassistant/components/adguard/sensor.py index dd0400b6592..012df197684 100644 --- a/homeassistant/components/adguard/sensor.py +++ b/homeassistant/components/adguard/sensor.py @@ -14,7 +14,7 @@ from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity import Entity from . import AdGuardHomeDeviceEntity -from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERION, DOMAIN +from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERSION, DOMAIN SCAN_INTERVAL = timedelta(seconds=300) PARALLEL_UPDATES = 4 @@ -26,24 +26,24 @@ async def async_setup_entry( async_add_entities: Callable[[list[Entity], bool], None], ) -> None: """Set up AdGuard Home sensor based on a config entry.""" - adguard = hass.data[DOMAIN][DATA_ADGUARD_CLIENT] + adguard = hass.data[DOMAIN][entry.entry_id][DATA_ADGUARD_CLIENT] try: version = await adguard.version() except AdGuardHomeConnectionError as exception: raise PlatformNotReady from exception - hass.data[DOMAIN][DATA_ADGUARD_VERION] = version + hass.data[DOMAIN][entry.entry_id][DATA_ADGUARD_VERSION] = version sensors = [ - AdGuardHomeDNSQueriesSensor(adguard), - AdGuardHomeBlockedFilteringSensor(adguard), - AdGuardHomePercentageBlockedSensor(adguard), - AdGuardHomeReplacedParentalSensor(adguard), - AdGuardHomeReplacedSafeBrowsingSensor(adguard), - AdGuardHomeReplacedSafeSearchSensor(adguard), - AdGuardHomeAverageProcessingTimeSensor(adguard), - AdGuardHomeRulesCountSensor(adguard), + AdGuardHomeDNSQueriesSensor(adguard, entry), + AdGuardHomeBlockedFilteringSensor(adguard, entry), + AdGuardHomePercentageBlockedSensor(adguard, entry), + AdGuardHomeReplacedParentalSensor(adguard, entry), + AdGuardHomeReplacedSafeBrowsingSensor(adguard, entry), + AdGuardHomeReplacedSafeSearchSensor(adguard, entry), + AdGuardHomeAverageProcessingTimeSensor(adguard, entry), + AdGuardHomeRulesCountSensor(adguard, entry), ] async_add_entities(sensors, True) @@ -55,6 +55,7 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity, SensorEntity): def __init__( self, adguard: AdGuardHome, + entry: ConfigEntry, name: str, icon: str, measurement: str, @@ -66,7 +67,7 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity, SensorEntity): self._unit_of_measurement = unit_of_measurement self.measurement = measurement - super().__init__(adguard, name, icon, enabled_default) + super().__init__(adguard, entry, name, icon, enabled_default) @property def unique_id(self) -> str: @@ -95,10 +96,15 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity, SensorEntity): class AdGuardHomeDNSQueriesSensor(AdGuardHomeSensor): """Defines a AdGuard Home DNS Queries sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( - adguard, "AdGuard DNS Queries", "mdi:magnify", "dns_queries", "queries" + adguard, + entry, + "AdGuard DNS Queries", + "mdi:magnify", + "dns_queries", + "queries", ) async def _adguard_update(self) -> None: @@ -109,10 +115,11 @@ class AdGuardHomeDNSQueriesSensor(AdGuardHomeSensor): class AdGuardHomeBlockedFilteringSensor(AdGuardHomeSensor): """Defines a AdGuard Home blocked by filtering sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard DNS Queries Blocked", "mdi:magnify-close", "blocked_filtering", @@ -128,10 +135,11 @@ class AdGuardHomeBlockedFilteringSensor(AdGuardHomeSensor): class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor): """Defines a AdGuard Home blocked percentage sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard DNS Queries Blocked Ratio", "mdi:magnify-close", "blocked_percentage", @@ -147,10 +155,11 @@ class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor): class AdGuardHomeReplacedParentalSensor(AdGuardHomeSensor): """Defines a AdGuard Home replaced by parental control sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard Parental Control Blocked", "mdi:human-male-girl", "blocked_parental", @@ -165,10 +174,11 @@ class AdGuardHomeReplacedParentalSensor(AdGuardHomeSensor): class AdGuardHomeReplacedSafeBrowsingSensor(AdGuardHomeSensor): """Defines a AdGuard Home replaced by safe browsing sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard Safe Browsing Blocked", "mdi:shield-half-full", "blocked_safebrowsing", @@ -183,10 +193,11 @@ class AdGuardHomeReplacedSafeBrowsingSensor(AdGuardHomeSensor): class AdGuardHomeReplacedSafeSearchSensor(AdGuardHomeSensor): """Defines a AdGuard Home replaced by safe search sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard Safe Searches Enforced", "mdi:shield-search", "enforced_safesearch", @@ -201,10 +212,11 @@ class AdGuardHomeReplacedSafeSearchSensor(AdGuardHomeSensor): class AdGuardHomeAverageProcessingTimeSensor(AdGuardHomeSensor): """Defines a AdGuard Home average processing time sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard Average Processing Speed", "mdi:speedometer", "average_speed", @@ -220,10 +232,11 @@ class AdGuardHomeAverageProcessingTimeSensor(AdGuardHomeSensor): class AdGuardHomeRulesCountSensor(AdGuardHomeSensor): """Defines a AdGuard Home rules count sensor.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry): """Initialize AdGuard Home sensor.""" super().__init__( adguard, + entry, "AdGuard Rules Count", "mdi:counter", "rules_count", diff --git a/homeassistant/components/adguard/switch.py b/homeassistant/components/adguard/switch.py index 0b127a280cf..22b4e8319f3 100644 --- a/homeassistant/components/adguard/switch.py +++ b/homeassistant/components/adguard/switch.py @@ -14,7 +14,7 @@ from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity import Entity from . import AdGuardHomeDeviceEntity -from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERION, DOMAIN +from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERSION, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -28,22 +28,22 @@ async def async_setup_entry( async_add_entities: Callable[[list[Entity], bool], None], ) -> None: """Set up AdGuard Home switch based on a config entry.""" - adguard = hass.data[DOMAIN][DATA_ADGUARD_CLIENT] + adguard = hass.data[DOMAIN][entry.entry_id][DATA_ADGUARD_CLIENT] try: version = await adguard.version() except AdGuardHomeConnectionError as exception: raise PlatformNotReady from exception - hass.data[DOMAIN][DATA_ADGUARD_VERION] = version + hass.data[DOMAIN][entry.entry_id][DATA_ADGUARD_VERSION] = version switches = [ - AdGuardHomeProtectionSwitch(adguard), - AdGuardHomeFilteringSwitch(adguard), - AdGuardHomeParentalSwitch(adguard), - AdGuardHomeSafeBrowsingSwitch(adguard), - AdGuardHomeSafeSearchSwitch(adguard), - AdGuardHomeQueryLogSwitch(adguard), + AdGuardHomeProtectionSwitch(adguard, entry), + AdGuardHomeFilteringSwitch(adguard, entry), + AdGuardHomeParentalSwitch(adguard, entry), + AdGuardHomeSafeBrowsingSwitch(adguard, entry), + AdGuardHomeSafeSearchSwitch(adguard, entry), + AdGuardHomeQueryLogSwitch(adguard, entry), ] async_add_entities(switches, True) @@ -54,6 +54,7 @@ class AdGuardHomeSwitch(AdGuardHomeDeviceEntity, SwitchEntity): def __init__( self, adguard: AdGuardHome, + entry: ConfigEntry, name: str, icon: str, key: str, @@ -62,7 +63,7 @@ class AdGuardHomeSwitch(AdGuardHomeDeviceEntity, SwitchEntity): """Initialize AdGuard Home switch.""" self._state = False self._key = key - super().__init__(adguard, name, icon, enabled_default) + super().__init__(adguard, entry, name, icon, enabled_default) @property def unique_id(self) -> str: @@ -104,10 +105,10 @@ class AdGuardHomeSwitch(AdGuardHomeDeviceEntity, SwitchEntity): class AdGuardHomeProtectionSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home protection switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" super().__init__( - adguard, "AdGuard Protection", "mdi:shield-check", "protection" + adguard, entry, "AdGuard Protection", "mdi:shield-check", "protection" ) async def _adguard_turn_off(self) -> None: @@ -126,10 +127,10 @@ class AdGuardHomeProtectionSwitch(AdGuardHomeSwitch): class AdGuardHomeParentalSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home parental control switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" super().__init__( - adguard, "AdGuard Parental Control", "mdi:shield-check", "parental" + adguard, entry, "AdGuard Parental Control", "mdi:shield-check", "parental" ) async def _adguard_turn_off(self) -> None: @@ -148,10 +149,10 @@ class AdGuardHomeParentalSwitch(AdGuardHomeSwitch): class AdGuardHomeSafeSearchSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home safe search switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" super().__init__( - adguard, "AdGuard Safe Search", "mdi:shield-check", "safesearch" + adguard, entry, "AdGuard Safe Search", "mdi:shield-check", "safesearch" ) async def _adguard_turn_off(self) -> None: @@ -170,10 +171,10 @@ class AdGuardHomeSafeSearchSwitch(AdGuardHomeSwitch): class AdGuardHomeSafeBrowsingSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home safe search switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" super().__init__( - adguard, "AdGuard Safe Browsing", "mdi:shield-check", "safebrowsing" + adguard, entry, "AdGuard Safe Browsing", "mdi:shield-check", "safebrowsing" ) async def _adguard_turn_off(self) -> None: @@ -192,9 +193,11 @@ class AdGuardHomeSafeBrowsingSwitch(AdGuardHomeSwitch): class AdGuardHomeFilteringSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home filtering switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" - super().__init__(adguard, "AdGuard Filtering", "mdi:shield-check", "filtering") + super().__init__( + adguard, entry, "AdGuard Filtering", "mdi:shield-check", "filtering" + ) async def _adguard_turn_off(self) -> None: """Turn off the switch.""" @@ -212,10 +215,11 @@ class AdGuardHomeFilteringSwitch(AdGuardHomeSwitch): class AdGuardHomeQueryLogSwitch(AdGuardHomeSwitch): """Defines a AdGuard Home query log switch.""" - def __init__(self, adguard: AdGuardHome) -> None: + def __init__(self, adguard: AdGuardHome, entry: ConfigEntry) -> None: """Initialize AdGuard Home switch.""" super().__init__( adguard, + entry, "AdGuard Query Log", "mdi:shield-check", "querylog", diff --git a/tests/components/adguard/test_config_flow.py b/tests/components/adguard/test_config_flow.py index 94760cade9f..0923883274b 100644 --- a/tests/components/adguard/test_config_flow.py +++ b/tests/components/adguard/test_config_flow.py @@ -92,10 +92,14 @@ async def test_full_flow_implementation( async def test_integration_already_exists(hass: HomeAssistant) -> None: """Test we only allow a single config flow.""" - MockConfigEntry(domain=DOMAIN).add_to_hass(hass) + MockConfigEntry( + domain=DOMAIN, data={"host": "mock-adguard", "port": "3000"} + ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": "user"} + DOMAIN, + data={"host": "mock-adguard", "port": "3000"}, + context={"source": "user"}, ) assert result["type"] == "abort" assert result["reason"] == "single_instance_allowed" @@ -104,11 +108,11 @@ async def test_integration_already_exists(hass: HomeAssistant) -> None: async def test_hassio_single_instance(hass: HomeAssistant) -> None: """Test we only allow a single config flow.""" MockConfigEntry( - domain="adguard", data={"host": "mock-adguard", "port": "3000"} + domain=DOMAIN, data={"host": "mock-adguard", "port": "3000"} ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( - "adguard", + DOMAIN, data={"addon": "AdGuard Home Addon", "host": "mock-adguard", "port": "3000"}, context={"source": "hassio"}, ) @@ -119,13 +123,13 @@ async def test_hassio_single_instance(hass: HomeAssistant) -> None: async def test_hassio_update_instance_not_running(hass: HomeAssistant) -> None: """Test we only allow a single config flow.""" entry = MockConfigEntry( - domain="adguard", data={"host": "mock-adguard", "port": "3000"} + domain=DOMAIN, data={"host": "mock-adguard", "port": "3000"} ) entry.add_to_hass(hass) assert entry.state == config_entries.ENTRY_STATE_NOT_LOADED result = await hass.config_entries.flow.async_init( - "adguard", + DOMAIN, data={ "addon": "AdGuard Home Addon", "host": "mock-adguard-updated", @@ -153,7 +157,7 @@ async def test_hassio_update_instance_running( ) entry = MockConfigEntry( - domain="adguard", + domain=DOMAIN, data={ "host": "mock-adguard", "port": "3000", @@ -184,7 +188,7 @@ async def test_hassio_update_instance_running( return_value=True, ) as mock_load: result = await hass.config_entries.flow.async_init( - "adguard", + DOMAIN, data={ "addon": "AdGuard Home Addon", "host": "mock-adguard-updated", @@ -211,7 +215,7 @@ async def test_hassio_confirm( ) result = await hass.config_entries.flow.async_init( - "adguard", + DOMAIN, data={"addon": "AdGuard Home Addon", "host": "mock-adguard", "port": 3000}, context={"source": "hassio"}, ) @@ -239,7 +243,7 @@ async def test_hassio_connection_error( ) result = await hass.config_entries.flow.async_init( - "adguard", + DOMAIN, data={"addon": "AdGuard Home Addon", "host": "mock-adguard", "port": 3000}, context={"source": "hassio"}, )