From 23fb4b50c91b308f83751aa27cef714d435480e2 Mon Sep 17 00:00:00 2001
From: Jordi <Jordi1990@users.noreply.github.com>
Date: Sat, 17 Aug 2024 20:45:24 +0200
Subject: [PATCH] Add brand selection to support additional brands who use the
 same API for AquaCell integration (#121817)

* Support harvey brand

* Update tests

* Moved the brand selection step to the same step as credentials

* Update tests/components/aquacell/test_init.py

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
---
 homeassistant/components/aquacell/__init__.py    |  6 +++++-
 homeassistant/components/aquacell/config_flow.py | 16 +++++++++++++---
 homeassistant/components/aquacell/const.py       |  1 +
 homeassistant/components/aquacell/manifest.json  |  2 +-
 homeassistant/components/aquacell/strings.json   |  3 ++-
 homeassistant/generated/integrations.json        |  2 +-
 tests/components/aquacell/__init__.py            | 12 ++++++++++++
 tests/components/aquacell/conftest.py            | 16 +++++++++++++++-
 tests/components/aquacell/test_config_flow.py    | 10 +++++++++-
 tests/components/aquacell/test_init.py           | 11 +++++++++++
 10 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/homeassistant/components/aquacell/__init__.py b/homeassistant/components/aquacell/__init__.py
index 98cf5d7f0f0..e44c0f00fa8 100644
--- a/homeassistant/components/aquacell/__init__.py
+++ b/homeassistant/components/aquacell/__init__.py
@@ -3,12 +3,14 @@
 from __future__ import annotations
 
 from aioaquacell import AquacellApi
+from aioaquacell.const import Brand
 
 from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import Platform
 from homeassistant.core import HomeAssistant
 from homeassistant.helpers.aiohttp_client import async_get_clientsession
 
+from .const import CONF_BRAND
 from .coordinator import AquacellCoordinator
 
 PLATFORMS = [Platform.SENSOR]
@@ -20,7 +22,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: AquacellConfigEntry) ->
     """Set up Aquacell from a config entry."""
     session = async_get_clientsession(hass)
 
-    aquacell_api = AquacellApi(session)
+    brand = entry.data.get(CONF_BRAND, Brand.AQUACELL)
+
+    aquacell_api = AquacellApi(session, brand)
 
     coordinator = AquacellCoordinator(hass, aquacell_api)
 
diff --git a/homeassistant/components/aquacell/config_flow.py b/homeassistant/components/aquacell/config_flow.py
index a9c749e9e2d..332cd16e749 100644
--- a/homeassistant/components/aquacell/config_flow.py
+++ b/homeassistant/components/aquacell/config_flow.py
@@ -7,18 +7,27 @@ import logging
 from typing import Any
 
 from aioaquacell import ApiException, AquacellApi, AuthenticationFailed
+from aioaquacell.const import SUPPORTED_BRANDS, Brand
 import voluptuous as vol
 
 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
 from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
 from homeassistant.helpers.aiohttp_client import async_get_clientsession
 
