Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions data/config/mosquitto/public/default-dynamic-security.json
Original file line number Diff line number Diff line change
Expand Up @@ -1498,31 +1498,31 @@
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/counter/config/home_consumption_source_id",
"topic": "openWB/set/counter/config/consider_less_charging",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/counter/config/consider_less_charging",
"topic": "openWB/set/counter/get/hierarchy",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/counter/get/hierarchy",
"topic": "openWB/set/counter/+/config/max_power_errorcase",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/counter/+/config/max_power_errorcase",
"topic": "openWB/set/counter/+/config/max_currents",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/counter/+/config/max_currents",
"topic": "openWB/set/counter/+/config/is_home_consumption_counter",
"priority": 0,
"allow": true
},
Expand Down Expand Up @@ -1550,12 +1550,6 @@
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/counter/config/home_consumption_source_id",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/counter/config/consider_less_charging",
Expand Down Expand Up @@ -1586,6 +1580,12 @@
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/counter/+/config/is_home_consumption_counter",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/counter/+/config/max_total_power",
Expand Down
5 changes: 3 additions & 2 deletions packages/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ def data_() -> None:
fault_state=0), config=Mock(spec=PvConfig, max_ac_out=10000)))})
data.data.counter_data.update({
"counter0": Mock(spec=Counter, data=Mock(spec=CounterData, get=Mock(
spec=CounterGet, currents=[40]*3, power=6200, daily_imported=45000, daily_exported=3000, fault_state=0))),
spec=CounterGet, currents=[40]*3, power=6200, daily_imported=45000, daily_exported=3000, fault_state=0),
config=Mock(spec=CounterConfig, is_home_consumption_counter=True))),
"counter6": Mock(spec=Counter, data=Mock(spec=CounterData, get=Mock(
spec=CounterGet, currents=[25, 10, 25], power=13800, daily_imported=20000, daily_exported=0,
imported=14000, exported=18000, fault_state=0),
config=Mock(spec=CounterConfig, max_currents=[32]*3),
config=Mock(spec=CounterConfig, max_currents=[32]*3, is_home_consumption_counter=False),
set=Mock(spec=CounterSet, raw_currents_left=[31]*3)))})


Expand Down
8 changes: 5 additions & 3 deletions packages/control/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def get_counter_default_config():
return {"max_power_errorcase": 7000,
"max_currents": [35]*3,
"max_total_power": 24000,
"is_home_consumption_counter": False
}


Expand All @@ -38,10 +39,11 @@ class ControlRangeState(Enum):

@dataclass
class Config:
max_power_errorcase: float = field(default=7000, metadata={"topic": "get/max_power_errorcase"})
max_power_errorcase: float = field(default=7000, metadata={"topic": "config/max_power_errorcase"})
max_currents: List[float] = field(default_factory=currents_list_factory, metadata={
"topic": "get/max_currents"})
max_total_power: float = field(default=0, metadata={"topic": "get/max_total_power"})
"topic": "config/max_currents"})
max_total_power: float = field(default=0, metadata={"topic": "config/max_total_power"})
is_home_consumption_counter: bool = field(default=False, metadata={"topic": "config/is_home_consumption_counter"})


def config_factory() -> Config:
Expand Down
125 changes: 84 additions & 41 deletions packages/control/counter_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
from dataclasses import dataclass, field
import logging
import re
from typing import Callable, Dict, List, Optional, Tuple, Union
from typing import Callable, Dict, List, Tuple, Union

from control import data
from control.counter import Counter
from dataclass_utils.factories import empty_list_factory
from helpermodules.messaging import MessageType, pub_system_message
from helpermodules.pub import Pub
from modules.common.component_type import ComponentType, component_type_to_readable_text
from modules.common.fault_state import FaultStateLevel
from modules.common.simcount import SimCounter
Expand All @@ -20,8 +19,6 @@

@dataclass
class Config:
home_consumption_source_id: Optional[str] = field(
default=None, metadata={"topic": "config/home_consumption_source_id"})
consider_less_charging: bool = field(
default=False, metadata={"topic": "config/consider_less_charging"})

Expand Down Expand Up @@ -101,15 +98,11 @@ def get_id_evu_counter(self) -> int:

def set_home_consumption(self) -> None:
try:
self._validate_home_consumption_counter()
home_consumption, elements = self._calc_home_consumption()
if home_consumption < 0:
log.error(
f"Ungültiger Hausverbrauch: {home_consumption}W, Berücksichtigte Komponenten neben EVU {elements}")
if self.data.config.home_consumption_source_id is None:
hc_counter_source = self.get_evu_counter_str()
else:
hc_counter_source = f"counter{self.data.config.home_consumption_source_id}"
hc_counter_source = self.get_evu_counter_str()
hc_counter_data = data.data.counter_data[hc_counter_source].data
if hc_counter_data.get.fault_state == FaultStateLevel.NO_ERROR:
hc_counter_data.get.fault_state = FaultStateLevel.WARNING.value
Expand All @@ -130,49 +123,99 @@ def set_home_consumption(self) -> None:
except Exception:
log.exception("Fehler in der allgemeinen Zähler-Klasse")

EVU_IS_HC_COUNTER_ERROR = ("Der EVU-Zähler kann nicht als Quelle für den Hausverbrauch verwendet werden. Meist ist "
"der Zähler am EVU-Punkt installiert, dann muss im Lastmanagement unter Hausverbrauch"
" 'von openWB berechnen' ausgewählt werden. Wenn der Zähler im Hausverbrauchszweig "
"installiert ist, einen virtuellen Zähler anlegen und im Lastmanagement ganz links "
"anordnen.")

