From 7d5d9ab7c9ed494f23b35627667f4a5e965a0bbd Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 26 Nov 2025 15:17:30 +0100 Subject: [PATCH 1/3] draft --- packages/modules/common/store/_counter.py | 116 ++++++++----- .../modules/common/store/_counter_test.py | 153 +++++++++++++++++- packages/modules/loadvars.py | 26 ++- 3 files changed, 248 insertions(+), 47 deletions(-) diff --git a/packages/modules/common/store/_counter.py b/packages/modules/common/store/_counter.py index b6a359af8d..2e07466980 100644 --- a/packages/modules/common/store/_counter.py +++ b/packages/modules/common/store/_counter.py @@ -1,6 +1,6 @@ import logging from operator import add -from typing import Optional +from typing import Dict, Optional from control import data from helpermodules import compatibility @@ -71,54 +71,84 @@ def calc_virtual(self, state: CounterState) -> CounterState: if self.add_child_values: self.currents = state.currents if state.currents else [0.0]*3 self.power = state.power + self.imported = state.imported + self.exported = state.exported self.incomplete_currents = False - - def add_current_power(element): - if hasattr(element, "currents") and element.currents is not None: - if sum(element.currents) == 0 and element.power != 0: - self.currents = [0, 0, 0] - self.incomplete_currents = True - else: - self.currents = list(map(add, self.currents, element.currents)) - else: - self.currents = [0, 0, 0] - self.incomplete_currents = True - self.power += element.power - counter_all = data.data.counter_all_data elements = counter_all.get_elements_for_downstream_calculation(self.delegate.delegate.num) - for element in elements: - try: - if element["type"] == ComponentType.CHARGEPOINT.value: - chargepoint = data.data.cp_data[f"cp{element['id']}"] - chargepoint_state = chargepoint.chargepoint_module.store.delegate.state - try: - self.currents = list(map(add, - self.currents, - convert_cp_currents_to_evu_currents( - chargepoint.data.config.phase_1, - chargepoint_state.currents))) - except KeyError: - raise KeyError("Für den virtuellen Zähler muss der Anschluss der Phasen von Ladepunkt" - f" {chargepoint.data.config.name} an die Phasen des EVU Zählers " - "angegeben werden.") - self.power += chargepoint_state.power - else: - component = get_component_obj_by_id(element['id']) - add_current_power(component.store.delegate.delegate.state) - except Exception: - log.exception(f"Fehler beim Hinzufügen der Werte für Element {element}") - - imported, exported = self.sim_counter.sim_count(self.power) - if self.incomplete_currents: - self.currents = None - return CounterState(currents=self.currents, - power=self.power, - exported=exported, - imported=imported) + if len(elements) == 0: + return self.calc_uncounted_consumption(state) + else: + return self.calc_consumers(elements) else: return state + def _add_values(self, element, calc_imported_exported: bool): + if hasattr(element, "currents") and element.currents is not None: + if sum(element.currents) == 0 and element.power != 0: + self.currents = [0, 0, 0] + self.incomplete_currents = True + else: + self.currents = list(map(add, self.currents, element.currents)) + else: + self.currents = [0, 0, 0] + self.incomplete_currents = True + if calc_imported_exported: + if hasattr(element, "imported") and element.imported is not None: + self.imported += element.imported + if element.exported is not None: + self.exported += element.exported + self.power += element.power + + def calc_consumers(self, elements: Dict, calc_imported_exported: bool = True) -> CounterState: + for element in elements: + try: + if element["type"] == ComponentType.CHARGEPOINT.value: + chargepoint = data.data.cp_data[f"cp{element['id']}"] + chargepoint_state = chargepoint.chargepoint_module.store.delegate.state + try: + self.currents = list(map(add, + self.currents, + convert_cp_currents_to_evu_currents( + chargepoint.data.config.phase_1, + chargepoint_state.currents))) + except KeyError: + raise KeyError("Für den virtuellen Zähler muss der Anschluss der Phasen von Ladepunkt" + f" {chargepoint.data.config.name} an die Phasen des EVU Zählers " + "angegeben werden.") + self.power += chargepoint_state.power + else: + component = get_component_obj_by_id(element['id']) + self._add_values(component.store.delegate.delegate.state) + except Exception: + log.exception(f"Fehler beim Hinzufügen der Werte für Element {element}") + + if calc_imported_exported: + self.imported, self.exported = self.sim_counter.sim_count(self.power) + if self.incomplete_currents: + self.currents = None + return CounterState(currents=self.currents, + power=self.power, + exported=self.exported, + imported=self.imported) + + def calc_uncounted_consumption(self) -> CounterState: + parent_id = data.data.counter_all_data.get_parent_of_element(self.delegate.delegate.num) + parent_component = get_component_obj_by_id(parent_id) + if "counter" not in parent_component.component_config.type: + raise Exception("Die übergeordnete Komponente des virtuellen Zählers muss ein Zähler sein.") + if parent_component.store.add_child_values: + raise Exception("Der übergeordnete Zähler des virtuellen Zählers darf nicht auch ein virtueller Zähler sein.") + elements = data.data.counter_all_data.get_elements_for_downstream_calculation(parent_id) + counter_state_consumers = self.calc_consumers(elements, calc_imported_exported=True) + parent_counter_get = data.data.counter_data[f"counter{parent_id}"].data.get + return CounterState( + currents=[parent_counter_get.currents[i] - counter_state_consumers.currents[i] for i in range(0, 3)], + power=parent_counter_get.power - counter_state_consumers.power, + exported=parent_counter_get.exported - counter_state_consumers.exported, + imported=parent_counter_get.imported - counter_state_consumers.imported + ) + def get_counter_value_store(component_num: int, add_child_values: bool = False, diff --git a/packages/modules/common/store/_counter_test.py b/packages/modules/common/store/_counter_test.py index b9e20cd649..41830d9349 100644 --- a/packages/modules/common/store/_counter_test.py +++ b/packages/modules/common/store/_counter_test.py @@ -16,7 +16,7 @@ from modules.common.store import _counter from modules.common.store._api import LoggingValueStore from modules.common.store._battery import BatteryValueStoreBroker, PurgeBatteryState -from modules.common.store._counter import PurgeCounterState +from modules.common.store._counter import CounterValueStoreBroker, PurgeCounterState from modules.common.store._inverter import InverterValueStoreBroker, PurgeInverterState from modules.devices.generic.mqtt.bat import MqttBat from modules.devices.generic.mqtt.counter import MqttCounter @@ -138,3 +138,154 @@ def test_calc_virtual(params: Params, monkeypatch): # evaluation assert vars(state) == vars(params.expected_state) + + +def test_calc_uncounted_consumption(monkeypatch): + """ + Test für calc_uncounted_consumption mit folgendem Szenario: + - Übergeordnete Ebene: Ein Zähler (id=0, parent counter) + - Gleiche Ebene wie virtueller Zähler: Ein Ladepunkt (id=1) und ein weiterer Zähler (id=2) + - Virtueller Zähler: id=3 (soll nicht-gezählten Verbrauch berechnen) + + Hierarchie: + Counter 0 (parent, 8000W total) + ├── Chargepoint 1 (3000W) + ├── Counter 2 (2000W) + └── Virtual Counter 3 (uncounted: 8000 - 3000 - 2000 = 3000W) + """ + # setup + data.data_init(Mock()) + data.data.counter_all_data = CounterAll() + + # Setup parent counter (id=0) auf übergeordneter Ebene + data.data.counter_data["counter0"] = Mock( + spec=Counter, + data=Mock( + spec=CounterData, + get=Mock( + spec=Get, + power=8000, # Gesamtverbrauch + exported=500, + imported=1000, + currents=[20.0, 22.0, 18.0] # Gesamtstrom + ) + ) + ) + + # Setup Ladepunkt (id=1) auf gleicher Ebene wie virtueller Zähler + add_chargepoint(1) + data.data.cp_data["cp1"].data.get.power = 3000 + data.data.cp_data["cp1"].data.get.currents = [8.0, 9.0, 7.0] + data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.power = 3000 + data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.currents = [8.0, 9.0, 7.0] + data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.imported = 150 + data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.exported = 0 + + # Setup weiterer Zähler (id=2) auf gleicher Ebene + data.data.counter_data["counter2"] = Mock( + spec=Counter, + data=Mock( + spec=CounterData, + get=Mock( + spec=Get, + power=2000, + exported=100, + imported=300, + currents=[5.0, 6.0, 4.0] + ) + ) + ) + + # Hierarchie: Parent Counter 0 hat Kinder: CP 1, Counter 2, Virtual Counter 3 + data.data.counter_all_data.data.get.hierarchy = [ + { + "id": 0, + "type": "counter", + "children": [ + {"id": 1, "type": "cp", "children": []}, + {"id": 2, "type": "counter", "children": []}, + {"id": 3, "type": "counter", "children": []} # Virtual counter + ] + } + ] + + # Mock für Parent-Lookup + def mock_get_parent_of_element(element_id): + if element_id == 3: # Virtual counter + return 0 # Parent counter + return None + + # Mock für get_elements_for_downstream_calculation + def mock_get_elements_for_downstream_calculation(parent_id): + if parent_id == 0: # Parent counter + return [ + {"id": 1, "type": "cp"}, + {"id": 2, "type": "counter"} + # Virtual counter 3 wird nicht in eigene Berechnung einbezogen + ] + return [] + + data.data.counter_all_data.get_parent_of_element = Mock(side_effect=mock_get_parent_of_element) + data.data.counter_all_data.get_elements_for_downstream_calculation = Mock( + side_effect=mock_get_elements_for_downstream_calculation + ) + + # Mock parent counter component + parent_counter_component = Mock() + parent_counter_component.component_config.type = "counter" + parent_counter_component.store.add_child_values = False # Nicht virtuell + + # Mock regular counter component (id=2) + regular_counter_component = Mock( + spec=MqttCounter, + store=Mock( + spec=PurgeCounterState, + delegate=Mock( + spec=LoggingValueStore, + delegate=Mock( + spec=CounterValueStoreBroker, + state=CounterState( + power=2000, + exported=100, + imported=300, + currents=[5.0, 6.0, 4.0] + ) + ) + ) + ) + ) + + def mock_get_component_obj_by_id(component_id): + if component_id == 0: # Parent counter + return parent_counter_component + elif component_id == 2: # Regular counter + return regular_counter_component + return None + + monkeypatch.setattr(_counter, "get_component_obj_by_id", mock_get_component_obj_by_id) + + # Setup virtual counter (id=3) + virtual_counter_purge = PurgeCounterState( + delegate=Mock(delegate=Mock(num=3)), + add_child_values=True, + simcounter=SimCounter(0, 0, prefix="virtual") + ) + + # execution + result_state = virtual_counter_purge.calc_uncounted_consumption() + + # evaluation + # Erwartete Werte: Parent Counter - (Chargepoint + Regular Counter) + # Power: 8000 - (3000 + 2000) = 3000W + # Currents: [20.0, 22.0, 18.0] - ([8.0, 9.0, 7.0] + [5.0, 6.0, 4.0]) = [7.0, 7.0, 7.0] + # Imported: 1000 - (150 + 300) = 550 + # Exported: 500 - (0 + 100) = 400 + + expected_state = CounterState( + power=3000, + currents=[7.0, 7.0, 7.0], + imported=550, + exported=400 + ) + + assert vars(result_state) == vars(expected_state) diff --git a/packages/modules/loadvars.py b/packages/modules/loadvars.py index f0b3815052..018032fbc1 100644 --- a/packages/modules/loadvars.py +++ b/packages/modules/loadvars.py @@ -29,9 +29,12 @@ def get_values(self) -> None: levels = data.data.counter_all_data.get_list_of_elements_per_level() levels.reverse() for level in levels: - self._update_values_of_level(level, not_finished_threads) + self._update_values_of_level_buttom_top(level, not_finished_threads) wait_for_module_update_completed(self.event_module_update_completed, topic) data.data.copy_module_data() + self._update_values_virtual_counter_uncounted_consumption(level, not_finished_threads) + wait_for_module_update_completed(self.event_module_update_completed, topic) + data.data.copy_module_data() wait_for_module_update_completed(self.event_module_update_completed, topic) joined_thread_handler(self._get_io(), data.data.general_data.data.control_interval/3) joined_thread_handler(self._set_io(), data.data.general_data.data.control_interval/3) @@ -59,8 +62,8 @@ def _set_values(self) -> List[str]: log.exception(f"Fehler im loadvars-Modul bei Element {cp.num}") return joined_thread_handler(modules_threads, data.data.general_data.data.control_interval/3) - def _update_values_of_level(self, elements, not_finished_threads: List[str]) -> None: - """Threads, um von der niedrigsten Ebene der Hierarchie Werte ggf. miteinander zu verrechnen und zu + def _update_values_of_level_buttom_top(self, elements, not_finished_threads: List[str]) -> None: + """Threads, um von der niedrigsten Ebene der Hierarchie beginnend Werte ggf. miteinander zu verrechnen und zu veröffentlichen""" modules_threads: List[Thread] = [] for element in elements: @@ -83,6 +86,23 @@ def _update_values_of_level(self, elements, not_finished_threads: List[str]) -> log.exception(f"Fehler im loadvars-Modul bei Element {element}") joined_thread_handler(modules_threads, data.data.general_data.data.control_interval/3) + def _update_values_virtual_counter_uncounted_consumption(self, not_finished_threads: List[str]) -> None: + modules_threads: List[Thread] = [] + for counter in data.data.counter_data.values(): + try: + component = get_finished_component_obj_by_id(counter.num, not_finished_threads) + if component.component_config.type == "virtual": + if len(data.data.counter_all_data.get_entry_of_element(counter.num)["children"]) == 0: + thread_name = f"component{component.component_config.id}" + if thread_name not in not_finished_threads: + modules_threads.append(Thread( + target=update_values, + args=(component,), + name=f"component{component.component_config.id}")) + except Exception: + log.exception(f"Fehler im loadvars-Modul bei Zähler {counter}") + joined_thread_handler(modules_threads, data.data.general_data.data.control_interval/3) + def _get_io(self) -> List[Thread]: threads = [] # type: List[Thread] try: From 03dfce2fe3868e50e27d110cf343531bf779e08c Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Tue, 2 Dec 2025 08:24:59 +0100 Subject: [PATCH 2/3] fix --- packages/modules/common/store/_counter.py | 42 +++++++---- .../modules/common/store/_counter_test.py | 71 ++++++------------- packages/modules/loadvars.py | 2 +- 3 files changed, 50 insertions(+), 65 deletions(-) diff --git a/packages/modules/common/store/_counter.py b/packages/modules/common/store/_counter.py index 2e07466980..2b9cbc9694 100644 --- a/packages/modules/common/store/_counter.py +++ b/packages/modules/common/store/_counter.py @@ -71,13 +71,13 @@ def calc_virtual(self, state: CounterState) -> CounterState: if self.add_child_values: self.currents = state.currents if state.currents else [0.0]*3 self.power = state.power - self.imported = state.imported - self.exported = state.exported + self.imported = state.imported if state.imported else 0 + self.exported = state.exported if state.exported else 0 self.incomplete_currents = False counter_all = data.data.counter_all_data elements = counter_all.get_elements_for_downstream_calculation(self.delegate.delegate.num) if len(elements) == 0: - return self.calc_uncounted_consumption(state) + return self.calc_uncounted_consumption() else: return self.calc_consumers(elements) else: @@ -96,11 +96,11 @@ def _add_values(self, element, calc_imported_exported: bool): if calc_imported_exported: if hasattr(element, "imported") and element.imported is not None: self.imported += element.imported - if element.exported is not None: + if hasattr(element, "exported") and element.exported is not None: self.exported += element.exported self.power += element.power - def calc_consumers(self, elements: Dict, calc_imported_exported: bool = True) -> CounterState: + def calc_consumers(self, elements: Dict, calc_imported_exported: bool = False) -> CounterState: for element in elements: try: if element["type"] == ComponentType.CHARGEPOINT.value: @@ -117,13 +117,20 @@ def calc_consumers(self, elements: Dict, calc_imported_exported: bool = True) -> f" {chargepoint.data.config.name} an die Phasen des EVU Zählers " "angegeben werden.") self.power += chargepoint_state.power + if calc_imported_exported: + self.imported += chargepoint_state.imported + self.exported += chargepoint_state.exported else: component = get_component_obj_by_id(element['id']) - self._add_values(component.store.delegate.delegate.state) + self._add_values(component.store.delegate.delegate.state, calc_imported_exported) except Exception: log.exception(f"Fehler beim Hinzufügen der Werte für Element {element}") - if calc_imported_exported: + if calc_imported_exported is False or self.imported is None or self.exported is None: + if self.imported is None and calc_imported_exported: + log.debug("Mind eine Komponente liefert keinen Zählestand für den Bezug, berechne Zählerstände") + if self.exported is None and calc_imported_exported: + log.debug("Mind eine Komponente liefert keinen Zählestand für die Einspeisung, berechne Zählerstände") self.imported, self.exported = self.sim_counter.sim_count(self.power) if self.incomplete_currents: self.currents = None @@ -133,20 +140,27 @@ def calc_consumers(self, elements: Dict, calc_imported_exported: bool = True) -> imported=self.imported) def calc_uncounted_consumption(self) -> CounterState: - parent_id = data.data.counter_all_data.get_parent_of_element(self.delegate.delegate.num) + parent_id = data.data.counter_all_data.get_entry_of_parent(self.delegate.delegate.num)["id"] parent_component = get_component_obj_by_id(parent_id) if "counter" not in parent_component.component_config.type: raise Exception("Die übergeordnete Komponente des virtuellen Zählers muss ein Zähler sein.") if parent_component.store.add_child_values: - raise Exception("Der übergeordnete Zähler des virtuellen Zählers darf nicht auch ein virtueller Zähler sein.") + raise Exception("Der übergeordnete Zähler des virtuellen Zählers darf nicht " + "auch ein virtueller Zähler sein.") elements = data.data.counter_all_data.get_elements_for_downstream_calculation(parent_id) - counter_state_consumers = self.calc_consumers(elements, calc_imported_exported=True) + # entferne den eigenen Zähler aus der Liste + elements = [el for el in elements if el["id"] != self.delegate.delegate.num] + self.calc_consumers(elements, calc_imported_exported=True) + log.debug(f"Erfasster Verbrauch virtueller Zähler {self.delegate.delegate.num}: " + f"{self.currents}A, {self.power}W, {self.exported}Wh, {self.imported}Wh") parent_counter_get = data.data.counter_data[f"counter{parent_id}"].data.get return CounterState( - currents=[parent_counter_get.currents[i] - counter_state_consumers.currents[i] for i in range(0, 3)], - power=parent_counter_get.power - counter_state_consumers.power, - exported=parent_counter_get.exported - counter_state_consumers.exported, - imported=parent_counter_get.imported - counter_state_consumers.imported + currents=[parent_counter_get.currents[i] - self.currents[i] + for i in range(0, 3)] if self.currents is not None else None, + power=parent_counter_get.power - self.power, + exported=0, + imported=(parent_counter_get.imported + self.exported - self.imported - + parent_counter_get.exported) if self.imported is not None else None ) diff --git a/packages/modules/common/store/_counter_test.py b/packages/modules/common/store/_counter_test.py index 41830d9349..b9c8c292d8 100644 --- a/packages/modules/common/store/_counter_test.py +++ b/packages/modules/common/store/_counter_test.py @@ -148,31 +148,40 @@ def test_calc_uncounted_consumption(monkeypatch): - Virtueller Zähler: id=3 (soll nicht-gezählten Verbrauch berechnen) Hierarchie: - Counter 0 (parent, 8000W total) - ├── Chargepoint 1 (3000W) - ├── Counter 2 (2000W) - └── Virtual Counter 3 (uncounted: 8000 - 3000 - 2000 = 3000W) + Counter 0 (parent, 8000W, 1kWh importiert, 0.5kWh exportiert) + ├── Chargepoint 1 (3000W, 150Wh importiert, 0Wh exportiert) + ├── Counter 2 (2000W, 300Wh importiert, 100Wh exportiert) + └── Virtual Counter 3 (uncounted: 8000 - 3000 - 2000 = 3000W, 0.15kWh imp, 0kWh exp) """ # setup data.data_init(Mock()) data.data.counter_all_data = CounterAll() + data.data.counter_all_data.data.get.hierarchy = [ + { + "id": 0, + "type": "counter", + "children": [ + {"id": 1, "type": "cp", "children": []}, + {"id": 2, "type": "counter", "children": []}, + {"id": 3, "type": "counter", "children": []} + ] + } + ] - # Setup parent counter (id=0) auf übergeordneter Ebene data.data.counter_data["counter0"] = Mock( spec=Counter, data=Mock( spec=CounterData, get=Mock( spec=Get, - power=8000, # Gesamtverbrauch + power=8000, exported=500, imported=1000, - currents=[20.0, 22.0, 18.0] # Gesamtstrom + currents=[20.0, 22.0, 18.0] ) ) ) - # Setup Ladepunkt (id=1) auf gleicher Ebene wie virtueller Zähler add_chargepoint(1) data.data.cp_data["cp1"].data.get.power = 3000 data.data.cp_data["cp1"].data.get.currents = [8.0, 9.0, 7.0] @@ -181,7 +190,6 @@ def test_calc_uncounted_consumption(monkeypatch): data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.imported = 150 data.data.cp_data["cp1"].chargepoint_module.store.delegate.state.exported = 0 - # Setup weiterer Zähler (id=2) auf gleicher Ebene data.data.counter_data["counter2"] = Mock( spec=Counter, data=Mock( @@ -196,46 +204,10 @@ def test_calc_uncounted_consumption(monkeypatch): ) ) - # Hierarchie: Parent Counter 0 hat Kinder: CP 1, Counter 2, Virtual Counter 3 - data.data.counter_all_data.data.get.hierarchy = [ - { - "id": 0, - "type": "counter", - "children": [ - {"id": 1, "type": "cp", "children": []}, - {"id": 2, "type": "counter", "children": []}, - {"id": 3, "type": "counter", "children": []} # Virtual counter - ] - } - ] - - # Mock für Parent-Lookup - def mock_get_parent_of_element(element_id): - if element_id == 3: # Virtual counter - return 0 # Parent counter - return None - - # Mock für get_elements_for_downstream_calculation - def mock_get_elements_for_downstream_calculation(parent_id): - if parent_id == 0: # Parent counter - return [ - {"id": 1, "type": "cp"}, - {"id": 2, "type": "counter"} - # Virtual counter 3 wird nicht in eigene Berechnung einbezogen - ] - return [] - - data.data.counter_all_data.get_parent_of_element = Mock(side_effect=mock_get_parent_of_element) - data.data.counter_all_data.get_elements_for_downstream_calculation = Mock( - side_effect=mock_get_elements_for_downstream_calculation - ) - - # Mock parent counter component parent_counter_component = Mock() parent_counter_component.component_config.type = "counter" - parent_counter_component.store.add_child_values = False # Nicht virtuell + parent_counter_component.store.add_child_values = False - # Mock regular counter component (id=2) regular_counter_component = Mock( spec=MqttCounter, store=Mock( @@ -264,7 +236,6 @@ def mock_get_component_obj_by_id(component_id): monkeypatch.setattr(_counter, "get_component_obj_by_id", mock_get_component_obj_by_id) - # Setup virtual counter (id=3) virtual_counter_purge = PurgeCounterState( delegate=Mock(delegate=Mock(num=3)), add_child_values=True, @@ -272,7 +243,7 @@ def mock_get_component_obj_by_id(component_id): ) # execution - result_state = virtual_counter_purge.calc_uncounted_consumption() + result_state = virtual_counter_purge.calc_virtual(CounterState()) # evaluation # Erwartete Werte: Parent Counter - (Chargepoint + Regular Counter) @@ -284,8 +255,8 @@ def mock_get_component_obj_by_id(component_id): expected_state = CounterState( power=3000, currents=[7.0, 7.0, 7.0], - imported=550, - exported=400 + imported=150, + exported=0 ) assert vars(result_state) == vars(expected_state) diff --git a/packages/modules/loadvars.py b/packages/modules/loadvars.py index 018032fbc1..76009ec8f2 100644 --- a/packages/modules/loadvars.py +++ b/packages/modules/loadvars.py @@ -32,7 +32,7 @@ def get_values(self) -> None: self._update_values_of_level_buttom_top(level, not_finished_threads) wait_for_module_update_completed(self.event_module_update_completed, topic) data.data.copy_module_data() - self._update_values_virtual_counter_uncounted_consumption(level, not_finished_threads) + self._update_values_virtual_counter_uncounted_consumption(not_finished_threads) wait_for_module_update_completed(self.event_module_update_completed, topic) data.data.copy_module_data() wait_for_module_update_completed(self.event_module_update_completed, topic) From 0a7868d33dadb58fdfdc25e966f6ba4faf0dde86 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Tue, 2 Dec 2025 08:32:34 +0100 Subject: [PATCH 3/3] flake8 --- packages/modules/common/store/_counter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/modules/common/store/_counter.py b/packages/modules/common/store/_counter.py index 2b9cbc9694..5e97045b6d 100644 --- a/packages/modules/common/store/_counter.py +++ b/packages/modules/common/store/_counter.py @@ -140,6 +140,9 @@ def calc_consumers(self, elements: Dict, calc_imported_exported: bool = False) - imported=self.imported) def calc_uncounted_consumption(self) -> CounterState: + """Berechnet den nicht-gezählten Verbrauch für einen virtuellen Zähler. + Dazu wird der Zählerstand des übergeordneten Zählers herangezogen und davon die + Werte aller anderen untergeordneten Komponenten abgezogen.""" parent_id = data.data.counter_all_data.get_entry_of_parent(self.delegate.delegate.num)["id"] parent_component = get_component_obj_by_id(parent_id) if "counter" not in parent_component.component_config.type: