Fix the Peblar charge limit maximum (#180564)

This commit is contained in:
Franck Nijhof
2026-08-29 20:36:10 +00:00
parent 262fd5da39
commit 22a9246eb5
4 changed files with 87 additions and 7 deletions
@@ -16,6 +16,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarDataUpdateCoordinator,
+9 -1
View File
@@ -70,8 +70,16 @@ class PeblarChargeCurrentLimitNumberEntity(
coordinator=coordinator,
description=NumberEntityDescription(key="charge_current_limit"),
)
# Not the user's own charge limit: that is the value being set here,
# so using it as the ceiling would ratchet the slider down and never
# let it back up. The charger accepts up to its hardware rating, and
# reduces anything above the installation limit configured during
# commissioning, so the lower of the two is what can actually be set.
configuration = entry.runtime_data.user_configuration_coordinator.data
self._attr_native_max_value = configuration.user_defined_charge_limit_current
self._attr_native_max_value = min(
entry.runtime_data.system_information.hardware_max_current,
configuration.current_control_fixed_charge_current_limit,
)
@override
async def async_added_to_hass(self) -> None:
+24 -6
View File
@@ -2,6 +2,7 @@
from collections.abc import Generator
from contextlib import nullcontext
import json
from unittest.mock import MagicMock, patch
from peblar import (
@@ -43,8 +44,25 @@ def mock_setup_entry() -> Generator[None]:
@pytest.fixture
def mock_peblar() -> Generator[MagicMock]:
"""Return a mocked Peblar client."""
def mock_peblar(request: pytest.FixtureRequest) -> Generator[MagicMock]:
"""Return a mocked Peblar client.
Parametrize indirectly with a dict to override single fixture fields,
so a test that cares about one flag or one limit does not need a full
copy of the fixture. Keys are looked up in both the system information
and the user configuration.
"""
overrides = getattr(request, "param", {})
system_information = json.loads(load_fixture("system_information.json", DOMAIN))
user_configuration = json.loads(load_fixture("user_configuration.json", DOMAIN))
for key, value in overrides.items():
if key in system_information:
system_information[key] = value
elif key in user_configuration:
user_configuration[key] = value
else:
msg = f"Unknown fixture field: {key}"
raise ValueError(msg)
with (
patch("homeassistant.components.peblar.Peblar", autospec=True) as peblar_mock,
patch("homeassistant.components.peblar.config_flow.Peblar", new=peblar_mock),
@@ -56,11 +74,11 @@ def mock_peblar() -> Generator[MagicMock]:
peblar.current_versions.return_value = PeblarVersions.from_json(
load_fixture("current_versions.json", DOMAIN)
)
peblar.user_configuration.return_value = PeblarUserConfiguration.from_json(
load_fixture("user_configuration.json", DOMAIN)
peblar.user_configuration.return_value = PeblarUserConfiguration.from_dict(
user_configuration
)
peblar.system_information.return_value = PeblarSystemInformation.from_json(
load_fixture("system_information.json", DOMAIN)
peblar.system_information.return_value = PeblarSystemInformation.from_dict(
system_information
)
api = peblar.rest_api.return_value
+53
View File
@@ -7,6 +7,7 @@ import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.number import (
ATTR_MAX,
ATTR_VALUE,
DOMAIN as NUMBER_DOMAIN,
SERVICE_SET_VALUE,
@@ -265,3 +266,55 @@ async def test_restore_state(
# Check if state is restored and value is set correctly
assert (state := hass.states.get("number.peblar_ev_charger_charge_limit"))
assert state.state == expected_state
@pytest.mark.parametrize(
("mock_peblar", "expected_max"),
[
({"UserDefinedChargeLimitCurrent": 10}, 16),
({"CurrentCtrlFixedChargeCurrentLimit": 10}, 10),
({"HwMaxCurrent": 10}, 10),
],
ids=["user limit is not a ceiling", "installation limit", "hardware rating"],
indirect=["mock_peblar"],
)
@pytest.mark.parametrize("init_integration", [Platform.NUMBER], indirect=True)
@pytest.mark.usefixtures("init_integration", "entity_registry_enabled_by_default")
async def test_charge_limit_maximum(
hass: HomeAssistant,
expected_max: int,
) -> None:
"""Test the ceiling on the charge limit.
The charger accepts up to its hardware rating and reduces anything
above the installation limit. The user's own charge limit is the value
being set here, so it must not narrow the range it is chosen from.
"""
state = hass.states.get("number.peblar_ev_charger_charge_limit")
assert state
assert state.attributes[ATTR_MAX] == expected_max
@pytest.mark.parametrize(
"mock_peblar",
[{"UserDefinedChargeLimitCurrent": 10}],
indirect=True,
)
@pytest.mark.parametrize("init_integration", [Platform.NUMBER], indirect=True)
@pytest.mark.usefixtures("init_integration", "entity_registry_enabled_by_default")
async def test_charge_limit_can_be_raised_again(
hass: HomeAssistant,
mock_peblar: MagicMock,
) -> None:
"""A charger left on a low limit can still be turned back up."""
mocked_method = mock_peblar.rest_api.return_value.ev_interface
mocked_method.reset_mock()
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: "number.peblar_ev_charger_charge_limit", ATTR_VALUE: 16},
blocking=True,
)
mocked_method.assert_any_call(charge_current_limit=16000)