def _validate_home_consumption_counter(self):
if self.data.config.home_consumption_source_id is not None:
if self.data.config.home_consumption_source_id == self.get_id_evu_counter():
hc_counter_data = data.data.counter_data[self.get_evu_counter_str()].data
hc_counter_data.get.fault_state = FaultStateLevel.ERROR.value
hc_counter_data.get.fault_str = self.EVU_IS_HC_COUNTER_ERROR
evu_counter = self.get_id_evu_counter()
Pub().pub(f"openWB/set/counter/{evu_counter}/get/fault_state",
hc_counter_data.get.fault_state)
Pub().pub(f"openWB/set/counter/{evu_counter}/get/fault_str",
hc_counter_data.get.fault_str)
raise Exception(self.EVU_IS_HC_COUNTER_ERROR)

def _calc_home_consumption(self) -> Tuple[float, List]:
power = 0
if self.data.config.home_consumption_source_id is None:
id_source = self.get_id_evu_counter()
else:
id_source = self.data.config.home_consumption_source_id
elements_to_sum_up = self.get_elements_for_downstream_calculation(id_source)
hc_all_power = 0
no_hc_all_power = 0
no_hc_evu = 0
evu_id = self.get_id_evu_counter()
elements_to_sum_up = self.get_elements_for_downstream_calculation(evu_id)

evu_is_HC = data.data.counter_data[f"counter{evu_id}"].data.config.is_home_consumption_counter

for element in elements_to_sum_up:
if element["type"] == ComponentType.CHARGEPOINT.value:
component = data.data.cp_data[f"cp{element['id']}"]
if element["type"] == ComponentType.COUNTER.value:
component = data.data.counter_data[f"counter{element['id']}"]

_hc_all_power, hc_counter = self._get_home_consumption_counter(element, evu_is_HC=evu_is_HC)
hc_all_power += _hc_all_power

for counter in hc_counter:
no_hc_all_power += self._get_no_home_consumption(counter)
continue

elif element["type"] == ComponentType.BAT.value:
component = data.data.bat_data[f"bat{element['id']}"]
elif element["type"] == ComponentType.COUNTER.value:
component = data.data.counter_data[f"counter{element['id']}"]
elif element["type"] == ComponentType.CHARGEPOINT.value:
component = data.data.cp_data[f"cp{element['id']}"]
elif element["type"] == ComponentType.INVERTER.value:
component = data.data.pv_data[f"pv{element['id']}"]

if component.data.get.fault_state < 2:
power += component.data.get.power
no_hc_evu += component.data.get.power
else:
log.warning(
f"Komponente {element['type']}{component.num} ist im Fehlerzustand und wird nicht berücksichtigt.")
evu = data.data.counter_data[f"counter{id_source}"].data.get.power
return evu - power - self.data.set.smarthome_power_excluded_from_home_consumption, elements_to_sum_up

evu_power = data.data.counter_data[f"counter{evu_id}"].data.get.power

if data.data.counter_data[f"counter{evu_id}"].data.config.is_home_consumption_counter:
return (evu_power - no_hc_all_power - no_hc_evu -
self.data.set.smarthome_power_excluded_from_home_consumption), elements_to_sum_up
else:
return (hc_all_power - no_hc_all_power -
self.data.set.smarthome_power_excluded_from_home_consumption), elements_to_sum_up

def _get_no_home_consumption(self, element) -> float:
# Summiert die Leistung aller Komponenten, die nicht als Hausverbrauch gezählt werden,
# unterhalb des angegebenen Elements.
not_home_consumption = 0
if element["type"] != ComponentType.COUNTER.value:
# Wenn kein Counter, dann get power davon -> not_home_consumption
if element["type"] == ComponentType.CHARGEPOINT.value:
component = data.data.cp_data[f"cp{element['id']}"]
elif element["type"] == ComponentType.BAT.value:
component = data.data.bat_data[f"bat{element['id']}"]
elif element["type"] == ComponentType.INVERTER.value:
component = data.data.pv_data[f"pv{element['id']}"]

if component.data.get.fault_state < 2:
not_home_consumption += component.data.get.power
Comment on lines +172 to +182

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kannst Du die Berechnung noch etwas umstrukturieren? Diesen Teil gibt es in _calc_home_consumption fast genau so schon mal, sodass es den nur einmal gibt.


return not_home_consumption

# Wenn Counter, dann get not_home_consumption von allen Children
for child in element["children"]:
not_home_consumption += self._get_no_home_consumption(child)

return not_home_consumption

def _get_home_consumption_counter(self, elements, evu_is_HC=False) -> Tuple[float, List]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bitte noch Type-Hints für die Parameter hinzufügen.

# Sucht rekursiv HC-Zähler im Teilbaum, summiert deren Leistung
# und gibt eine Liste der gefundenen HC-Zähler zurück.
# -> wenn mehrer HC-Zähler auf der selben Ebene sind

total_power = 0
hc_counters = []

if elements["type"] == ComponentType.COUNTER.value:
component = data.data.counter_data[f"counter{elements['id']}"]
if component.data.config.is_home_consumption_counter or evu_is_HC:
hc_counters.append(elements)
total_power += component.data.get.power
# Kinder nicht weiter durchsuchen,
# da deren Leistung bereits enthalten ist.
return total_power, hc_counters
else:
# Zähler kein HC -> check Kinder
# Alle durchgehen, falls ein Zähler mehrer Zähler als Kinder hat
for element in elements["children"]:
if element["type"] == ComponentType.COUNTER.value:
power, counters = self._get_home_consumption_counter(element, evu_is_HC=evu_is_HC)
total_power += power
hc_counters.extend(counters)
else:
continue
return total_power, hc_counters

def _add_hybrid_bat(self, id: int) -> List:
elements = []
Expand Down
Loading