Skip to content

Commit 1eb05a3

Browse files
committed
Adapt devices to config.
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
1 parent 64fab24 commit 1eb05a3

File tree

3 files changed

+178
-34
lines changed

3 files changed

+178
-34
lines changed

src/akkudoktoreos/devices/battery.py

+79-20
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
import numpy as np
44
from pydantic import BaseModel, Field, field_validator
55

6+
from akkudoktoreos.devices.devicesabc import DeviceBase
7+
from akkudoktoreos.utils.logutil import get_logger
68
from akkudoktoreos.utils.utils import NumpyEncoder
79

10+
logger = get_logger(__name__)
11+
812

913
def max_ladeleistung_w_field(default: Optional[float] = None) -> Optional[float]:
1014
return Field(
@@ -83,31 +87,86 @@ def convert_numpy(cls, field: Any) -> Any:
8387
return NumpyEncoder.convert_numpy(field)[0]
8488

8589

86-
class PVAkku:
87-
def __init__(self, parameters: BaseAkkuParameters, hours: int = 24):
88-
# Battery capacity in Wh
89-
self.kapazitaet_wh = parameters.kapazitaet_wh
90-
# Initial state of charge in Wh
91-
self.start_soc_prozent = parameters.start_soc_prozent
92-
self.soc_wh = (parameters.start_soc_prozent / 100) * parameters.kapazitaet_wh
93-
self.hours = hours
90+
class PVAkku(DeviceBase):
91+
def __init__(
92+
self,
93+
parameters: Optional[BaseAkkuParameters] = None,
94+
hours: Optional[int] = 24,
95+
provider_id: Optional[str] = None,
96+
):
97+
# Configuration initialisation
98+
self.provider_id = provider_id
99+
self.prefix = "<invalid>"
100+
if self.provider_id == "GenericBattery":
101+
self.prefix = "battery"
102+
elif self.provider_id == "GenericBEV":
103+
self.prefix = "bev"
104+
# Parameter initialisiation
105+
self.parameters = parameters
106+
if hours is None:
107+
self.hours = self.total_hours
108+
else:
109+
self.hours = hours
110+
111+
self.initialised = False
112+
# Run setup if parameters are given, otherwise setup() has to be called later when the config is initialised.
113+
if self.parameters is not None:
114+
self.setup()
115+
116+
def setup(self) -> None:
117+
if self.initialised:
118+
return
119+
if self.provider_id is not None:
120+
# Setup by configuration
121+
# Battery capacity in Wh
122+
self.kapazitaet_wh = getattr(self.config, f"{self.prefix}_capacity")
123+
# Initial state of charge in Wh
124+
self.start_soc_prozent = getattr(self.config, f"{self.prefix}_soc_start")
125+
self.hours = self.total_hours
126+
# Charge and discharge efficiency
127+
self.lade_effizienz = getattr(self.config, f"{self.prefix}_charge_efficiency")
128+
self.entlade_effizienz = getattr(self.config, f"{self.prefix}_discharge_efficiency")
129+
self.max_ladeleistung_w = getattr(self.config, f"{self.prefix}_charge_power_max")
130+
# Only assign for storage battery
131+
if self.provider_id == "GenericBattery":
132+
self.min_soc_prozent = getattr(self.config, f"{self.prefix}_soc_mint")
133+
else:
134+
self.min_soc_prozent = 0
135+
self.max_soc_prozent = getattr(self.config, f"{self.prefix}_soc_mint")
136+
elif self.parameters is not None:
137+
# Setup by parameters
138+
# Battery capacity in Wh
139+
self.kapazitaet_wh = self.parameters.kapazitaet_wh
140+
# Initial state of charge in Wh
141+
self.start_soc_prozent = self.parameters.start_soc_prozent
142+
# Charge and discharge efficiency
143+
self.lade_effizienz = self.parameters.lade_effizienz
144+
self.entlade_effizienz = self.parameters.entlade_effizienz
145+
self.max_ladeleistung_w = self.parameters.max_ladeleistung_w
146+
# Only assign for storage battery
147+
self.min_soc_prozent = (
148+
self.parameters.min_soc_prozent
149+
if isinstance(self.parameters, PVAkkuParameters)
150+
else 0
151+
)
152+
self.max_soc_prozent = self.parameters.max_soc_prozent
153+
else:
154+
error_msg = "Parameters and provider ID missing. Can't instantiate."
155+
logger.error(error_msg)
156+
raise ValueError(error_msg)
157+
158+
# init
159+
if self.max_ladeleistung_w is None:
160+
self.max_ladeleistung_w = self.kapazitaet_wh
94161
self.discharge_array = np.full(self.hours, 1)
95162
self.charge_array = np.full(self.hours, 1)
96-
# Charge and discharge efficiency
97-
self.lade_effizienz = parameters.lade_effizienz
98-
self.entlade_effizienz = parameters.entlade_effizienz
99-
self.max_ladeleistung_w = (
100-
parameters.max_ladeleistung_w if parameters.max_ladeleistung_w else self.kapazitaet_wh
101-
)
102-
# Only assign for storage battery
103-
self.min_soc_prozent = (
104-
parameters.min_soc_prozent if isinstance(parameters, PVAkkuParameters) else 0
105-
)
106-
self.max_soc_prozent = parameters.max_soc_prozent
107-
# Calculate min and max SoC in Wh
163+
# Calculate start, min and max SoC in Wh
164+
self.soc_wh = (self.start_soc_prozent / 100) * self.kapazitaet_wh
108165
self.min_soc_wh = (self.min_soc_prozent / 100) * self.kapazitaet_wh
109166
self.max_soc_wh = (self.max_soc_prozent / 100) * self.kapazitaet_wh
110167

168+
self.initialised = True
169+
111170
def to_dict(self) -> dict[str, Any]:
112171
return {
113172
"kapazitaet_wh": self.kapazitaet_wh,

src/akkudoktoreos/devices/generic.py

+52-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
from typing import Optional
2+
13
import numpy as np
24
from pydantic import BaseModel, Field
35

6+
from akkudoktoreos.devices.devicesabc import DeviceBase
7+
from akkudoktoreos.utils.logutil import get_logger
8+
9+
logger = get_logger(__name__)
10+
411

512
class HomeApplianceParameters(BaseModel):
613
consumption_wh: int = Field(
@@ -13,21 +20,57 @@ class HomeApplianceParameters(BaseModel):
1320
)
1421

1522

16-
class HomeAppliance:
17-
def __init__(self, parameters: HomeApplianceParameters, hours: int = 24):
18-
self.hours = hours # Total duration for which the planning is done
19-
self.consumption_wh = (
20-
parameters.consumption_wh
21-
) # Total energy consumption of the device in kWh
22-
self.duration_h = parameters.duration_h # Duration of use in hours
23+
class HomeAppliance(DeviceBase):
24+
def __init__(
25+
self,
26+
parameters: Optional[HomeApplianceParameters] = None,
27+
hours: Optional[int] = 24,
28+
provider_id: Optional[str] = None,
29+
):
30+
# Configuration initialisation
31+
self.provider_id = provider_id
32+
self.prefix = "<invalid>"
33+
if self.provider_id == "GenericDishWasher":
34+
self.prefix = "dishwasher"
35+
# Parameter initialisiation
36+
self.parameters = parameters
37+
if hours is None:
38+
self.hours = self.total_hours
39+
else:
40+
self.hours = hours
41+
42+
self.initialised = False
43+
# Run setup if parameters are given, otherwise setup() has to be called later when the config is initialised.
44+
if self.parameters is not None:
45+
self.setup()
46+
47+
def setup(self) -> None:
48+
if self.initialised:
49+
return
50+
if self.provider_id is not None:
51+
# Setup by configuration
52+
self.hours = self.total_hours
53+
self.consumption_wh = getattr(self.config, f"{self.prefix}_consumption")
54+
self.duration_h = getattr(self.config, f"{self.prefix}_duration")
55+
elif self.parameters is not None:
56+
# Setup by parameters
57+
self.consumption_wh = (
58+
self.parameters.consumption_wh
59+
) # Total energy consumption of the device in kWh
60+
self.duration_h = self.parameters.duration_h # Duration of use in hours
61+
else:
62+
error_msg = "Parameters and provider ID missing. Can't instantiate."
63+
logger.error(error_msg)
64+
raise ValueError(error_msg)
2365
self.load_curve = np.zeros(self.hours) # Initialize the load curve with zeros
66+
self.initialised = True
2467

2568
def set_starting_time(self, start_hour: int, global_start_hour: int = 0) -> None:
2669
"""Sets the start time of the device and generates the corresponding load curve.
2770
2871
:param start_hour: The hour at which the device should start.
2972
"""
30-
self.reset()
73+
self.reset_load_curve()
3174
# Check if the duration of use is within the available time frame
3275
if start_hour + self.duration_h > self.hours:
3376
raise ValueError("The duration of use exceeds the available time frame.")
@@ -40,7 +83,7 @@ def set_starting_time(self, start_hour: int, global_start_hour: int = 0) -> None
4083
# Set the power for the duration of use in the load curve array
4184
self.load_curve[start_hour : start_hour + self.duration_h] = power_per_hour
4285

43-
def reset(self) -> None:
86+
def reset_load_curve(self) -> None:
4487
"""Resets the load curve."""
4588
self.load_curve = np.zeros(self.hours)
4689

src/akkudoktoreos/devices/inverter.py

+47-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,61 @@
1+
from typing import Optional
2+
13
from pydantic import BaseModel, Field
24

35
from akkudoktoreos.devices.battery import PVAkku
6+
from akkudoktoreos.devices.devicesabc import DeviceBase
7+
from akkudoktoreos.utils.logutil import get_logger
8+
9+
logger = get_logger(__name__)
410

511

612
class WechselrichterParameters(BaseModel):
713
max_leistung_wh: float = Field(default=10000, gt=0)
814

915

10-
class Wechselrichter:
11-
def __init__(self, parameters: WechselrichterParameters, akku: PVAkku):
12-
self.max_leistung_wh = (
13-
parameters.max_leistung_wh # Maximum power that the inverter can handle
14-
)
16+
class Wechselrichter(DeviceBase):
17+
def __init__(
18+
self,
19+
parameters: Optional[WechselrichterParameters] = None,
20+
akku: Optional[PVAkku] = None,
21+
provider_id: Optional[str] = None,
22+
):
23+
# Configuration initialisation
24+
self.provider_id = provider_id
25+
self.prefix = "<invalid>"
26+
if self.provider_id == "GenericInverter":
27+
self.prefix = "inverter"
28+
# Parameter initialisiation
29+
self.parameters = parameters
30+
if akku is None:
31+
# For the moment raise exception
32+
# TODO: Make akku configurable by config
33+
error_msg = "Battery for PV inverter is mandatory."
34+
logger.error(error_msg)
35+
raise NotImplementedError(error_msg)
1536
self.akku = akku # Connection to a battery object
1637

38+
self.initialised = False
39+
# Run setup if parameters are given, otherwise setup() has to be called later when the config is initialised.
40+
if self.parameters is not None:
41+
self.setup()
42+
43+
def setup(self) -> None:
44+
if self.initialised:
45+
return
46+
if self.provider_id is not None:
47+
# Setup by configuration
48+
self.max_leistung_wh = getattr(self.config, f"{self.prefix}_power_max")
49+
elif self.parameters is not None:
50+
# Setup by parameters
51+
self.max_leistung_wh = (
52+
self.parameters.max_leistung_wh # Maximum power that the inverter can handle
53+
)
54+
else:
55+
error_msg = "Parameters and provider ID missing. Can't instantiate."
56+
logger.error(error_msg)
57+
raise ValueError(error_msg)
58+
1759
def energie_verarbeiten(
1860
self, erzeugung: float, verbrauch: float, hour: int
1961
) -> tuple[float, float, float, float]:

0 commit comments

Comments
 (0)