diff --git a/packages/control/consumer/consumer_data.py b/packages/control/consumer/consumer_data.py index e7212a1ae9..e72a63512d 100644 --- a/packages/control/consumer/consumer_data.py +++ b/packages/control/consumer/consumer_data.py @@ -64,6 +64,7 @@ class ConsumerConfig: max_power: float = 5000 min_current: float = 0.5 min_interval: int = 60 + is_home_consumption_consumer: str = "auto_home_consumption" @dataclass diff --git a/packages/control/counter_all/counter_all.py b/packages/control/counter_all/counter_all.py index 88d04e968d..8c5e10c80e 100644 --- a/packages/control/counter_all/counter_all.py +++ b/packages/control/counter_all/counter_all.py @@ -78,6 +78,8 @@ def _get_component(self, element: Dict) -> Any: return data.data.counter_data[f"counter{element['id']}"] elif element["type"] == ComponentType.CHARGEPOINT.value: return data.data.cp_data[f"cp{element['id']}"] + elif element["type"] == ComponentType.CONSUMER.value: + return data.data.consumer_data[f"consumer{element['id']}"] elif element["type"] == ComponentType.BAT.value: return data.data.bat_data[f"bat{element['id']}"] elif element["type"] == ComponentType.INVERTER.value: @@ -93,6 +95,13 @@ def _get_is_home_consumption(self, counter: Counter, parent_home_consumption: st return counter.data.config.is_home_consumption_counter + def _get_is_home_consumption_consumer(self, consumer: Any, parent_home_consumption: str) -> str: + consumer_mode = getattr(consumer.data.config, "is_home_consumption_consumer", + CounterMode.AUTO_HOME_CONSUMPTION.value) + if consumer_mode == CounterMode.AUTO_HOME_CONSUMPTION.value: + return parent_home_consumption + return consumer_mode + def _get_local_power_from_counter(self, element: Dict) -> float: # Wird nur von Countern aufgerufen # Gib den lokalen Verbrauch des Zählers zurück @@ -131,6 +140,10 @@ def _calc_home_consumption_from_counter( if comp.data.get.fault_state < 2: if child["type"] == ComponentType.COUNTER.value: home_consumption += self._calc_home_consumption_from_counter(child, child_home_consumption) + elif child["type"] == ComponentType.CONSUMER.value: + if self._get_is_home_consumption_consumer( + comp, child_home_consumption) == CounterMode.HOME_CONSUMPTION.value: + home_consumption += comp.data.get.power else: log.warning( f"Komponente {element['type']}{comp.num} ist im Fehlerzustand und wird nicht berücksichtigt.") diff --git a/packages/control/counter_all/counter_home_consumption_test.py b/packages/control/counter_all/counter_home_consumption_test.py index cdc7b8ef50..c6b01c52f1 100644 --- a/packages/control/counter_all/counter_home_consumption_test.py +++ b/packages/control/counter_all/counter_home_consumption_test.py @@ -95,6 +95,53 @@ def test_set_home_consumption(home_consumption: int, assert c.data.set.home_consumption == expected_home_consumption +@pytest.mark.parametrize( + ["counter_mode", "consumer_mode", "expected_home_consumption"], + [ + pytest.param(CounterMode.HOME_CONSUMPTION.value, "auto_home_consumption", 1000, + id="consumer_auto_inherits_home"), + pytest.param(CounterMode.HOME_CONSUMPTION.value, "no_home_consumption", 700, + id="consumer_explicit_no_home"), + pytest.param(CounterMode.NOT_HOME_CONSUMPTION.value, "home_consumption", 300, + id="consumer_explicit_home_overrides_parent"), + ], +) +def test_calc_home_consumption_with_consumer_modes(counter_mode: str, + consumer_mode: str, + expected_home_consumption: int): + data.data_init(Mock()) + c = CounterAll() + c.data.get.hierarchy = [{ + "id": 0, + "type": "counter", + "children": [{"id": 7, "type": "consumer", "children": []}], + }] + + data.data.counter_data = { + "counter0": Mock( + spec=Counter, + num=0, + data=Mock( + spec=CounterData, + get=Mock(spec=CounterGet, power=1000, fault_state=0), + config=Mock(spec=CounterConfig, is_home_consumption_counter=counter_mode), + ), + ), + } + data.data.consumer_data = { + "consumer7": Mock( + num=7, + data=Mock( + get=Mock(power=300, fault_state=0), + config=Mock(is_home_consumption_consumer=consumer_mode), + ), + ), + } + + home_consumption = c._calc_home_consumption()[0] + assert home_consumption == expected_home_consumption + + def hierarchy_home_consumption_standard() -> CounterAll: # counter0 # | diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 4ee2e58581..c45fed4354 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -58,7 +58,7 @@ class UpdateConfig: - DATASTORE_VERSION = 145 + DATASTORE_VERSION = 146 valid_topic = [ "^openWB/bat/config/bat_control_activated$", @@ -194,6 +194,7 @@ class UpdateConfig: "^openWB/consumer/get/daily_imported$", "^openWB/consumer/[0-9]+/module$", "^openWB/consumer/[0-9]+/config$", + "^openWB/consumer/[0-9]+/config/is_home_consumption_consumer$", "^openWB/consumer/[0-9]+/extra_meter$", "^openWB/consumer/[0-9]+/usage$", "^openWB/consumer/[0-9]+/get/currents$", @@ -3802,3 +3803,19 @@ def upgrade(topic: str, payload) -> Optional[dict]: "Direkte Kind-Zaehler des bisherigen Hausverbrauchs-Zaehlers wurden nicht angepasst." ) self._append_datastore_version(145) + + def upgrade_datastore_146(self) -> None: + def upgrade(topic: str, payload) -> Optional[dict]: + if re.search(r"^openWB/consumer/[0-9]+/config$", topic) is not None: + config_payload = decode_payload(payload) + if ( + isinstance(config_payload, dict) + and "is_home_consumption_consumer" not in config_payload + ): + updated_payload = config_payload + updated_payload["is_home_consumption_consumer"] = CounterMode.AUTO_HOME_CONSUMPTION.value + return {topic: updated_payload} + return None + + self._loop_all_received_topics(upgrade) + self._append_datastore_version(146)