From 2159cb55b1af2f0c943b32963992cebfc9a582e9 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 16 Sep 2026 15:12:30 +0200 Subject: [PATCH 1/2] wait_for_start_active default to false as in legacy smarthome --- packages/control/consumer/consumer_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/control/consumer/consumer_data.py b/packages/control/consumer/consumer_data.py index e72a63512d..42d5c75029 100644 --- a/packages/control/consumer/consumer_data.py +++ b/packages/control/consumer/consumer_data.py @@ -54,7 +54,7 @@ class Usage: time_charging: TimeCharging = field(default_factory=lambda: TimeCharging()) type: ConsumerUsage = ConsumerUsage.METER_ONLY reset_chargemode: ResetChargemode = field(default_factory=lambda: ResetChargemode()) - wait_for_start_active: bool = True + wait_for_start_active: bool = False @dataclass From fb9f4c3fae5cb6700f35a99a876c8f68e2988097 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 16 Sep 2026 15:20:48 +0200 Subject: [PATCH 2/2] fix reset reserved surplus in case of aborted switch on delay --- packages/control/counter.py | 39 +++++++++++++++------------ packages/control/counter_test.py | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/packages/control/counter.py b/packages/control/counter.py index 136e1484f7..4e8b832e93 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -596,23 +596,30 @@ def reset_switch_on_off(self, load: Load): if load.data.control_parameter.timestamp_switch_on_off is not None: load.data.control_parameter.timestamp_switch_on_off = None evu_counter = data.data.counter_all_data.get_evu_counter() - # Wenn bereits geladen wird, lief die Abschaltverzögerung -> Leistung, die nach Abschalten frei - # geworden wäre, nicht mehr zum zur Verfügung stehenden Überschuss zählen. - # Wenn nicht geladen wird, reservierte Leistung freigeben. - surplus_config = data.data.general_data.data.chargemode_config.surplus - if isinstance(load, Chargepoint): - if not load.data.get.charge_state: - threshold = surplus_config.vehicle.switch_on_threshold * load.data.set.phases_to_use + # Reservierungen nur zurücknehmen, wenn wirklich ein Verzögerungszustand aktiv war. + state = load.data.control_parameter.state + if state in (ChargepointState.SWITCH_ON_DELAY, ChargepointState.SWITCH_OFF_DELAY): + surplus_config = data.data.general_data.data.chargemode_config.surplus + if isinstance(load, Chargepoint): + if state == ChargepointState.SWITCH_ON_DELAY: + threshold = surplus_config.vehicle.switch_on_threshold * load.data.set.phases_to_use + else: + threshold = surplus_config.vehicle.switch_on_threshold * load.data.control_parameter.phases else: - threshold = surplus_config.vehicle.switch_on_threshold * load.data.control_parameter.phases - else: - threshold = (load.data.control_parameter.required_current * - 230 * - load.data.control_parameter.phases) - if not load.data.get.charge_state: - evu_counter.data.set.reserved_surplus -= threshold - else: - evu_counter.data.set.released_surplus -= threshold + threshold = (load.data.control_parameter.required_current * + 230 * + load.data.control_parameter.phases) + + if state == ChargepointState.SWITCH_ON_DELAY: + evu_counter.data.set.reserved_surplus = max( + 0, + evu_counter.data.set.reserved_surplus - threshold, + ) + else: + evu_counter.data.set.released_surplus = max( + 0, + evu_counter.data.set.released_surplus - threshold, + ) load.data.control_parameter.state = ChargepointState.NO_CHARGING_ALLOWED except Exception: log.exception("Fehler im allgemeinen PV-Modul") diff --git a/packages/control/counter_test.py b/packages/control/counter_test.py index f84173799b..c1bd1ff754 100644 --- a/packages/control/counter_test.py +++ b/packages/control/counter_test.py @@ -7,6 +7,7 @@ from control import counter as counter_module from control import data from control.chargepoint.chargepoint import Chargepoint +from control.consumer.consumer import Consumer from control.counter import Counter, CounterData, Get from control.ev.ev import Ev from control.ev.charge_template import ChargeTemplate @@ -196,3 +197,47 @@ def test_control_range(control_range, evu_power, expected_range_offset, general_ # evaluation assert range_offset == expected_range_offset + + +def test_reset_switch_on_off_ignores_stale_timestamp_without_delay_state(general_data_fixture, monkeypatch): + # setup + evu_counter = Counter(0) + evu_counter.data.set.reserved_surplus = 690 + monkeypatch.setattr(data.data.counter_all_data, "get_evu_counter", Mock(return_value=evu_counter)) + + consumer = Consumer(7) + consumer.data.control_parameter.timestamp_switch_on_off = 1652683250.0 + consumer.data.control_parameter.state = ChargepointState.NO_CHARGING_ALLOWED + consumer.data.control_parameter.required_current = 21.70138888888889 + consumer.data.control_parameter.phases = 1 + consumer.data.get.charge_state = False + + # execution + evu_counter.reset_switch_on_off(consumer) + + # evaluation + assert evu_counter.data.set.reserved_surplus == 690 + assert consumer.data.control_parameter.timestamp_switch_on_off is None + assert consumer.data.control_parameter.state == ChargepointState.NO_CHARGING_ALLOWED + + +def test_reset_switch_on_off_releases_reserved_surplus_on_switch_on_delay(general_data_fixture, monkeypatch): + # setup + evu_counter = Counter(0) + evu_counter.data.set.reserved_surplus = 690 + monkeypatch.setattr(data.data.counter_all_data, "get_evu_counter", Mock(return_value=evu_counter)) + + consumer = Consumer(6) + consumer.data.control_parameter.timestamp_switch_on_off = 1652683250.0 + consumer.data.control_parameter.state = ChargepointState.SWITCH_ON_DELAY + consumer.data.control_parameter.required_current = 3 + consumer.data.control_parameter.phases = 1 + consumer.data.get.charge_state = False + + # execution + evu_counter.reset_switch_on_off(consumer) + + # evaluation + assert evu_counter.data.set.reserved_surplus == 0 + assert consumer.data.control_parameter.timestamp_switch_on_off is None + assert consumer.data.control_parameter.state == ChargepointState.NO_CHARGING_ALLOWED