mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 09:17:53 +00:00
Get kostal plenticore hostname id from get_settings (#93008)
* Get hostname id from get_settings * Add try except in get_hostname_id function * Update tests after adding get_hostname_id function * Revert "Update tests after adding get_hostname_id function" This reverts commit 5fa4e533cb18e8d141dbb1b7aed021f80f4312a2. * Add test for G2 models in config flow. * Add test for helper module. * Fix test for numbers. * Revert "Add try except in get_hostname_id function" This reverts commit 059f5bd9b413ca060300e09a6a1f0dffb4420f56. * Update variable name with known hostname ids to be private --------- Co-authored-by: Stefan Gmeiner <stefangm42@gmail.com>
This commit is contained in:
parent
1dccb8a9a9
commit
2721874f13
@ -12,6 +12,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN
|
||||
from .helper import get_hostname_id
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -32,9 +33,10 @@ async def test_connection(hass: HomeAssistant, data) -> str:
|
||||
session = async_get_clientsession(hass)
|
||||
async with ApiClient(session, data["host"]) as client:
|
||||
await client.login(data["password"])
|
||||
values = await client.get_setting_values("scb:network", "Hostname")
|
||||
hostname_id = await get_hostname_id(client)
|
||||
values = await client.get_setting_values("scb:network", hostname_id)
|
||||
|
||||
return values["scb:network"]["Hostname"]
|
||||
return values["scb:network"][hostname_id]
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -23,6 +23,7 @@ from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_DataT = TypeVar("_DataT")
|
||||
_KNOWN_HOSTNAME_IDS = ("Network:Hostname", "Hostname")
|
||||
|
||||
|
||||
class Plenticore:
|
||||
@ -69,6 +70,7 @@ class Plenticore:
|
||||
)
|
||||
|
||||
# get some device meta data
|
||||
hostname_id = await get_hostname_id(self._client)
|
||||
settings = await self._client.get_setting_values(
|
||||
{
|
||||
"devices:local": [
|
||||
@ -78,7 +80,7 @@ class Plenticore:
|
||||
"Properties:VersionIOC",
|
||||
"Properties:VersionMC",
|
||||
],
|
||||
"scb:network": ["Hostname"],
|
||||
"scb:network": [hostname_id],
|
||||
}
|
||||
)
|
||||
|
||||
@ -91,7 +93,7 @@ class Plenticore:
|
||||
identifiers={(DOMAIN, device_local["Properties:SerialNo"])},
|
||||
manufacturer="Kostal",
|
||||
model=f"{prod1} {prod2}",
|
||||
name=settings["scb:network"]["Hostname"],
|
||||
name=settings["scb:network"][hostname_id],
|
||||
sw_version=f'IOC: {device_local["Properties:VersionIOC"]}'
|
||||
+ f' MC: {device_local["Properties:VersionMC"]}',
|
||||
)
|
||||
@ -403,3 +405,12 @@ class PlenticoreDataFormatter:
|
||||
return state
|
||||
|
||||
return PlenticoreDataFormatter.EM_STATES.get(value)
|
||||
|
||||
|
||||
async def get_hostname_id(client: ApiClient) -> str:
|
||||
"""Check for known existing hostname ids."""
|
||||
all_settings = await client.get_settings()
|
||||
for entry in all_settings["scb:network"]:
|
||||
if entry.id in _KNOWN_HOSTNAME_IDS:
|
||||
return entry.id
|
||||
raise ApiException("Hostname identifier not found in KNOWN_HOSTNAME_IDS")
|
||||
|
@ -1,8 +1,10 @@
|
||||
"""Test the Kostal Plenticore Solar Inverter config flow."""
|
||||
import asyncio
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import ANY, AsyncMock, MagicMock, patch
|
||||
|
||||
from pykoplenti import AuthenticationException
|
||||
from pykoplenti import ApiClient, AuthenticationException, SettingsData
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.kostal_plenticore.const import DOMAIN
|
||||
@ -11,8 +13,33 @@ from homeassistant.core import HomeAssistant
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_formx(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form."""
|
||||
@pytest.fixture
|
||||
def mock_apiclient() -> ApiClient:
|
||||
"""Return a mocked ApiClient instance."""
|
||||
apiclient = MagicMock(spec=ApiClient)
|
||||
apiclient.__aenter__.return_value = apiclient
|
||||
apiclient.__aexit__ = AsyncMock()
|
||||
|
||||
return apiclient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_apiclient_class(mock_apiclient) -> Generator[type[ApiClient], None, None]:
|
||||
"""Return a mocked ApiClient class."""
|
||||
with patch(
|
||||
"homeassistant.components.kostal_plenticore.config_flow.ApiClient",
|
||||
autospec=True,
|
||||
) as mock_api_class:
|
||||
mock_api_class.return_value = mock_apiclient
|
||||
yield mock_api_class
|
||||
|
||||
|
||||
async def test_form_g1(
|
||||
hass: HomeAssistant,
|
||||
mock_apiclient_class: type[ApiClient],
|
||||
mock_apiclient: ApiClient,
|
||||
) -> None:
|
||||
"""Test the config flow for G1 models."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
@ -21,25 +48,19 @@ async def test_formx(hass: HomeAssistant) -> None:
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kostal_plenticore.config_flow.ApiClient"
|
||||
) as mock_api_class, patch(
|
||||
"homeassistant.components.kostal_plenticore.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
# mock of the context manager instance
|
||||
mock_api_ctx = MagicMock()
|
||||
mock_api_ctx.login = AsyncMock()
|
||||
mock_api_ctx.get_setting_values = AsyncMock(
|
||||
mock_apiclient.login = AsyncMock()
|
||||
mock_apiclient.get_settings = AsyncMock(
|
||||
return_value={"scb:network": [SettingsData({"id": "Hostname"})]}
|
||||
)
|
||||
mock_apiclient.get_setting_values = AsyncMock(
|
||||
# G1 model has the entry id "Hostname"
|
||||
return_value={"scb:network": {"Hostname": "scb"}}
|
||||
)
|
||||
|
||||
# mock of the return instance of ApiClient
|
||||
mock_api = MagicMock()
|
||||
mock_api.__aenter__.return_value = mock_api_ctx
|
||||
mock_api.__aexit__ = AsyncMock()
|
||||
|
||||
mock_api_class.return_value = mock_api
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
@ -49,11 +70,68 @@ async def test_formx(hass: HomeAssistant) -> None:
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_api_class.assert_called_once_with(ANY, "1.1.1.1")
|
||||
mock_api.__aenter__.assert_called_once()
|
||||
mock_api.__aexit__.assert_called_once()
|
||||
mock_api_ctx.login.assert_called_once_with("test-password")
|
||||
mock_api_ctx.get_setting_values.assert_called_once()
|
||||
mock_apiclient_class.assert_called_once_with(ANY, "1.1.1.1")
|
||||
mock_apiclient.__aenter__.assert_called_once()
|
||||
mock_apiclient.__aexit__.assert_called_once()
|
||||
mock_apiclient.login.assert_called_once_with("test-password")
|
||||
mock_apiclient.get_settings.assert_called_once()
|
||||
mock_apiclient.get_setting_values.assert_called_once_with(
|
||||
"scb:network", "Hostname"
|
||||
)
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "scb"
|
||||
assert result2["data"] == {
|
||||
"host": "1.1.1.1",
|
||||
"password": "test-password",
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_g2(
|
||||
hass: HomeAssistant,
|
||||
mock_apiclient_class: type[ApiClient],
|
||||
mock_apiclient: ApiClient,
|
||||
) -> None:
|
||||
"""Test the config flow for G2 models."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.kostal_plenticore.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
# mock of the context manager instance
|
||||
mock_apiclient.login = AsyncMock()
|
||||
mock_apiclient.get_settings = AsyncMock(
|
||||
return_value={"scb:network": [SettingsData({"id": "Network:Hostname"})]}
|
||||
)
|
||||
mock_apiclient.get_setting_values = AsyncMock(
|
||||
# G1 model has the entry id "Hostname"
|
||||
return_value={"scb:network": {"Network:Hostname": "scb"}}
|
||||
)
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_apiclient_class.assert_called_once_with(ANY, "1.1.1.1")
|
||||
mock_apiclient.__aenter__.assert_called_once()
|
||||
mock_apiclient.__aexit__.assert_called_once()
|
||||
mock_apiclient.login.assert_called_once_with("test-password")
|
||||
mock_apiclient.get_settings.assert_called_once()
|
||||
mock_apiclient.get_setting_values.assert_called_once_with(
|
||||
"scb:network", "Network:Hostname"
|
||||
)
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "scb"
|
||||
|
107
tests/components/kostal_plenticore/test_helper.py
Normal file
107
tests/components/kostal_plenticore/test_helper.py
Normal file
@ -0,0 +1,107 @@
|
||||
"""Test Kostal Plenticore helper."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from pykoplenti import ApiClient, SettingsData
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.kostal_plenticore.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_apiclient() -> Generator[ApiClient, None, None]:
|
||||
"""Return a mocked ApiClient class."""
|
||||
with patch(
|
||||
"homeassistant.components.kostal_plenticore.helper.ApiClient",
|
||||
autospec=True,
|
||||
) as mock_api_class:
|
||||
apiclient = MagicMock(spec=ApiClient)
|
||||
apiclient.__aenter__.return_value = apiclient
|
||||
apiclient.__aexit__ = AsyncMock()
|
||||
mock_api_class.return_value = apiclient
|
||||
yield apiclient
|
||||
|
||||
|
||||
async def test_plenticore_async_setup_g1(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_apiclient: ApiClient,
|
||||
) -> None:
|
||||
"""Tests the async_setup() method of the Plenticore class for G1 models."""
|
||||
mock_apiclient.get_settings = AsyncMock(
|
||||
return_value={"scb:network": [SettingsData({"id": "Hostname"})]}
|
||||
)
|
||||
mock_apiclient.get_setting_values = AsyncMock(
|
||||
# G1 model has the entry id "Hostname"
|
||||
return_value={
|
||||
"devices:local": {
|
||||
"Properties:SerialNo": "12345",
|
||||
"Branding:ProductName1": "PLENTICORE",
|
||||
"Branding:ProductName2": "plus 10",
|
||||
"Properties:VersionIOC": "01.45",
|
||||
"Properties:VersionMC": "01.46",
|
||||
},
|
||||
"scb:network": {"Hostname": "scb"},
|
||||
}
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
plenticore = hass.data[DOMAIN][mock_config_entry.entry_id]
|
||||
|
||||
assert plenticore.device_info == DeviceInfo(
|
||||
configuration_url="http://192.168.1.2",
|
||||
identifiers={(DOMAIN, "12345")},
|
||||
manufacturer="Kostal",
|
||||
model="PLENTICORE plus 10",
|
||||
name="scb",
|
||||
sw_version="IOC: 01.45 MC: 01.46",
|
||||
)
|
||||
|
||||
|
||||
async def test_plenticore_async_setup_g2(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_apiclient: ApiClient,
|
||||
) -> None:
|
||||
"""Tests the async_setup() method of the Plenticore class for G2 models."""
|
||||
mock_apiclient.get_settings = AsyncMock(
|
||||
return_value={"scb:network": [SettingsData({"id": "Network:Hostname"})]}
|
||||
)
|
||||
mock_apiclient.get_setting_values = AsyncMock(
|
||||
# G1 model has the entry id "Hostname"
|
||||
return_value={
|
||||
"devices:local": {
|
||||
"Properties:SerialNo": "12345",
|
||||
"Branding:ProductName1": "PLENTICORE",
|
||||
"Branding:ProductName2": "plus 10",
|
||||
"Properties:VersionIOC": "01.45",
|
||||
"Properties:VersionMC": "01.46",
|
||||
},
|
||||
"scb:network": {"Network:Hostname": "scb"},
|
||||
}
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
plenticore = hass.data[DOMAIN][mock_config_entry.entry_id]
|
||||
|
||||
assert plenticore.device_info == DeviceInfo(
|
||||
configuration_url="http://192.168.1.2",
|
||||
identifiers={(DOMAIN, "12345")},
|
||||
manufacturer="Kostal",
|
||||
model="PLENTICORE plus 10",
|
||||
name="scb",
|
||||
sw_version="IOC: 01.45 MC: 01.46",
|
||||
)
|
@ -62,7 +62,20 @@ def mock_get_setting_values(mock_plenticore_client: ApiClient) -> list:
|
||||
"id": "Battery:MinHomeComsumption",
|
||||
}
|
||||
),
|
||||
]
|
||||
],
|
||||
"scb:network": [
|
||||
SettingsData(
|
||||
{
|
||||
"min": "1",
|
||||
"default": None,
|
||||
"access": "readwrite",
|
||||
"unit": None,
|
||||
"id": "Hostname",
|
||||
"type": "string",
|
||||
"max": "63",
|
||||
}
|
||||
)
|
||||
],
|
||||
}
|
||||
|
||||
# this values are always retrieved by the integration on startup
|
||||
@ -112,7 +125,22 @@ async def test_setup_no_entries(
|
||||
) -> None:
|
||||
"""Test that no entries are setup if Plenticore does not provide data."""
|
||||
|
||||
mock_plenticore_client.get_settings.return_value = []
|
||||
# remove all settings except hostname which is used during setup
|
||||
mock_plenticore_client.get_settings.return_value = {
|
||||
"scb:network": [
|
||||
SettingsData(
|
||||
{
|
||||
"min": "1",
|
||||
"default": None,
|
||||
"access": "readwrite",
|
||||
"unit": None,
|
||||
"id": "Hostname",
|
||||
"type": "string",
|
||||
"max": "63",
|
||||
}
|
||||
)
|
||||
],
|
||||
}
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user