From 738701a2d628c9d9b32f0fa7d5cbc0c375e0a5e1 Mon Sep 17 00:00:00 2001 From: stegm Date: Mon, 2 May 2022 11:42:18 +0200 Subject: [PATCH] Handle missing kostal plenticore battery option (#65237) Co-authored-by: Martin Hjelmare --- .../components/kostal_plenticore/select.py | 45 +++++++++----- .../components/kostal_plenticore/conftest.py | 61 ++++++++----------- .../kostal_plenticore/test_diagnostics.py | 31 +++++++++- .../kostal_plenticore/test_select.py | 45 ++++++++++++++ 4 files changed, 130 insertions(+), 52 deletions(-) create mode 100644 tests/components/kostal_plenticore/test_select.py diff --git a/homeassistant/components/kostal_plenticore/select.py b/homeassistant/components/kostal_plenticore/select.py index 1844f0894a5..7ac06f2ebef 100644 --- a/homeassistant/components/kostal_plenticore/select.py +++ b/homeassistant/components/kostal_plenticore/select.py @@ -24,6 +24,8 @@ async def async_setup_entry( ) -> None: """Add kostal plenticore Select widget.""" plenticore: Plenticore = hass.data[DOMAIN][entry.entry_id] + + available_settings_data = await plenticore.client.get_settings() select_data_update_coordinator = SelectDataUpdateCoordinator( hass, _LOGGER, @@ -32,23 +34,34 @@ async def async_setup_entry( plenticore, ) - async_add_entities( - PlenticoreDataSelect( - select_data_update_coordinator, - entry_id=entry.entry_id, - platform_name=entry.title, - device_class="kostal_plenticore__battery", - module_id=select.module_id, - data_id=select.data_id, - name=select.name, - current_option="None", - options=select.options, - is_on=select.is_on, - device_info=plenticore.device_info, - unique_id=f"{entry.entry_id}_{select.module_id}", + entities = [] + for select in SELECT_SETTINGS_DATA: + if select.module_id not in available_settings_data: + continue + needed_data_ids = {data_id for data_id in select.options if data_id != "None"} + available_data_ids = { + setting.id for setting in available_settings_data[select.module_id] + } + if not needed_data_ids <= available_data_ids: + continue + entities.append( + PlenticoreDataSelect( + select_data_update_coordinator, + entry_id=entry.entry_id, + platform_name=entry.title, + device_class="kostal_plenticore__battery", + module_id=select.module_id, + data_id=select.data_id, + name=select.name, + current_option="None", + options=select.options, + is_on=select.is_on, + device_info=plenticore.device_info, + unique_id=f"{entry.entry_id}_{select.module_id}", + ) ) - for select in SELECT_SETTINGS_DATA - ) + + async_add_entities(entities) class PlenticoreDataSelect(CoordinatorEntity, SelectEntity, ABC): diff --git a/tests/components/kostal_plenticore/conftest.py b/tests/components/kostal_plenticore/conftest.py index c3ed1b45592..4e789a34198 100644 --- a/tests/components/kostal_plenticore/conftest.py +++ b/tests/components/kostal_plenticore/conftest.py @@ -4,9 +4,10 @@ from __future__ import annotations from collections.abc import Generator from unittest.mock import AsyncMock, MagicMock, patch -from kostal.plenticore import MeData, SettingsData, VersionData +from kostal.plenticore import MeData, VersionData import pytest +from homeassistant.components.kostal_plenticore.helper import Plenticore from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import DeviceInfo @@ -14,10 +15,19 @@ from tests.common import MockConfigEntry @pytest.fixture -async def init_integration( - hass: HomeAssistant, -) -> Generator[None, MockConfigEntry, None]: - """Set up Kostal Plenticore integration for testing.""" +def mock_config_entry() -> MockConfigEntry: + """Return a mocked ConfigEntry for testing.""" + return MockConfigEntry( + entry_id="2ab8dd92a62787ddfe213a67e09406bd", + title="scb", + domain="kostal_plenticore", + data={"host": "192.168.1.2", "password": "SecretPassword"}, + ) + + +@pytest.fixture +def mock_plenticore() -> Generator[Plenticore, None, None]: + """Set up a Plenticore mock with some default values.""" with patch( "homeassistant.components.kostal_plenticore.Plenticore", autospec=True ) as mock_api_class: @@ -60,37 +70,20 @@ async def init_integration( ) plenticore.client.get_process_data = AsyncMock() - plenticore.client.get_process_data.return_value = { - "devices:local": ["HomeGrid_P", "HomePv_P"] - } - plenticore.client.get_settings = AsyncMock() - plenticore.client.get_settings.return_value = { - "devices:local": [ - SettingsData( - { - "id": "Battery:MinSoc", - "unit": "%", - "default": "None", - "min": 5, - "max": 100, - "type": "byte", - "access": "readwrite", - } - ) - ] - } - mock_config_entry = MockConfigEntry( - entry_id="2ab8dd92a62787ddfe213a67e09406bd", - title="scb", - domain="kostal_plenticore", - data={"host": "192.168.1.2", "password": "SecretPassword"}, - ) + yield plenticore - mock_config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() +@pytest.fixture +async def init_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry +) -> MockConfigEntry: + """Set up Kostal Plenticore integration for testing.""" - yield mock_config_entry + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + return mock_config_entry diff --git a/tests/components/kostal_plenticore/test_diagnostics.py b/tests/components/kostal_plenticore/test_diagnostics.py index 56af8bafe06..1f249aa3798 100644 --- a/tests/components/kostal_plenticore/test_diagnostics.py +++ b/tests/components/kostal_plenticore/test_diagnostics.py @@ -1,7 +1,9 @@ """Test Kostal Plenticore diagnostics.""" from aiohttp import ClientSession +from kostal.plenticore import SettingsData from homeassistant.components.diagnostics import REDACTED +from homeassistant.components.kostal_plenticore.helper import Plenticore from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry @@ -9,9 +11,34 @@ from tests.components.diagnostics import get_diagnostics_for_config_entry async def test_entry_diagnostics( - hass: HomeAssistant, hass_client: ClientSession, init_integration: MockConfigEntry -): + hass: HomeAssistant, + hass_client: ClientSession, + mock_plenticore: Plenticore, + init_integration: MockConfigEntry, +) -> None: """Test config entry diagnostics.""" + + # set some test process and settings data for the diagnostics output + mock_plenticore.client.get_process_data.return_value = { + "devices:local": ["HomeGrid_P", "HomePv_P"] + } + + mock_plenticore.client.get_settings.return_value = { + "devices:local": [ + SettingsData( + { + "id": "Battery:MinSoc", + "unit": "%", + "default": "None", + "min": 5, + "max": 100, + "type": "byte", + "access": "readwrite", + } + ) + ] + } + assert await get_diagnostics_for_config_entry( hass, hass_client, init_integration ) == { diff --git a/tests/components/kostal_plenticore/test_select.py b/tests/components/kostal_plenticore/test_select.py new file mode 100644 index 00000000000..6023b015483 --- /dev/null +++ b/tests/components/kostal_plenticore/test_select.py @@ -0,0 +1,45 @@ +"""Test the Kostal Plenticore Solar Inverter select platform.""" +from kostal.plenticore import SettingsData + +from homeassistant.components.kostal_plenticore.helper import Plenticore +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry + +from tests.common import MockConfigEntry + + +async def test_select_battery_charging_usage_available( + hass: HomeAssistant, mock_plenticore: Plenticore, mock_config_entry: MockConfigEntry +) -> None: + """Test that the battery charging usage select entity is added if the settings are available.""" + + mock_plenticore.client.get_settings.return_value = { + "devices:local": [ + SettingsData({"id": "Battery:SmartBatteryControl:Enable"}), + SettingsData({"id": "Battery:TimeControl:Enable"}), + ] + } + + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert entity_registry.async_get(hass).async_is_registered( + "select.battery_charging_usage_mode" + ) + + +async def test_select_battery_charging_usage_not_available( + hass: HomeAssistant, mock_plenticore: Plenticore, mock_config_entry: MockConfigEntry +) -> None: + """Test that the battery charging usage select entity is not added if the settings are unavailable.""" + + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert not entity_registry.async_get(hass).async_is_registered( + "select.battery_charging_usage_mode" + )