diff --git a/packages/control/consumer/consumer.py b/packages/control/consumer/consumer.py index fa5f5e0343..547890a80c 100644 --- a/packages/control/consumer/consumer.py +++ b/packages/control/consumer/consumer.py @@ -526,3 +526,12 @@ def set_mode_changed(self, submode: Chargemode, mode: Optional[Chargemode]) -> N self.reset_wait_for_start() else: self.chargemode_changed = False + + def set_plug_state(self): + if self.data.usage.type in NOT_CONTROLLED: + if self.data.get.power == 0: + self.data.get.plug_state = False + else: + self.data.get.plug_state = True + else: + self.data.get.plug_state = self.data.set.current > 0 diff --git a/packages/control/consumer/consumer_data.py b/packages/control/consumer/consumer_data.py index 482a1a7ce7..9bd5493a8c 100644 --- a/packages/control/consumer/consumer_data.py +++ b/packages/control/consumer/consumer_data.py @@ -62,7 +62,7 @@ class ConsumerConfig: @dataclass class Get: - charge_state: bool = False + charge_state: bool = field(default=False, metadata={"topic": "get/charge_state"}) currents: List[float] = field(default_factory=currents_list_factory) daily_imported: float = field(default=0, metadata={"topic": "get/daily_imported"}) error_timestamp: int = 0 @@ -71,6 +71,7 @@ class Get: fault_state: int = 0 imported: float = 0 phases_in_use: int = 0 + plug_state: bool = field(default=False, metadata={"topic": "get/plug_state"}) power: float = 0 powers: Optional[List[Optional[float]]] = None set_power: Optional[float] = None diff --git a/packages/control/consumer/consumer_test.py b/packages/control/consumer/consumer_test.py index e0f8b47c1b..b08cfa0f8a 100644 --- a/packages/control/consumer/consumer_test.py +++ b/packages/control/consumer/consumer_test.py @@ -36,6 +36,60 @@ def consumer() -> Consumer: return load +@pytest.mark.parametrize( + "usage_type, power, expected_plug_state", + [ + pytest.param(ConsumerUsage.METER_ONLY, 0, False, id="meter-only-zero-power"), + pytest.param(ConsumerUsage.METER_ONLY, 1, True, id="meter-only-nonzero-power"), + pytest.param(ConsumerUsage.SELF_CONTROLLED, 0, False, id="self-controlled-zero-power"), + pytest.param(ConsumerUsage.SELF_CONTROLLED, 1, True, id="self-controlled-nonzero-power"), + ], +) +def test_set_plug_state_for_not_controlled_consumers( + consumer: Consumer, + usage_type: ConsumerUsage, + power: float, + expected_plug_state: bool): + # setup + consumer.data.usage.type = usage_type + consumer.data.get.power = power + consumer.data.set.current = 0 + + # execution + consumer.set_plug_state() + + # evaluation + assert consumer.data.get.plug_state is expected_plug_state + + +@pytest.mark.parametrize( + "usage_type, current, expected_plug_state", + [ + pytest.param(ConsumerUsage.CONTINUOUS, 0, False, id="continuous-zero-current"), + pytest.param(ConsumerUsage.CONTINUOUS, 1, True, id="continuous-positive-current"), + pytest.param(ConsumerUsage.SUSPENDABLE_ONOFF, 0, False, id="onoff-zero-current"), + pytest.param(ConsumerUsage.SUSPENDABLE_ONOFF, 1, True, id="onoff-positive-current"), + pytest.param(ConsumerUsage.SUSPENDABLE_TUNABLE, 0, False, id="tunable-zero-current"), + pytest.param(ConsumerUsage.SUSPENDABLE_TUNABLE, 1, True, id="tunable-positive-current"), + ], +) +def test_set_plug_state_for_controlled_consumers( + consumer: Consumer, + usage_type: ConsumerUsage, + current: float, + expected_plug_state: bool): + # setup + consumer.data.usage.type = usage_type + consumer.data.get.power = 0 + consumer.data.set.current = current + + # execution + consumer.set_plug_state() + + # evaluation + assert consumer.data.get.plug_state is expected_plug_state + + def test_get_parameter_clears_previous_state_string_when_switch_interval_is_active(consumer: Consumer): # setup consumer.data.set.switch_interval_elapsed = False diff --git a/packages/control/process.py b/packages/control/process.py index edacc92f49..7d5e403a93 100644 --- a/packages/control/process.py +++ b/packages/control/process.py @@ -92,6 +92,7 @@ def process_algorithm_results(self) -> None: consumer.data.get.state_str = self._prepend_state_message( "Strom freigegeben, warten auf Verbraucher.", consumer.data.get.state_str) + consumer.set_plug_state() consumer_thread = self._start_consumer(consumer) if consumer_thread is not None: modules_threads.append(consumer_thread) diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index d67736b248..276a5bd89d 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -1286,7 +1286,9 @@ def process_consumer_topic(self, msg): re.search("consumer/[0-9]+/get/state_str$", msg.topic) is not None or re.search("consumer/[0-9]+/set/wait_for_start_state$", msg.topic) is not None): self._validate_value(msg, str) - elif re.search("consumer/[0-9]+/get/state$", msg.topic) is not None: + elif (re.search("consumer/[0-9]+/get/charge_state$", msg.topic) is not None or + re.search("consumer/[0-9]+/get/plug_state$", msg.topic) is not None or + re.search("consumer/[0-9]+/get/state$", msg.topic) is not None): self._validate_value(msg, bool) elif re.search("consumer/[0-9]+/set/phases_to_use$", msg.topic) is not None: self._validate_value(msg, int, [(0, 3)]) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index d96d97a2bb..210e3c041f 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -204,9 +204,11 @@ class UpdateConfig: "^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/charge_state$", "^openWB/consumer/[0-9]+/get/currents$", "^openWB/consumer/[0-9]+/get/fault_state$", "^openWB/consumer/[0-9]+/get/fault_str$", + "^openWB/consumer/[0-9]+/get/plug_state$", "^openWB/consumer/[0-9]+/get/powers$", "^openWB/consumer/[0-9]+/get/power$", "^openWB/consumer/[0-9]+/get/state$",