-from .const import CONF_REFRESH_TOKEN, CONF_REFRESH_TOKEN_CREATION_TIME, DOMAIN
+from .const import (
+    CONF_BRAND,
+    CONF_REFRESH_TOKEN,
+    CONF_REFRESH_TOKEN_CREATION_TIME,
+    DOMAIN,
+)
 
 _LOGGER = logging.getLogger(__name__)
 
 DATA_SCHEMA = vol.Schema(
     {
+        vol.Required(CONF_BRAND, default=Brand.AQUACELL): vol.In(
+            {key: brand.name for key, brand in SUPPORTED_BRANDS.items()}
+        ),
         vol.Required(CONF_EMAIL): str,
         vol.Required(CONF_PASSWORD): str,
     }
@@ -33,7 +42,7 @@ class AquaCellConfigFlow(ConfigFlow, domain=DOMAIN):
     async def async_step_user(
         self, user_input: dict[str, Any] | None = None
     ) -> ConfigFlowResult:
-        """Handle the initial step."""
+        """Handle the cloud logon step."""
         errors: dict[str, str] = {}
         if user_input is not None:
             await self.async_set_unique_id(
@@ -42,7 +51,7 @@ class AquaCellConfigFlow(ConfigFlow, domain=DOMAIN):
             self._abort_if_unique_id_configured()
 
             session = async_get_clientsession(self.hass)
-            api = AquacellApi(session)
+            api = AquacellApi(session, user_input[CONF_BRAND])
             try:
                 refresh_token = await api.authenticate(
                     user_input[CONF_EMAIL], user_input[CONF_PASSWORD]
@@ -59,6 +68,7 @@ class AquaCellConfigFlow(ConfigFlow, domain=DOMAIN):
                     title=user_input[CONF_EMAIL],
                     data={
                         **user_input,
+                        CONF_BRAND: user_input[CONF_BRAND],
                         CONF_REFRESH_TOKEN: refresh_token,
                         CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(),
                     },
diff --git a/homeassistant/components/aquacell/const.py b/homeassistant/components/aquacell/const.py
index 96568d2286b..818c96fc53a 100644
--- a/homeassistant/components/aquacell/const.py
+++ b/homeassistant/components/aquacell/const.py
@@ -5,6 +5,7 @@ from datetime import timedelta
 DOMAIN = "aquacell"
 DATA_AQUACELL = "DATA_AQUACELL"
 
+CONF_BRAND = "brand"
 CONF_REFRESH_TOKEN = "refresh_token"
 CONF_REFRESH_TOKEN_CREATION_TIME = "refresh_token_creation_time"
 
diff --git a/homeassistant/components/aquacell/manifest.json b/homeassistant/components/aquacell/manifest.json
index de4a9986d6e..2d8b80f4488 100644
--- a/homeassistant/components/aquacell/manifest.json
+++ b/homeassistant/components/aquacell/manifest.json
@@ -1,6 +1,6 @@
 {
   "domain": "aquacell",
-  "name": "Aquacell",
+  "name": "AquaCell",
   "codeowners": ["@Jordi1990"],
   "config_flow": true,
   "dependencies": ["http", "network"],
diff --git a/homeassistant/components/aquacell/strings.json b/homeassistant/components/aquacell/strings.json
index 32b6bba943a..53304d04804 100644
--- a/homeassistant/components/aquacell/strings.json
+++ b/homeassistant/components/aquacell/strings.json
@@ -2,8 +2,9 @@
   "config": {
     "step": {
       "user": {
-        "description": "Fill in your Aquacell mobile app credentials",
+        "description": "Select the brand of the softener and fill in your softener mobile app credentials",
         "data": {
+          "brand": "Brand",
           "email": "[%key:common::config_flow::data::email%]",
           "password": "[%key:common::config_flow::data::password%]"
         }
diff --git a/homeassistant/generated/integrations.json b/homeassistant/generated/integrations.json
index 7df27aa5e68..a61e58d80d4 100644
--- a/homeassistant/generated/integrations.json
+++ b/homeassistant/generated/integrations.json
@@ -414,7 +414,7 @@
       "iot_class": "local_polling"
     },
     "aquacell": {
-      "name": "Aquacell",
+      "name": "AquaCell",
       "integration_type": "device",
       "config_flow": true,
       "iot_class": "cloud_polling"
diff --git a/tests/components/aquacell/__init__.py b/tests/components/aquacell/__init__.py
index c54bc539496..9190172145a 100644
--- a/tests/components/aquacell/__init__.py
+++ b/tests/components/aquacell/__init__.py
@@ -1,6 +1,9 @@
 """Tests for the Aquacell integration."""
 
+from aioaquacell import Brand
+
 from homeassistant.components.aquacell.const import (
+    CONF_BRAND,
     CONF_REFRESH_TOKEN,
     CONF_REFRESH_TOKEN_CREATION_TIME,
 )
@@ -14,11 +17,20 @@ TEST_CONFIG_ENTRY = {
     CONF_PASSWORD: "test-password",
     CONF_REFRESH_TOKEN: "refresh-token",
     CONF_REFRESH_TOKEN_CREATION_TIME: 0,
+    CONF_BRAND: Brand.AQUACELL,
+}
+
+TEST_CONFIG_ENTRY_WITHOUT_BRAND = {
+    CONF_EMAIL: "test@test.com",
+    CONF_PASSWORD: "test-password",
+    CONF_REFRESH_TOKEN: "refresh-token",
+    CONF_REFRESH_TOKEN_CREATION_TIME: 0,
 }
 
 TEST_USER_INPUT = {
     CONF_EMAIL: "test@test.com",
     CONF_PASSWORD: "test-password",
+    CONF_BRAND: "aquacell",
 }
 
 DSN = "DSN"
diff --git a/tests/components/aquacell/conftest.py b/tests/components/aquacell/conftest.py
index f5a741ceed8..443f7da77ce 100644
--- a/tests/components/aquacell/conftest.py
+++ b/tests/components/aquacell/conftest.py
@@ -13,7 +13,7 @@ from homeassistant.components.aquacell.const import (
 )
 from homeassistant.const import CONF_EMAIL
 
-from . import TEST_CONFIG_ENTRY
+from . import TEST_CONFIG_ENTRY, TEST_CONFIG_ENTRY_WITHOUT_BRAND
 
 from tests.common import MockConfigEntry, load_json_array_fixture
 
@@ -76,3 +76,17 @@ def mock_config_entry() -> MockConfigEntry:
             CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(),
         },
     )
+
+
+@pytest.fixture
+def mock_config_entry_without_brand() -> MockConfigEntry:
+    """Mock a config entry."""
+    return MockConfigEntry(
+        domain=DOMAIN,
+        title="Aquacell",
+        unique_id=TEST_CONFIG_ENTRY[CONF_EMAIL],
+        data={
+            **TEST_CONFIG_ENTRY_WITHOUT_BRAND,
+            CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(),
+        },
+    )
diff --git a/tests/components/aquacell/test_config_flow.py b/tests/components/aquacell/test_config_flow.py
index b6bcb82293c..b73852d513f 100644
--- a/tests/components/aquacell/test_config_flow.py
+++ b/tests/components/aquacell/test_config_flow.py
@@ -5,7 +5,11 @@ from unittest.mock import AsyncMock
 from aioaquacell import ApiException, AuthenticationFailed
 import pytest
 
-from homeassistant.components.aquacell.const import CONF_REFRESH_TOKEN, DOMAIN
+from homeassistant.components.aquacell.const import (
+    CONF_BRAND,
+    CONF_REFRESH_TOKEN,
+    DOMAIN,
+)
 from homeassistant.config_entries import SOURCE_USER
 from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
 from homeassistant.core import HomeAssistant
@@ -51,7 +55,9 @@ async def test_full_flow(
     result = await hass.config_entries.flow.async_init(
         DOMAIN, context={"source": SOURCE_USER}
     )
+
     assert result["type"] is FlowResultType.FORM
+    assert result["step_id"] == "user"
     assert result["errors"] == {}
 
     result2 = await hass.config_entries.flow.async_configure(
@@ -65,6 +71,7 @@ async def test_full_flow(
     assert result2["data"][CONF_EMAIL] == TEST_CONFIG_ENTRY[CONF_EMAIL]
     assert result2["data"][CONF_PASSWORD] == TEST_CONFIG_ENTRY[CONF_PASSWORD]
     assert result2["data"][CONF_REFRESH_TOKEN] == TEST_CONFIG_ENTRY[CONF_REFRESH_TOKEN]
+    assert result2["data"][CONF_BRAND] == TEST_CONFIG_ENTRY[CONF_BRAND]
     assert len(mock_setup_entry.mock_calls) == 1
 
 
@@ -109,4 +116,5 @@ async def test_form_exceptions(
     assert result3["data"][CONF_EMAIL] == TEST_CONFIG_ENTRY[CONF_EMAIL]
     assert result3["data"][CONF_PASSWORD] == TEST_CONFIG_ENTRY[CONF_PASSWORD]
     assert result3["data"][CONF_REFRESH_TOKEN] == TEST_CONFIG_ENTRY[CONF_REFRESH_TOKEN]
+    assert result3["data"][CONF_BRAND] == TEST_CONFIG_ENTRY[CONF_BRAND]
     assert len(mock_setup_entry.mock_calls) == 1
diff --git a/tests/components/aquacell/test_init.py b/tests/components/aquacell/test_init.py
index a70d077e180..580d87f4d9a 100644
--- a/tests/components/aquacell/test_init.py
+++ b/tests/components/aquacell/test_init.py
@@ -38,6 +38,17 @@ async def test_load_unload_entry(
     assert entry.state is ConfigEntryState.NOT_LOADED
 
 
+async def test_load_withoutbrand(
+    hass: HomeAssistant,
+    mock_aquacell_api: AsyncMock,
+    mock_config_entry_without_brand: MockConfigEntry,
+) -> None:
+    """Test load entry without brand."""
+    await setup_integration(hass, mock_config_entry_without_brand)
+
+    assert mock_config_entry_without_brand.state is ConfigEntryState.LOADED
+
+
 async def test_coordinator_update_valid_refresh_token(
     hass: HomeAssistant,
     mock_aquacell_api: AsyncMock,
-- 
GitLab