Only offer smart charging modes the Peblar accepts (#180565)

This commit is contained in:
Franck Nijhof
2026-08-29 01:50:01 +02:00
committed by GitHub
parent 6b453881ca
commit 036cebbf06
2 changed files with 67 additions and 7 deletions
+31 -7
View File
@@ -33,22 +33,38 @@ class PeblarSelectEntityDescription(SelectEntityDescription):
"""Class describing Peblar select entities."""
has_fn: Callable[[PeblarRuntimeData], bool] = lambda _: True
options_fn: Callable[[PeblarUserConfiguration], list[str]] | None = None
current_fn: Callable[[PeblarUserConfiguration], str | None]
select_fn: Callable[[Peblar, str], Awaitable[Any]]
def _smart_charging_options(configuration: PeblarUserConfiguration) -> list[str]:
"""Return the smart charging modes this charger will accept.
A charger without a power meter configured rejects solar charging, and
scheduled charging can be switched off during commissioning. Offering
those anyway lands the user on a mode the charger quietly ignores.
"""
solar = configuration.solar_charging_allowed
return [
option
for option, allowed in (
("default", True),
("fast_solar", solar),
("pure_solar", solar),
("scheduled", configuration.scheduled_charging_allowed),
("smart_solar", solar),
)
if allowed
]
DESCRIPTIONS = [
PeblarSelectEntityDescription(
key="smart_charging",
translation_key="smart_charging",
entity_category=EntityCategory.CONFIG,
options=[
"default",
"fast_solar",
"pure_solar",
"scheduled",
"smart_solar",
],
options_fn=_smart_charging_options,
current_fn=lambda x: x.smart_charging.value if x.smart_charging else None,
select_fn=lambda x, mode: x.smart_charging(SmartChargingMode(mode)),
),
@@ -118,6 +134,14 @@ class PeblarSelectEntity(
entity_description: PeblarSelectEntityDescription
@property
@override
def options(self) -> list[str]:
"""Return the options this charger currently accepts."""
if (options_fn := self.entity_description.options_fn) is not None:
return options_fn(self.coordinator.data)
return super().options
@property
@override
def current_option(self) -> str | None:
+36
View File
@@ -17,6 +17,7 @@ from syrupy.assertion import SnapshotAssertion
from homeassistant.components.peblar.const import DOMAIN
from homeassistant.components.select import (
ATTR_OPTION,
ATTR_OPTIONS,
DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
)
@@ -250,3 +251,38 @@ async def test_hw_entity_absent_when_hw_flag_false(
)
is None
)
@pytest.mark.parametrize(
("mock_peblar", "expected_options"),
[
(
{"SolarChargingAllowed": False},
["default", "scheduled"],
),
(
{"ScheduledChargingAllowed": False},
["default", "fast_solar", "pure_solar", "smart_solar"],
),
(
{"SolarChargingAllowed": False, "ScheduledChargingAllowed": False},
["default"],
),
],
ids=["no solar", "no scheduled", "neither"],
indirect=["mock_peblar"],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_smart_charging_options_follow_the_charger(
hass: HomeAssistant,
expected_options: list[str],
) -> None:
"""Only offer the smart charging modes the charger accepts.
A charger without a power meter rejects solar charging, and the web
interface hides those modes. Offering them anyway lets the user pick
something the charger quietly ignores.
"""
state = hass.states.get("select.peblar_ev_charger_smart_charging")
assert state
assert state.attributes[ATTR_OPTIONS] == expected_options