| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  | from typing import Any, Optional | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-18 15:53:29 +01:00
										 |  |  |  | import numpy as np | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  | from pydantic import Field, field_validator | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-05 14:41:07 +01:00
										 |  |  |  | from akkudoktoreos.core.logging import get_logger | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  | from akkudoktoreos.devices.devicesabc import ( | 
					
						
							|  |  |  |  |     DeviceBase, | 
					
						
							|  |  |  |  |     DeviceOptimizeResult, | 
					
						
							|  |  |  |  |     DeviceParameters, | 
					
						
							|  |  |  |  | ) | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  | from akkudoktoreos.utils.utils import NumpyEncoder | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-15 14:40:03 +01:00
										 |  |  |  | logger = get_logger(__name__) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | def max_charging_power_field(description: Optional[str] = None) -> float: | 
					
						
							|  |  |  |  |     if description is None: | 
					
						
							|  |  |  |  |         description = "Maximum charging power in watts." | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |     return Field( | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         default=5000, | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |         gt=0, | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         description=description, | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |     ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | def initial_soc_percentage_field(description: str) -> int: | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     return Field(default=0, ge=0, le=100, description=description, examples=[42]) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def discharging_efficiency_field(default_value: float) -> float: | 
					
						
							|  |  |  |  |     return Field( | 
					
						
							|  |  |  |  |         default=default_value, | 
					
						
							|  |  |  |  |         gt=0, | 
					
						
							|  |  |  |  |         le=1, | 
					
						
							|  |  |  |  |         description="A float representing the discharge efficiency of the battery.", | 
					
						
							|  |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  | class BaseBatteryParameters(DeviceParameters): | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     """Battery Device Simulation Configuration.""" | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     device_id: str = Field(description="ID of battery", examples=["battery1"]) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     capacity_wh: int = Field( | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |         gt=0, | 
					
						
							|  |  |  |  |         description="An integer representing the capacity of the battery in watt-hours.", | 
					
						
							|  |  |  |  |         examples=[8000], | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     charging_efficiency: float = Field( | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |         default=0.88, | 
					
						
							|  |  |  |  |         gt=0, | 
					
						
							|  |  |  |  |         le=1, | 
					
						
							|  |  |  |  |         description="A float representing the charging efficiency of the battery.", | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     discharging_efficiency: float = discharging_efficiency_field(0.88) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     max_charge_power_w: Optional[float] = max_charging_power_field() | 
					
						
							|  |  |  |  |     initial_soc_percentage: int = initial_soc_percentage_field( | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |         "An integer representing the state of charge of the battery at the **start** of the current hour (not the current state)." | 
					
						
							|  |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     min_soc_percentage: int = Field( | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |         default=0, | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |         ge=0, | 
					
						
							|  |  |  |  |         le=100, | 
					
						
							|  |  |  |  |         description="An integer representing the minimum state of charge (SOC) of the battery in percentage.", | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |         examples=[10], | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     max_soc_percentage: int = Field( | 
					
						
							|  |  |  |  |         default=100, | 
					
						
							|  |  |  |  |         ge=0, | 
					
						
							|  |  |  |  |         le=100, | 
					
						
							|  |  |  |  |         description="An integer representing the maximum state of charge (SOC) of the battery in percentage.", | 
					
						
							|  |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | class SolarPanelBatteryParameters(BaseBatteryParameters): | 
					
						
							|  |  |  |  |     max_charge_power_w: Optional[float] = max_charging_power_field() | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | class ElectricVehicleParameters(BaseBatteryParameters): | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     """Battery Electric Vehicle Device Simulation Configuration.""" | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     device_id: str = Field(description="ID of electric vehicle", examples=["ev1"]) | 
					
						
							|  |  |  |  |     discharging_efficiency: float = discharging_efficiency_field(1.0) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     initial_soc_percentage: int = initial_soc_percentage_field( | 
					
						
							| 
									
										
										
										
											2024-11-15 22:27:25 +01:00
										 |  |  |  |         "An integer representing the current state of charge (SOC) of the battery in percentage." | 
					
						
							|  |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-09-20 12:02:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-03 11:05:44 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  | class ElectricVehicleResult(DeviceOptimizeResult): | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     """Result class containing information related to the electric vehicle's charging and discharging behavior.""" | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-15 00:54:45 +01:00
										 |  |  |  |     device_id: str = Field(description="ID of electric vehicle", examples=["ev1"]) | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     charge_array: list[float] = Field( | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         description="Hourly charging status (0 for no charging, 1 for charging)." | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     ) | 
					
						
							|  |  |  |  |     discharge_array: list[int] = Field( | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         description="Hourly discharging status (0 for no discharging, 1 for discharging)." | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     discharging_efficiency: float = Field(description="The discharge efficiency as a float..") | 
					
						
							|  |  |  |  |     capacity_wh: int = Field(description="Capacity of the EV’s battery in watt-hours.") | 
					
						
							|  |  |  |  |     charging_efficiency: float = Field(description="Charging efficiency as a float..") | 
					
						
							|  |  |  |  |     max_charge_power_w: int = Field(description="Maximum charging power in watts.") | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     soc_wh: float = Field( | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         description="State of charge of the battery in watt-hours at the start of the simulation." | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     initial_soc_percentage: int = Field( | 
					
						
							|  |  |  |  |         description="State of charge at the start of the simulation in percentage." | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     @field_validator("discharge_array", "charge_array", mode="before") | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def convert_numpy(cls, field: Any) -> Any: | 
					
						
							|  |  |  |  |         return NumpyEncoder.convert_numpy(field)[0] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | class Battery(DeviceBase): | 
					
						
							|  |  |  |  |     """Represents a battery device with methods to simulate energy charging and discharging.""" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  |     def __init__(self, parameters: Optional[BaseBatteryParameters] = None): | 
					
						
							|  |  |  |  |         self.parameters: Optional[BaseBatteryParameters] = None | 
					
						
							|  |  |  |  |         super().__init__(parameters) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  |     def _setup(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Sets up the battery parameters based on configuration or provided parameters.""" | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  |         assert self.parameters is not None | 
					
						
							|  |  |  |  |         self.capacity_wh = self.parameters.capacity_wh | 
					
						
							|  |  |  |  |         self.initial_soc_percentage = self.parameters.initial_soc_percentage | 
					
						
							|  |  |  |  |         self.charging_efficiency = self.parameters.charging_efficiency | 
					
						
							|  |  |  |  |         self.discharging_efficiency = self.parameters.discharging_efficiency | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # Only assign for storage battery | 
					
						
							|  |  |  |  |         self.min_soc_percentage = ( | 
					
						
							|  |  |  |  |             self.parameters.min_soc_percentage | 
					
						
							|  |  |  |  |             if isinstance(self.parameters, SolarPanelBatteryParameters) | 
					
						
							|  |  |  |  |             else 0 | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  |         self.max_soc_percentage = self.parameters.max_soc_percentage | 
					
						
							| 
									
										
										
										
											2024-12-15 14:40:03 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         # Initialize state of charge | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  |         if self.parameters.max_charge_power_w is not None: | 
					
						
							|  |  |  |  |             self.max_charge_power_w = self.parameters.max_charge_power_w | 
					
						
							|  |  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |             self.max_charge_power_w = self.capacity_wh  # TODO this should not be equal capacity_wh | 
					
						
							| 
									
										
										
										
											2024-02-25 16:47:28 +01:00
										 |  |  |  |         self.discharge_array = np.full(self.hours, 1) | 
					
						
							| 
									
										
										
										
											2024-10-16 15:40:04 +02:00
										 |  |  |  |         self.charge_array = np.full(self.hours, 1) | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         self.soc_wh = (self.initial_soc_percentage / 100) * self.capacity_wh | 
					
						
							|  |  |  |  |         self.min_soc_wh = (self.min_soc_percentage / 100) * self.capacity_wh | 
					
						
							|  |  |  |  |         self.max_soc_wh = (self.max_soc_percentage / 100) * self.capacity_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def to_dict(self) -> dict[str, Any]: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Converts the object to a dictionary representation.""" | 
					
						
							| 
									
										
										
										
											2024-03-28 08:16:57 +01:00
										 |  |  |  |         return { | 
					
						
							| 
									
										
										
										
											2025-01-12 05:19:37 +01:00
										 |  |  |  |             "device_id": self.device_id, | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |             "capacity_wh": self.capacity_wh, | 
					
						
							|  |  |  |  |             "initial_soc_percentage": self.initial_soc_percentage, | 
					
						
							| 
									
										
										
										
											2024-03-28 08:16:57 +01:00
										 |  |  |  |             "soc_wh": self.soc_wh, | 
					
						
							|  |  |  |  |             "hours": self.hours, | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |             "discharge_array": self.discharge_array, | 
					
						
							|  |  |  |  |             "charge_array": self.charge_array, | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |             "charging_efficiency": self.charging_efficiency, | 
					
						
							|  |  |  |  |             "discharging_efficiency": self.discharging_efficiency, | 
					
						
							|  |  |  |  |             "max_charge_power_w": self.max_charge_power_w, | 
					
						
							| 
									
										
										
										
											2024-03-28 08:16:57 +01:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def reset(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Resets the battery state to its initial values.""" | 
					
						
							|  |  |  |  |         self.soc_wh = (self.initial_soc_percentage / 100) * self.capacity_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  |         self.soc_wh = min(max(self.soc_wh, self.min_soc_wh), self.max_soc_wh) | 
					
						
							| 
									
										
										
										
											2024-02-25 16:47:28 +01:00
										 |  |  |  |         self.discharge_array = np.full(self.hours, 1) | 
					
						
							| 
									
										
										
										
											2024-10-16 15:40:04 +02:00
										 |  |  |  |         self.charge_array = np.full(self.hours, 1) | 
					
						
							| 
									
										
										
										
											2024-09-20 12:02:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def set_discharge_per_hour(self, discharge_array: np.ndarray) -> None: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Sets the discharge values for each hour.""" | 
					
						
							|  |  |  |  |         if len(discharge_array) != self.hours: | 
					
						
							|  |  |  |  |             raise ValueError(f"Discharge array must have exactly {self.hours} elements.") | 
					
						
							| 
									
										
										
										
											2024-03-28 08:16:57 +01:00
										 |  |  |  |         self.discharge_array = np.array(discharge_array) | 
					
						
							| 
									
										
										
										
											2024-02-18 14:32:27 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def set_charge_per_hour(self, charge_array: np.ndarray) -> None: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Sets the charge values for each hour.""" | 
					
						
							|  |  |  |  |         if len(charge_array) != self.hours: | 
					
						
							|  |  |  |  |             raise ValueError(f"Charge array must have exactly {self.hours} elements.") | 
					
						
							| 
									
										
										
										
											2024-03-28 08:16:57 +01:00
										 |  |  |  |         self.charge_array = np.array(charge_array) | 
					
						
							| 
									
										
										
										
											2024-03-25 14:40:48 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |     def set_charge_allowed_for_hour(self, charge: float, hour: int) -> None: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Sets the charge for a specific hour.""" | 
					
						
							|  |  |  |  |         if hour >= self.hours: | 
					
						
							|  |  |  |  |             raise ValueError(f"Hour {hour} is out of range. Must be less than {self.hours}.") | 
					
						
							| 
									
										
										
										
											2024-10-16 15:40:04 +02:00
										 |  |  |  |         self.charge_array[hour] = charge | 
					
						
							| 
									
										
										
										
											2024-10-14 10:10:12 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     def current_soc_percentage(self) -> float: | 
					
						
							|  |  |  |  |         """Calculates the current state of charge in percentage.""" | 
					
						
							|  |  |  |  |         return (self.soc_wh / self.capacity_wh) * 100 | 
					
						
							| 
									
										
										
										
											2024-02-18 14:32:27 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     def discharge_energy(self, wh: float, hour: int) -> tuple[float, float]: | 
					
						
							|  |  |  |  |         """Discharges energy from the battery.""" | 
					
						
							| 
									
										
										
										
											2024-10-22 10:29:57 +02:00
										 |  |  |  |         if self.discharge_array[hour] == 0: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |             return 0.0, 0.0 | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         max_possible_discharge_wh = (self.soc_wh - self.min_soc_wh) * self.discharging_efficiency | 
					
						
							|  |  |  |  |         max_possible_discharge_wh = max(max_possible_discharge_wh, 0.0) | 
					
						
							| 
									
										
										
										
											2024-09-20 12:02:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         max_possible_discharge_wh = min( | 
					
						
							|  |  |  |  |             max_possible_discharge_wh, self.max_charge_power_w | 
					
						
							|  |  |  |  |         )  # TODO make a new cfg variable max_discharge_power_w | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         actual_discharge_wh = min(wh, max_possible_discharge_wh) | 
					
						
							|  |  |  |  |         actual_withdrawal_wh = ( | 
					
						
							|  |  |  |  |             actual_discharge_wh / self.discharging_efficiency | 
					
						
							|  |  |  |  |             if self.discharging_efficiency > 0 | 
					
						
							|  |  |  |  |             else 0.0 | 
					
						
							|  |  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         self.soc_wh -= actual_withdrawal_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  |         self.soc_wh = max(self.soc_wh, self.min_soc_wh) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         losses_wh = actual_withdrawal_wh - actual_discharge_wh | 
					
						
							|  |  |  |  |         return actual_discharge_wh, losses_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     def charge_energy( | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |         self, wh: Optional[float], hour: int, relative_power: float = 0.0 | 
					
						
							|  |  |  |  |     ) -> tuple[float, float]: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         """Charges energy into the battery.""" | 
					
						
							| 
									
										
										
										
											2024-03-25 14:40:48 +01:00
										 |  |  |  |         if hour is not None and self.charge_array[hour] == 0: | 
					
						
							| 
									
										
										
										
											2024-11-26 22:28:05 +01:00
										 |  |  |  |             return 0.0, 0.0  # Charging not allowed in this hour | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-16 15:40:04 +02:00
										 |  |  |  |         if relative_power > 0.0: | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |             wh = self.max_charge_power_w * relative_power | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         wh = wh if wh is not None else self.max_charge_power_w | 
					
						
							| 
									
										
										
										
											2024-03-25 14:40:48 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         max_possible_charge_wh = ( | 
					
						
							|  |  |  |  |             (self.max_soc_wh - self.soc_wh) / self.charging_efficiency | 
					
						
							|  |  |  |  |             if self.charging_efficiency > 0 | 
					
						
							|  |  |  |  |             else 0.0 | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  |         max_possible_charge_wh = max(max_possible_charge_wh, 0.0) | 
					
						
							| 
									
										
										
										
											2024-10-22 10:29:57 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         effective_charge_wh = min(wh, max_possible_charge_wh) | 
					
						
							|  |  |  |  |         charged_wh = effective_charge_wh * self.charging_efficiency | 
					
						
							| 
									
										
										
										
											2024-05-02 10:27:33 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         self.soc_wh += charged_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  |         self.soc_wh = min(self.soc_wh, self.max_soc_wh) | 
					
						
							| 
									
										
										
										
											2024-10-22 10:29:57 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |         losses_wh = effective_charge_wh - charged_wh | 
					
						
							|  |  |  |  |         return charged_wh, losses_wh | 
					
						
							| 
									
										
										
										
											2024-10-03 09:20:15 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-19 14:50:19 +01:00
										 |  |  |  |     def current_energy_content(self) -> float: | 
					
						
							|  |  |  |  |         """Returns the current usable energy in the battery.""" | 
					
						
							|  |  |  |  |         usable_energy = (self.soc_wh - self.min_soc_wh) * self.discharging_efficiency | 
					
						
							|  |  |  |  |         return max(usable_energy, 0.0) |