mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-04-19 08:55:15 +00:00
AC Charge Bug, Price Cache On/Off
This commit is contained in:
parent
b925ef45cc
commit
fca2338bd7
@ -95,21 +95,13 @@ class EnergieManagementSystem:
|
|||||||
haushaltsgeraet_wh_pro_stunde[stunde_since_now] = ha_load
|
haushaltsgeraet_wh_pro_stunde[stunde_since_now] = ha_load
|
||||||
|
|
||||||
# E-Auto handling
|
# E-Auto handling
|
||||||
if self.eauto:
|
if self.eauto and self.ev_charge_hours[stunde]>0:
|
||||||
geladene_menge_eauto, verluste_eauto = self.eauto.energie_laden(None, stunde, relative_power=self.ev_charge_hours[stunde])
|
geladene_menge_eauto, verluste_eauto = self.eauto.energie_laden(None, stunde, relative_power=self.ev_charge_hours[stunde])
|
||||||
# if self.ev_charge_hours[stunde] > 0.0:
|
|
||||||
# print(self.ev_charge_hours[stunde], " ", geladene_menge_eauto," ", self.eauto.ladezustand_in_prozent())
|
|
||||||
verbrauch += geladene_menge_eauto
|
verbrauch += geladene_menge_eauto
|
||||||
verluste_wh_pro_stunde[stunde_since_now] += verluste_eauto
|
verluste_wh_pro_stunde[stunde_since_now] += verluste_eauto
|
||||||
|
|
||||||
|
if self.eauto:
|
||||||
eauto_soc_pro_stunde[stunde_since_now] = self.eauto.ladezustand_in_prozent()
|
eauto_soc_pro_stunde[stunde_since_now] = self.eauto.ladezustand_in_prozent()
|
||||||
|
|
||||||
# AC PV Battery Charge
|
|
||||||
if self.ac_charge_hours[stunde] > 0.0:
|
|
||||||
self.akku.set_charge_allowed_for_hour(self.ac_charge_hours[stunde],stunde)
|
|
||||||
geladene_menge, verluste_wh = self.akku.energie_laden(None,stunde,relative_power=self.ac_charge_hours[stunde])
|
|
||||||
verbrauch += geladene_menge
|
|
||||||
verluste_wh_pro_stunde[stunde_since_now] += verluste_wh
|
|
||||||
|
|
||||||
# Process inverter logic
|
# Process inverter logic
|
||||||
erzeugung = self.pv_prognose_wh[stunde]
|
erzeugung = self.pv_prognose_wh[stunde]
|
||||||
self.akku.set_charge_allowed_for_hour(self.dc_charge_hours[stunde],stunde)
|
self.akku.set_charge_allowed_for_hour(self.dc_charge_hours[stunde],stunde)
|
||||||
@ -117,7 +109,14 @@ class EnergieManagementSystem:
|
|||||||
self.wechselrichter.energie_verarbeiten(erzeugung, verbrauch, stunde)
|
self.wechselrichter.energie_verarbeiten(erzeugung, verbrauch, stunde)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# AC PV Battery Charge
|
||||||
|
if self.ac_charge_hours[stunde] > 0.0:
|
||||||
|
self.akku.set_charge_allowed_for_hour(1,stunde)
|
||||||
|
geladene_menge, verluste_wh = self.akku.energie_laden(None,stunde,relative_power=self.ac_charge_hours[stunde])
|
||||||
|
#print(stunde, " ", geladene_menge, " ",self.ac_charge_hours[stunde]," ",self.akku.ladezustand_in_prozent())
|
||||||
|
verbrauch += geladene_menge
|
||||||
|
netzbezug +=geladene_menge
|
||||||
|
verluste_wh_pro_stunde[stunde_since_now] += verluste_wh
|
||||||
|
|
||||||
netzeinspeisung_wh_pro_stunde[stunde_since_now] = netzeinspeisung
|
netzeinspeisung_wh_pro_stunde[stunde_since_now] = netzeinspeisung
|
||||||
netzbezug_wh_pro_stunde[stunde_since_now] = netzbezug
|
netzbezug_wh_pro_stunde[stunde_since_now] = netzbezug
|
||||||
|
@ -31,6 +31,7 @@ class optimization_problem:
|
|||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.fix_seed = fixed_seed
|
self.fix_seed = fixed_seed
|
||||||
self.optimize_ev = True
|
self.optimize_ev = True
|
||||||
|
self.optimize_dc_charge = False
|
||||||
|
|
||||||
# Set a fixed seed for random operations if provided
|
# Set a fixed seed for random operations if provided
|
||||||
if fixed_seed is not None:
|
if fixed_seed is not None:
|
||||||
@ -63,7 +64,12 @@ class optimization_problem:
|
|||||||
ac_charge = ac_charge / 5.0 # Normalize AC charge to range between 0 and 1
|
ac_charge = ac_charge / 5.0 # Normalize AC charge to range between 0 and 1
|
||||||
|
|
||||||
# Create dc_charge array: 7 = Not allowed (mapped to 0), 8 = Allowed (mapped to 1)
|
# Create dc_charge array: 7 = Not allowed (mapped to 0), 8 = Allowed (mapped to 1)
|
||||||
dc_charge = np.where(discharge_hours_bin == 8, 1, 0)
|
# Create dc_charge array: Only if DC charge optimization is enabled
|
||||||
|
if self.optimize_dc_charge:
|
||||||
|
dc_charge = np.where(discharge_hours_bin == 8, 1, 0)
|
||||||
|
else:
|
||||||
|
dc_charge = np.ones_like(discharge_hours_bin) # Set DC charge to 0 if optimization is disabled
|
||||||
|
|
||||||
|
|
||||||
# Create discharge array: Only consider value 1 (Discharge), set the rest to 0 (binary output)
|
# Create discharge array: Only consider value 1 (Discharge), set the rest to 0 (binary output)
|
||||||
discharge = np.where(discharge_hours_bin == 1, 1, 0)
|
discharge = np.where(discharge_hours_bin == 1, 1, 0)
|
||||||
@ -95,7 +101,10 @@ class optimization_problem:
|
|||||||
charge_discharge_mutated, = self.toolbox.mutate_charge_discharge(charge_discharge_part)
|
charge_discharge_mutated, = self.toolbox.mutate_charge_discharge(charge_discharge_part)
|
||||||
|
|
||||||
# Ensure that no invalid states are introduced during mutation (valid values: 0-8)
|
# Ensure that no invalid states are introduced during mutation (valid values: 0-8)
|
||||||
charge_discharge_mutated = np.clip(charge_discharge_mutated, 0, 8)
|
if self.optimize_dc_charge:
|
||||||
|
charge_discharge_mutated = np.clip(charge_discharge_mutated, 0, 8)
|
||||||
|
else:
|
||||||
|
charge_discharge_mutated = np.clip(charge_discharge_mutated, 0, 6)
|
||||||
|
|
||||||
# Use split_charge_discharge to split the mutated array into AC charge, DC charge, and discharge components
|
# Use split_charge_discharge to split the mutated array into AC charge, DC charge, and discharge components
|
||||||
#ac_charge, dc_charge, discharge = self.split_charge_discharge(charge_discharge_mutated)
|
#ac_charge, dc_charge, discharge = self.split_charge_discharge(charge_discharge_mutated)
|
||||||
@ -190,7 +199,11 @@ class optimization_problem:
|
|||||||
|
|
||||||
# Initialize toolbox with attributes and operations
|
# Initialize toolbox with attributes and operations
|
||||||
self.toolbox = base.Toolbox()
|
self.toolbox = base.Toolbox()
|
||||||
self.toolbox.register("attr_discharge_state", random.randint, 0,11)
|
if self.optimize_dc_charge:
|
||||||
|
self.toolbox.register("attr_discharge_state", random.randint, 0,8)
|
||||||
|
else:
|
||||||
|
self.toolbox.register("attr_discharge_state", random.randint, 0,6)
|
||||||
|
|
||||||
if self.optimize_ev:
|
if self.optimize_ev:
|
||||||
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(possible_ev_charge_currents) - 1)
|
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(possible_ev_charge_currents) - 1)
|
||||||
self.toolbox.register("attr_int", random.randint, start_hour, 23)
|
self.toolbox.register("attr_int", random.randint, start_hour, 23)
|
||||||
@ -205,7 +218,10 @@ class optimization_problem:
|
|||||||
#self.toolbox.register("mutate", tools.mutFlipBit, indpb=0.1)
|
#self.toolbox.register("mutate", tools.mutFlipBit, indpb=0.1)
|
||||||
# Register separate mutation functions for each type of value:
|
# Register separate mutation functions for each type of value:
|
||||||
# - Discharge state mutation (-5, 0, 1)
|
# - Discharge state mutation (-5, 0, 1)
|
||||||
self.toolbox.register("mutate_charge_discharge", tools.mutUniformInt, low=0, up=8, indpb=0.1)
|
if self.optimize_dc_charge:
|
||||||
|
self.toolbox.register("mutate_charge_discharge", tools.mutUniformInt, low=0, up=8, indpb=0.1)
|
||||||
|
else:
|
||||||
|
self.toolbox.register("mutate_charge_discharge", tools.mutUniformInt, low=0, up=6, indpb=0.1)
|
||||||
# - Float mutation for EV charging values
|
# - Float mutation for EV charging values
|
||||||
self.toolbox.register("mutate_ev_charge_index", tools.mutUniformInt, low=0, up=len(possible_ev_charge_currents) - 1, indpb=0.1)
|
self.toolbox.register("mutate_ev_charge_index", tools.mutUniformInt, low=0, up=len(possible_ev_charge_currents) - 1, indpb=0.1)
|
||||||
# - Start hour mutation for household devices
|
# - Start hour mutation for household devices
|
||||||
@ -234,7 +250,9 @@ class optimization_problem:
|
|||||||
|
|
||||||
|
|
||||||
ems.set_akku_discharge_hours(discharge)
|
ems.set_akku_discharge_hours(discharge)
|
||||||
ems.set_akku_dc_charge_hours(dc)
|
# Set DC charge hours only if DC optimization is enabled
|
||||||
|
if self.optimize_dc_charge:
|
||||||
|
ems.set_akku_dc_charge_hours(dc)
|
||||||
ems.set_akku_ac_charge_hours(ac)
|
ems.set_akku_ac_charge_hours(ac)
|
||||||
|
|
||||||
if self.optimize_ev:
|
if self.optimize_ev:
|
||||||
@ -242,8 +260,8 @@ class optimization_problem:
|
|||||||
possible_ev_charge_currents[i] for i in eautocharge_hours_index
|
possible_ev_charge_currents[i] for i in eautocharge_hours_index
|
||||||
]
|
]
|
||||||
ems.set_ev_charge_hours(eautocharge_hours_float)
|
ems.set_ev_charge_hours(eautocharge_hours_float)
|
||||||
#else:
|
else:
|
||||||
# ems.set_ev_charge_hours(np.full(self.prediction_hours, 0 ))
|
ems.set_ev_charge_hours(np.full(self.prediction_hours, 0 ))
|
||||||
return ems.simuliere(start_hour)
|
return ems.simuliere(start_hour)
|
||||||
|
|
||||||
def evaluate(
|
def evaluate(
|
||||||
@ -284,8 +302,11 @@ class optimization_problem:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Adjust total balance with battery value and penalties for unmet SOC
|
# Adjust total balance with battery value and penalties for unmet SOC
|
||||||
|
|
||||||
restwert_akku = ems.akku.aktueller_energieinhalt() * parameter["preis_euro_pro_wh_akku"]
|
restwert_akku = ems.akku.aktueller_energieinhalt() * parameter["preis_euro_pro_wh_akku"]
|
||||||
|
#print(ems.akku.aktueller_energieinhalt()," * ", parameter["preis_euro_pro_wh_akku"] , " ", restwert_akku, " ", gesamtbilanz)
|
||||||
gesamtbilanz += -restwert_akku
|
gesamtbilanz += -restwert_akku
|
||||||
|
#print(gesamtbilanz)
|
||||||
if self.optimize_ev:
|
if self.optimize_ev:
|
||||||
gesamtbilanz += max(
|
gesamtbilanz += max(
|
||||||
0,
|
0,
|
||||||
@ -318,8 +339,8 @@ class optimization_problem:
|
|||||||
self.toolbox,
|
self.toolbox,
|
||||||
mu=100,
|
mu=100,
|
||||||
lambda_=150,
|
lambda_=150,
|
||||||
cxpb=0.7,
|
cxpb=0.6,
|
||||||
mutpb=0.3,
|
mutpb=0.4,
|
||||||
ngen=ngen,
|
ngen=ngen,
|
||||||
stats=stats,
|
stats=stats,
|
||||||
halloffame=hof,
|
halloffame=hof,
|
||||||
@ -412,8 +433,8 @@ class optimization_problem:
|
|||||||
discharge_hours_bin, eautocharge_hours_float, spuelstart_int = self.split_individual(
|
discharge_hours_bin, eautocharge_hours_float, spuelstart_int = self.split_individual(
|
||||||
start_solution
|
start_solution
|
||||||
)
|
)
|
||||||
|
if self.optimize_ev:
|
||||||
|
eautocharge_hours_float = [possible_ev_charge_currents[i] for i in eautocharge_hours_float]
|
||||||
|
|
||||||
ac_charge, dc_charge, discharge = self.decode_charge_discharge(discharge_hours_bin)
|
ac_charge, dc_charge, discharge = self.decode_charge_discharge(discharge_hours_bin)
|
||||||
# Visualize the results
|
# Visualize the results
|
||||||
|
@ -5,7 +5,6 @@ import matplotlib.pyplot as plt
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
class BatteryDataProcessor:
|
class BatteryDataProcessor:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -235,7 +234,7 @@ class BatteryDataProcessor:
|
|||||||
marker="o",
|
marker="o",
|
||||||
label="100% SoC Points",
|
label="100% SoC Points",
|
||||||
)
|
)
|
||||||
# plt.scatter(last_points_0_df['timestamp'], last_points_0_df['battery_voltage'], color='red', marker='x', label='0% SoC Points')
|
plt.scatter(last_points_0_df['timestamp'], last_points_0_df['battery_voltage'], color='red', marker='x', label='0% SoC Points')
|
||||||
plt.xlabel("Timestamp")
|
plt.xlabel("Timestamp")
|
||||||
plt.ylabel("Voltage (V)")
|
plt.ylabel("Voltage (V)")
|
||||||
plt.legend()
|
plt.legend()
|
||||||
@ -255,7 +254,7 @@ class BatteryDataProcessor:
|
|||||||
marker="o",
|
marker="o",
|
||||||
label="100% SoC Points",
|
label="100% SoC Points",
|
||||||
)
|
)
|
||||||
# plt.scatter(last_points_0_df['timestamp'], last_points_0_df['battery_current'], color='red', marker='x', label='0% SoC Points')
|
plt.scatter(last_points_0_df['timestamp'], last_points_0_df['battery_current'], color='red', marker='x', label='0% SoC Points')
|
||||||
plt.xlabel("Timestamp")
|
plt.xlabel("Timestamp")
|
||||||
plt.ylabel("Current (A)")
|
plt.ylabel("Current (A)")
|
||||||
plt.legend()
|
plt.legend()
|
||||||
@ -281,17 +280,23 @@ class BatteryDataProcessor:
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# MariaDB Verbindungsdetails
|
# MariaDB Verbindungsdetails
|
||||||
config = {}
|
|
||||||
|
config = {
|
||||||
|
'user': 'soc',
|
||||||
|
'password': 'Rayoflight123!',
|
||||||
|
'host': '192.168.1.135',
|
||||||
|
'database': 'sensor'
|
||||||
|
}
|
||||||
|
|
||||||
# Parameter festlegen
|
# Parameter festlegen
|
||||||
voltage_high_threshold = 55.4 # 100% SoC
|
voltage_high_threshold = 55.4 # 100% SoC
|
||||||
voltage_low_threshold = 46.5 # 0% SoC
|
voltage_low_threshold = 48 # 0% SoC
|
||||||
current_low_threshold = 2 # Niedriger Strom für beide Zustände
|
current_low_threshold = 2 # Niedriger Strom für beide Zustände
|
||||||
gap = 30 # Zeitlücke in Minuten zum Gruppieren von Maxima/Minima
|
gap = 30 # Zeitlücke in Minuten zum Gruppieren von Maxima/Minima
|
||||||
bat_capacity = 33 * 1000 / 48
|
bat_capacity = 0.8*33 * 1000 / 48
|
||||||
|
|
||||||
# Zeitpunkt X definieren
|
# Zeitpunkt X definieren
|
||||||
zeitpunkt_x = (datetime.now() - timedelta(weeks=100)).strftime("%Y-%m-%d %H:%M:%S")
|
zeitpunkt_x = (datetime.now() - timedelta(weeks=4)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
# BatteryDataProcessor instanziieren und verwenden
|
# BatteryDataProcessor instanziieren und verwenden
|
||||||
processor = BatteryDataProcessor(
|
processor = BatteryDataProcessor(
|
||||||
@ -310,7 +315,7 @@ if __name__ == "__main__":
|
|||||||
last_points_100_df, last_points_0_df
|
last_points_100_df, last_points_0_df
|
||||||
)
|
)
|
||||||
# soh_df = processor.calculate_soh(integration_results)
|
# soh_df = processor.calculate_soh(integration_results)
|
||||||
processor.update_database_with_soc(soc_df)
|
#processor.update_database_with_soc(soc_df)
|
||||||
|
|
||||||
processor.plot_data(last_points_100_df, last_points_0_df, soc_df)
|
processor.plot_data(last_points_100_df, last_points_0_df, soc_df)
|
||||||
|
|
||||||
|
@ -22,18 +22,20 @@ def repeat_to_shape(array, target_shape):
|
|||||||
|
|
||||||
|
|
||||||
class HourlyElectricityPriceForecast:
|
class HourlyElectricityPriceForecast:
|
||||||
def __init__(self, source, cache_dir="cache", charges=0.000228, prediction_hours=24): # 228
|
def __init__(self, source, cache_dir="cache", charges=0.000228, prediction_hours=24, cache=True): # 228
|
||||||
self.cache_dir = cache_dir
|
self.cache_dir = cache_dir
|
||||||
|
self.cache=cache
|
||||||
os.makedirs(self.cache_dir, exist_ok=True)
|
os.makedirs(self.cache_dir, exist_ok=True)
|
||||||
self.cache_time_file = os.path.join(self.cache_dir, "cache_timestamp.txt")
|
self.cache_time_file = os.path.join(self.cache_dir, "cache_timestamp.txt")
|
||||||
self.prices = self.load_data(source)
|
self.prices = self.load_data(source)
|
||||||
self.charges = charges
|
self.charges = charges
|
||||||
self.prediction_hours = prediction_hours
|
self.prediction_hours = prediction_hours
|
||||||
|
|
||||||
|
|
||||||
def load_data(self, source):
|
def load_data(self, source):
|
||||||
cache_filename = self.get_cache_filename(source)
|
cache_filename = self.get_cache_filename(source)
|
||||||
if source.startswith("http"):
|
if source.startswith("http"):
|
||||||
if os.path.exists(cache_filename) and not self.is_cache_expired():
|
if os.path.exists(cache_filename) and not self.is_cache_expired() and self.cache==True:
|
||||||
print("Loading data from cache...")
|
print("Loading data from cache...")
|
||||||
with open(cache_filename, "r") as file:
|
with open(cache_filename, "r") as file:
|
||||||
json_data = json.load(file)
|
json_data = json.load(file)
|
||||||
|
@ -62,6 +62,7 @@ def flask_strompreis():
|
|||||||
price_forecast = HourlyElectricityPriceForecast(
|
price_forecast = HourlyElectricityPriceForecast(
|
||||||
source=f"https://api.akkudoktor.net/prices?start={date_now}&end={date}",
|
source=f"https://api.akkudoktor.net/prices?start={date_now}&end={date}",
|
||||||
prediction_hours=prediction_hours,
|
prediction_hours=prediction_hours,
|
||||||
|
cache=False
|
||||||
)
|
)
|
||||||
specific_date_prices = price_forecast.get_price_for_daterange(
|
specific_date_prices = price_forecast.get_price_for_daterange(
|
||||||
date_now, date
|
date_now, date
|
||||||
|
Loading…
x
Reference in New Issue
Block a user