From bb81a3e7ee6800e73c219e6bf74b314dfe3bcb1c Mon Sep 17 00:00:00 2001 From: Bla Bla Date: Sun, 8 Sep 2024 10:28:54 +0200 Subject: [PATCH] =?UTF-8?q?Lastprediction=20als=20Service=20verf=C3=BCgbar?= =?UTF-8?q?=20und=20ohne=20DB=20Abfrage.=20y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.example.py | 3 +- flask_server.py | 218 ++++++++++++++++++++++---------- modules/class_load_corrector.py | 167 ++++++++++-------------- requirements.txt | 1 - 4 files changed, 221 insertions(+), 168 deletions(-) diff --git a/config.example.py b/config.example.py index 83e29d8..4cee206 100644 --- a/config.example.py +++ b/config.example.py @@ -7,7 +7,8 @@ strafe=10 moegliche_ladestroeme_in_prozent = [0.0 ,6.0/16.0, 7.0/16.0, 8.0/16.0, 9.0/16.0, 10.0/16.0, 11.0/16.0, 12.0/16.0, 13.0/16.0, 14.0/16.0, 15.0/16.0, 1.0 ] -db_config = { +# Optional +db_config = { 'user': '', 'password': '', 'host': '192.168.1.135', diff --git a/flask_server.py b/flask_server.py index 26fd1f4..2dd1574 100644 --- a/flask_server.py +++ b/flask_server.py @@ -33,31 +33,31 @@ opt_class = optimization_problem(prediction_hours=prediction_hours, strafe=10, o -@app.route('/last_correction', methods=['GET']) -def flask_last_correction(): - if request.method == 'GET': - year_energy = float(request.args.get("year_energy")) - date_now,date = get_start_enddate(prediction_hours,startdate=datetime.now().date()) - ############### - # Load Forecast - ############### - lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) - #leistung_haushalt = lf.get_daily_stats(date)[0,...] # Datum anpassen - leistung_haushalt = lf.get_stats_for_date_range(date_now,date)[0] # Nur Erwartungswert! - - gesamtlast = Gesamtlast(prediction_hours=prediction_hours) - gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) - +# @app.route('/last_correction', methods=['GET']) +# def flask_last_correction(): + # if request.method == 'GET': + # year_energy = float(request.args.get("year_energy")) + # date_now,date = get_start_enddate(prediction_hours,startdate=datetime.now().date()) # ############### - # # WP - # ############## - # leistung_wp = wp.simulate_24h(temperature_forecast) - # gesamtlast.hinzufuegen("Heatpump", leistung_wp) + # # Load Forecast + # ############### + # lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) + # #leistung_haushalt = lf.get_daily_stats(date)[0,...] # Datum anpassen + # leistung_haushalt = lf.get_stats_for_date_range(date_now,date)[0] # Nur Erwartungswert! + + # gesamtlast = Gesamtlast(prediction_hours=prediction_hours) + # gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) + + # # ############### + # # # WP + # # ############## + # # leistung_wp = wp.simulate_24h(temperature_forecast) + # # gesamtlast.hinzufuegen("Heatpump", leistung_wp) - last = gesamtlast.gesamtlast_berechnen() - print(last) - #print(specific_date_prices) - return jsonify(last.tolist()) + # last = gesamtlast.gesamtlast_berechnen() + # print(last) + # #print(specific_date_prices) + # return jsonify(last.tolist()) @app.route('/soc', methods=['GET']) @@ -106,66 +106,146 @@ def flask_strompreis(): return jsonify(specific_date_prices.tolist()) -@app.route('/gesamtlast', methods=['GET']) + +# Die letzten X gemessenen Daten + gesamtlast Simple oder eine andere Schätung als Input +# Daraus wird dann eine neuen Lastprognose erstellt welche korrigiert ist. +# Input: +@app.route('/gesamtlast', methods=['POST']) def flask_gesamtlast(): - if request.method == 'GET': - year_energy = float(request.args.get("year_energy")) - prediction_hours = int(request.args.get("hours", 48)) # Default to 24 hours if not specified - date_now = datetime.now() - end_date = (date_now + timedelta(hours=prediction_hours)).strftime('%Y-%m-%d %H:%M:%S') + # Daten aus dem JSON-Body abrufen + data = request.get_json() - ############### - # Load Forecast - ############### - # Instantiate LastEstimator and get measured data - estimator = LastEstimator() - start_date = (date_now - timedelta(days=60)).strftime('%Y-%m-%d') # Example: last 60 days - end_date = date_now.strftime('%Y-%m-%d') # Current date + # Extract year_energy and prediction_hours from the request JSON + year_energy = float(data.get("year_energy")) + prediction_hours = int(data.get("hours", 48)) # Default to 48 hours if not specified - last_df = estimator.get_last(start_date, end_date) + # Measured data as JSON + measured_data_json = data.get("measured_data") - selected_columns = last_df[['timestamp', 'Last']] - selected_columns['time'] = pd.to_datetime(selected_columns['timestamp']).dt.floor('H') - selected_columns['Last'] = pd.to_numeric(selected_columns['Last'], errors='coerce') - cleaned_data = selected_columns.dropna() + # Convert JSON data into a Pandas DataFrame + measured_data = pd.DataFrame(measured_data_json) + # Make sure the 'time' column is in datetime format + measured_data['time'] = pd.to_datetime(measured_data['time']) - # Instantiate LoadForecast - lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) + # Check if the datetime has timezone info, if not, assume it's local time + if measured_data['time'].dt.tz is None: + # Treat it as local time and localize it + measured_data['time'] = measured_data['time'].dt.tz_localize('Europe/Berlin') + else: + # Convert the time to local timezone (e.g., 'Europe/Berlin') + measured_data['time'] = measured_data['time'].dt.tz_convert('Europe/Berlin') - # Generate forecast data - forecast_list = [] - for single_date in pd.date_range(cleaned_data['time'].min().date(), cleaned_data['time'].max().date()): - date_str = single_date.strftime('%Y-%m-%d') - daily_forecast = lf.get_daily_stats(date_str) - mean_values = daily_forecast[0] - hours = [single_date + pd.Timedelta(hours=i) for i in range(24)] - daily_forecast_df = pd.DataFrame({'time': hours, 'Last Pred': mean_values}) - forecast_list.append(daily_forecast_df) + # Remove timezone info after conversion + measured_data['time'] = measured_data['time'].dt.tz_localize(None) + + # Instantiate LoadForecast and generate forecast data + lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) - forecast_df = pd.concat(forecast_list, ignore_index=True) + # Generate forecast data based on the measured data time range + forecast_list = [] + for single_date in pd.date_range(measured_data['time'].min().date(), measured_data['time'].max().date()): + date_str = single_date.strftime('%Y-%m-%d') + daily_forecast = lf.get_daily_stats(date_str) + mean_values = daily_forecast[0] + hours = [single_date + pd.Timedelta(hours=i) for i in range(24)] + daily_forecast_df = pd.DataFrame({'time': hours, 'Last Pred': mean_values}) + forecast_list.append(daily_forecast_df) - # Create LoadPredictionAdjuster instance - adjuster = LoadPredictionAdjuster(cleaned_data, forecast_df, lf) - adjuster.calculate_weighted_mean() - adjuster.adjust_predictions() + # Concatenate all daily forecasts into a single DataFrame + predicted_data = pd.concat(forecast_list, ignore_index=True) + #print(predicted_data) + # Create LoadPredictionAdjuster instance + adjuster = LoadPredictionAdjuster(measured_data, predicted_data, lf) - # Predict the next hours - future_predictions = adjuster.predict_next_hours(prediction_hours) + # Calculate weighted mean and adjust predictions + adjuster.calculate_weighted_mean() + adjuster.adjust_predictions() - leistung_haushalt = future_predictions['Adjusted Pred'].values + # Predict the next x hours + future_predictions = adjuster.predict_next_hours(prediction_hours) - gesamtlast = Gesamtlast(prediction_hours=prediction_hours) - gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) + # Extract the household power predictions + leistung_haushalt = future_predictions['Adjusted Pred'].values + + # Instantiate Gesamtlast and add household power predictions + gesamtlast = Gesamtlast(prediction_hours=prediction_hours) + gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) + + # ############### + # # WP (optional) + # ############### + # leistung_wp = wp.simulate_24h(temperature_forecast) + # gesamtlast.hinzufuegen("Heatpump", leistung_wp) + + # Calculate the total load + last = gesamtlast.gesamtlast_berechnen() + + # Return the calculated load as JSON + return jsonify(last.tolist()) + + + + +# @app.route('/gesamtlast', methods=['GET']) +# def flask_gesamtlast(): + # if request.method == 'GET': + # year_energy = float(request.args.get("year_energy")) + # prediction_hours = int(request.args.get("hours", 48)) # Default to 24 hours if not specified + # date_now = datetime.now() + # end_date = (date_now + timedelta(hours=prediction_hours)).strftime('%Y-%m-%d %H:%M:%S') # ############### - # # WP - # ############## - # leistung_wp = wp.simulate_24h(temperature_forecast) - # gesamtlast.hinzufuegen("Heatpump", leistung_wp) + # # Load Forecast + # ############### + # # Instantiate LastEstimator and get measured data + # estimator = LastEstimator() + # start_date = (date_now - timedelta(days=60)).strftime('%Y-%m-%d') # Example: last 60 days + # end_date = date_now.strftime('%Y-%m-%d') # Current date + + # last_df = estimator.get_last(start_date, end_date) + + # selected_columns = last_df[['timestamp', 'Last']] + # selected_columns['time'] = pd.to_datetime(selected_columns['timestamp']).dt.floor('H') + # selected_columns['Last'] = pd.to_numeric(selected_columns['Last'], errors='coerce') + # cleaned_data = selected_columns.dropna() + + # # Instantiate LoadForecast + # lf = LoadForecast(filepath=r'load_profiles.npz', year_energy=year_energy) + + # # Generate forecast data + # forecast_list = [] + # for single_date in pd.date_range(cleaned_data['time'].min().date(), cleaned_data['time'].max().date()): + # date_str = single_date.strftime('%Y-%m-%d') + # daily_forecast = lf.get_daily_stats(date_str) + # mean_values = daily_forecast[0] + # hours = [single_date + pd.Timedelta(hours=i) for i in range(24)] + # daily_forecast_df = pd.DataFrame({'time': hours, 'Last Pred': mean_values}) + # forecast_list.append(daily_forecast_df) + + # forecast_df = pd.concat(forecast_list, ignore_index=True) + + # # Create LoadPredictionAdjuster instance + # adjuster = LoadPredictionAdjuster(cleaned_data, forecast_df, lf) + # adjuster.calculate_weighted_mean() + # adjuster.adjust_predictions() + + # # Predict the next hours + # future_predictions = adjuster.predict_next_hours(prediction_hours) + + # leistung_haushalt = future_predictions['Adjusted Pred'].values + + # gesamtlast = Gesamtlast(prediction_hours=prediction_hours) + # gesamtlast.hinzufuegen("Haushalt", leistung_haushalt) + + # # ############### + # # # WP + # # ############## + # # leistung_wp = wp.simulate_24h(temperature_forecast) + # # gesamtlast.hinzufuegen("Heatpump", leistung_wp) - last = gesamtlast.gesamtlast_berechnen() - print(last) - return jsonify(last.tolist()) + # last = gesamtlast.gesamtlast_berechnen() + # print(last) + # return jsonify(last.tolist()) @app.route('/gesamtlast_simple', methods=['GET']) diff --git a/modules/class_load_corrector.py b/modules/class_load_corrector.py index 36b50ef..7e1d0be 100644 --- a/modules/class_load_corrector.py +++ b/modules/class_load_corrector.py @@ -44,11 +44,31 @@ class LoadPredictionAdjuster: def _merge_data(self): + # Konvertiere die Zeitspalte in beiden Datenrahmen zu datetime + self.predicted_data['time'] = pd.to_datetime(self.predicted_data['time']) + self.measured_data['time'] = pd.to_datetime(self.measured_data['time']) + + # Stelle sicher, dass beide Zeitspalten dieselbe Zeitzone haben + # Measured Data: Setze die Zeitzone auf UTC, falls es tz-naiv ist + if self.measured_data['time'].dt.tz is None: + self.measured_data['time'] = self.measured_data['time'].dt.tz_localize('UTC') + + # Predicted Data: Setze ebenfalls UTC und konvertiere anschließend in die lokale Zeitzone + self.predicted_data['time'] = self.predicted_data['time'].dt.tz_localize('UTC').dt.tz_convert('Europe/Berlin') + self.measured_data['time'] = self.measured_data['time'].dt.tz_convert('Europe/Berlin') + + # Optional: Entferne die Zeitzoneninformation, wenn du nur lokal arbeiten möchtest + self.predicted_data['time'] = self.predicted_data['time'].dt.tz_localize(None) + self.measured_data['time'] = self.measured_data['time'].dt.tz_localize(None) + + # Jetzt kannst du den Merge durchführen merged_data = pd.merge(self.measured_data, self.predicted_data, on='time', how='inner') + print(merged_data) merged_data['Hour'] = merged_data['time'].dt.hour merged_data['DayOfWeek'] = merged_data['time'].dt.dayofweek return merged_data + def calculate_weighted_mean(self, train_period_weeks=9, test_period_weeks=1): self.merged_data = self._remove_outliers(self.merged_data) train_end_date = self.merged_data['time'].max() - pd.Timedelta(weeks=test_period_weeks) @@ -124,112 +144,65 @@ class LoadPredictionAdjuster: -class LastEstimator: - def __init__(self): - self.conn_params = db_config - self.conn = mariadb.connect(**self.conn_params) - - def fetch_data(self, start_date, end_date): - queries = { - "Stromzaehler": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS Stromzaehler FROM sensor_stromzaehler WHERE topic = 'stromzaehler leistung' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - "PV": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS PV FROM data WHERE topic = 'solarallpower' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - "Batterie_Strom_PIP": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS Batterie_Strom_PIP FROM pip WHERE topic = 'battery_current' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - "Batterie_Volt_PIP": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS Batterie_Volt_PIP FROM pip WHERE topic = 'battery_voltage' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - "Stromzaehler_Raus": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS Stromzaehler_Raus FROM sensor_stromzaehler WHERE topic = 'stromzaehler leistung raus' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - "Wallbox": f"SELECT DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as timestamp, AVG(data) AS Wallbox_Leistung FROM wallbox WHERE topic = 'power_total' AND timestamp BETWEEN '{start_date}' AND '{end_date}' GROUP BY 1 ORDER BY timestamp ASC", - - } - dataframes = {} - for key, query in queries.items(): - dataframes[key] = pd.read_sql(query, self.conn) + + + + + + + +# if __name__ == '__main__': + + + # estimator = LastEstimator() + # start_date = "2024-06-01" + # end_date = "2024-08-01" + # last_df = estimator.get_last(start_date, end_date) + + # selected_columns = last_df[['timestamp', 'Last']] + # selected_columns['time'] = pd.to_datetime(selected_columns['timestamp']).dt.floor('H') + # selected_columns['Last'] = pd.to_numeric(selected_columns['Last'], errors='coerce') + + # # Drop rows with NaN values + # cleaned_data = selected_columns.dropna() + + # print(cleaned_data) + # # Create an instance of LoadForecast - return dataframes + # lf = LoadForecast(filepath=r'.\load_profiles.npz', year_energy=6000*1000) - def calculate_last(self, dataframes): - # Batterie_Leistung = Batterie_Strom_PIP * Batterie_Volt_PIP - dataframes["Batterie_Leistung"] = dataframes["Batterie_Strom_PIP"].merge(dataframes["Batterie_Volt_PIP"], on="timestamp", how="outer") - dataframes["Batterie_Leistung"]["Batterie_Leistung"] = dataframes["Batterie_Leistung"]["Batterie_Strom_PIP"] * dataframes["Batterie_Leistung"]["Batterie_Volt_PIP"] + # # Initialize an empty DataFrame to hold the forecast data + # forecast_list = [] - # Stromzaehler_Saldo = Stromzaehler - Stromzaehler_Raus - dataframes["Stromzaehler_Saldo"] = dataframes["Stromzaehler"].merge(dataframes["Stromzaehler_Raus"], on="timestamp", how="outer") - dataframes["Stromzaehler_Saldo"]["Stromzaehler_Saldo"] = dataframes["Stromzaehler_Saldo"]["Stromzaehler"] - dataframes["Stromzaehler_Saldo"]["Stromzaehler_Raus"] + # # Loop through each day in the date range + # for single_date in pd.date_range(cleaned_data['time'].min().date(), cleaned_data['time'].max().date()): + # date_str = single_date.strftime('%Y-%m-%d') + # daily_forecast = lf.get_daily_stats(date_str) + # mean_values = daily_forecast[0] # Extract the mean values + # hours = [single_date + pd.Timedelta(hours=i) for i in range(24)] + # daily_forecast_df = pd.DataFrame({'time': hours, 'Last Pred': mean_values}) + # forecast_list.append(daily_forecast_df) - # Stromzaehler_Saldo - Batterie_Leistung - dataframes["Netzleistung"] = dataframes["Stromzaehler_Saldo"].merge(dataframes["Batterie_Leistung"], on="timestamp", how="outer") - dataframes["Netzleistung"]["Netzleistung"] = dataframes["Netzleistung"]["Stromzaehler_Saldo"] - dataframes["Netzleistung"]["Batterie_Leistung"] + # # Concatenate all daily forecasts into a single DataFrame + # forecast_df = pd.concat(forecast_list, ignore_index=True) - # Füge die Wallbox-Leistung hinzu - dataframes["Netzleistung"] = dataframes["Netzleistung"].merge(dataframes["Wallbox"], on="timestamp", how="left") - dataframes["Netzleistung"]["Wallbox_Leistung"] = dataframes["Netzleistung"]["Wallbox_Leistung"].fillna(0) # Fülle fehlende Werte mit 0 + # # Create an instance of the LoadPredictionAdjuster class + # adjuster = LoadPredictionAdjuster(cleaned_data, forecast_df, lf) - # Last = Netzleistung + PV - # Berechne die endgültige Last - dataframes["Last"] = dataframes["Netzleistung"].merge(dataframes["PV"], on="timestamp", how="outer") - dataframes["Last"]["Last_ohneWallbox"] = dataframes["Last"]["Netzleistung"] + dataframes["Last"]["PV"] - dataframes["Last"]["Last"] = dataframes["Last"]["Netzleistung"] + dataframes["Last"]["PV"] - dataframes["Last"]["Wallbox_Leistung"] - return dataframes["Last"].dropna() + # # Calculate the weighted mean differences + # adjuster.calculate_weighted_mean() - def get_last(self, start_date, end_date): - dataframes = self.fetch_data(start_date, end_date) - last_df = self.calculate_last(dataframes) - return last_df + # # Adjust the predictions + # adjuster.adjust_predictions() + # # Plot the results + # adjuster.plot_results() + # # Evaluate the model + # adjuster.evaluate_model() - - -if __name__ == '__main__': - - - estimator = LastEstimator() - start_date = "2024-06-01" - end_date = "2024-08-01" - last_df = estimator.get_last(start_date, end_date) - - selected_columns = last_df[['timestamp', 'Last']] - selected_columns['time'] = pd.to_datetime(selected_columns['timestamp']).dt.floor('H') - selected_columns['Last'] = pd.to_numeric(selected_columns['Last'], errors='coerce') - - # Drop rows with NaN values - cleaned_data = selected_columns.dropna() - - print(cleaned_data) - # Create an instance of LoadForecast - - lf = LoadForecast(filepath=r'.\load_profiles.npz', year_energy=6000*1000) - - # Initialize an empty DataFrame to hold the forecast data - forecast_list = [] - - # Loop through each day in the date range - for single_date in pd.date_range(cleaned_data['time'].min().date(), cleaned_data['time'].max().date()): - date_str = single_date.strftime('%Y-%m-%d') - daily_forecast = lf.get_daily_stats(date_str) - mean_values = daily_forecast[0] # Extract the mean values - hours = [single_date + pd.Timedelta(hours=i) for i in range(24)] - daily_forecast_df = pd.DataFrame({'time': hours, 'Last Pred': mean_values}) - forecast_list.append(daily_forecast_df) - - # Concatenate all daily forecasts into a single DataFrame - forecast_df = pd.concat(forecast_list, ignore_index=True) - - # Create an instance of the LoadPredictionAdjuster class - adjuster = LoadPredictionAdjuster(cleaned_data, forecast_df, lf) - - # Calculate the weighted mean differences - adjuster.calculate_weighted_mean() - - # Adjust the predictions - adjuster.adjust_predictions() - - # Plot the results - adjuster.plot_results() - - # Evaluate the model - adjuster.evaluate_model() - - # Predict the next x hours - future_predictions = adjuster.predict_next_hours(48) - print(future_predictions) \ No newline at end of file + # # Predict the next x hours + # future_predictions = adjuster.predict_next_hours(48) + # print(future_predictions) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 634ab69..21729b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,5 @@ deap scipy scikit-learn pandas -tensorflow joblib1.4.0 mariadb \ No newline at end of file