2024-02-16 12:57:09 +01:00
from flask import Flask , jsonify , request
import numpy as np
2024-08-30 11:49:44 +02:00
from datetime import datetime , timedelta
2024-02-16 12:57:09 +01:00
from pprint import pprint
2024-02-25 15:12:10 +01:00
import json , sys , os
import requests , hashlib
2024-08-30 11:49:44 +02:00
from dateutil import parser
import pandas as pd
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
class ForecastData :
2024-08-30 11:49:44 +02:00
def __init__ ( self , date_time , dc_power , ac_power , windspeed_10m = None , temperature = None , ac_power_measurement = None ) :
2024-02-25 15:12:10 +01:00
self . date_time = date_time
self . dc_power = dc_power
self . ac_power = ac_power
self . windspeed_10m = windspeed_10m
self . temperature = temperature
2024-08-30 11:49:44 +02:00
self . ac_power_measurement = ac_power_measurement
2024-02-25 15:12:10 +01:00
def get_date_time ( self ) :
return self . date_time
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
def get_dc_power ( self ) :
return self . dc_power
2024-02-16 12:57:09 +01:00
2024-03-31 13:00:01 +02:00
def ac_power_measurement ( self ) :
return self . ac_power_measurement
2024-02-25 15:12:10 +01:00
def get_ac_power ( self ) :
2024-08-30 11:49:44 +02:00
if self . ac_power_measurement is not None :
2024-03-31 13:00:01 +02:00
return self . ac_power_measurement
else :
return self . ac_power
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
def get_windspeed_10m ( self ) :
return self . windspeed_10m
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
def get_temperature ( self ) :
return self . temperature
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
class PVForecast :
2024-08-30 11:49:44 +02:00
def __init__ ( self , filepath = None , url = None , cache_dir = ' cache ' , prediction_hours = 48 ) :
2024-02-16 12:57:09 +01:00
self . meta = { }
self . forecast_data = [ ]
2024-02-25 15:12:10 +01:00
self . cache_dir = cache_dir
2024-03-03 10:03:32 +01:00
self . prediction_hours = prediction_hours
2024-03-31 13:00:01 +02:00
self . current_measurement = None
2024-08-30 11:49:44 +02:00
2024-02-25 15:12:10 +01:00
if not os . path . exists ( self . cache_dir ) :
os . makedirs ( self . cache_dir )
if filepath :
self . load_data_from_file ( filepath )
elif url :
self . load_data_with_caching ( url )
2024-08-30 11:49:44 +02:00
2024-03-03 10:03:32 +01:00
if len ( self . forecast_data ) < self . prediction_hours :
raise ValueError ( f " Die Vorhersage muss mindestens { self . prediction_hours } Stunden umfassen, aber es wurden nur { len ( self . forecast_data ) } Stunden vorhergesagt. " )
2024-03-31 13:00:01 +02:00
def update_ac_power_measurement ( self , date_time = None , ac_power_measurement = None ) :
found = False
2024-08-30 11:49:44 +02:00
input_date_hour = date_time . replace ( minute = 0 , second = 0 , microsecond = 0 )
2024-03-31 13:00:01 +02:00
for forecast in self . forecast_data :
2024-08-30 11:49:44 +02:00
forecast_date_hour = parser . parse ( forecast . date_time ) . replace ( minute = 0 , second = 0 , microsecond = 0 )
2024-03-31 13:00:01 +02:00
if forecast_date_hour == input_date_hour :
forecast . ac_power_measurement = ac_power_measurement
found = True
break
2024-02-16 12:57:09 +01:00
2024-02-25 15:12:10 +01:00
def process_data ( self , data ) :
self . meta = data . get ( ' meta ' , { } )
2024-03-08 14:22:11 +01:00
all_values = data . get ( ' values ' , [ ] )
2024-08-30 11:49:44 +02:00
2024-03-08 14:22:11 +01:00
for i in range ( len ( all_values [ 0 ] ) ) : # Annahme, dass alle Listen gleich lang sind
sum_dc_power = sum ( values [ i ] [ ' dcPower ' ] for values in all_values )
sum_ac_power = sum ( values [ i ] [ ' power ' ] for values in all_values )
2024-08-30 11:49:44 +02:00
# Zeige die ursprünglichen und berechneten Zeitstempel an
original_datetime = all_values [ 0 ] [ i ] . get ( ' datetime ' )
#print(original_datetime," ",sum_dc_power," ",all_values[0][i]['dcPower'])
dt = datetime . strptime ( original_datetime , " % Y- % m- %d T % H: % M: % S. %f % z " )
dt = dt . replace ( tzinfo = None )
#iso_datetime = parser.parse(original_datetime).isoformat() # Konvertiere zu ISO-Format
#print()
# Optional: 2 Stunden abziehen, um die Zeitanpassung zu testen
#adjusted_datetime = parser.parse(original_datetime) - timedelta(hours=2)
#print(f"Angepasste Zeitstempel: {adjusted_datetime.isoformat()}")
2024-02-25 15:12:10 +01:00
forecast = ForecastData (
2024-08-30 11:49:44 +02:00
date_time = dt , # Verwende angepassten Zeitstempel
2024-03-08 14:22:11 +01:00
dc_power = sum_dc_power ,
ac_power = sum_ac_power ,
windspeed_10m = all_values [ 0 ] [ i ] . get ( ' windspeed_10m ' ) ,
temperature = all_values [ 0 ] [ i ] . get ( ' temperature ' )
2024-02-25 15:12:10 +01:00
)
2024-03-08 14:22:11 +01:00
2024-08-30 11:49:44 +02:00
self . forecast_data . append ( forecast )
2024-02-25 15:12:10 +01:00
def load_data_from_file ( self , filepath ) :
with open ( filepath , ' r ' ) as file :
2024-02-16 12:57:09 +01:00
data = json . load ( file )
2024-02-25 15:12:10 +01:00
self . process_data ( data )
def load_data_from_url ( self , url ) :
response = requests . get ( url )
if response . status_code == 200 :
data = response . json ( )
pprint ( data )
self . process_data ( data )
else :
print ( f " Failed to load data from { url } . Status Code: { response . status_code } " )
self . load_data_from_url ( url )
def load_data_with_caching ( self , url ) :
2024-08-30 11:49:44 +02:00
date = datetime . now ( ) . strftime ( " % Y- % m- %d " )
2024-03-03 10:03:32 +01:00
2024-08-30 11:49:44 +02:00
cache_file = os . path . join ( self . cache_dir , self . generate_cache_filename ( url , date ) )
2024-02-25 15:12:10 +01:00
if os . path . exists ( cache_file ) :
with open ( cache_file , ' r ' ) as file :
data = json . load ( file )
print ( " Loading data from cache. " )
else :
response = requests . get ( url )
if response . status_code == 200 :
data = response . json ( )
with open ( cache_file , ' w ' ) as file :
json . dump ( data , file )
print ( " Data fetched from URL and cached. " )
else :
print ( f " Failed to load data from { url } . Status Code: { response . status_code } " )
return
self . process_data ( data )
2024-08-30 11:49:44 +02:00
def generate_cache_filename ( self , url , date ) :
2024-03-03 10:03:32 +01:00
cache_key = hashlib . sha256 ( f " { url } { date } " . encode ( ' utf-8 ' ) ) . hexdigest ( )
return f " cache_ { cache_key } .json "
2024-02-16 12:57:09 +01:00
def get_forecast_data ( self ) :
return self . forecast_data
2024-02-18 21:28:02 +01:00
def get_temperature_forecast_for_date ( self , input_date_str ) :
input_date = datetime . strptime ( input_date_str , " % Y- % m- %d " )
2024-08-30 11:49:44 +02:00
daily_forecast_obj = [ data for data in self . forecast_data if parser . parse ( data . get_date_time ( ) ) . date ( ) == input_date . date ( ) ]
2024-02-18 21:28:02 +01:00
daily_forecast = [ ]
for d in daily_forecast_obj :
daily_forecast . append ( d . get_temperature ( ) )
return np . array ( daily_forecast )
2024-02-18 14:32:27 +01:00
2024-02-25 16:47:28 +01:00
def get_pv_forecast_for_date_range ( self , start_date_str , end_date_str ) :
start_date = datetime . strptime ( start_date_str , " % Y- % m- %d " ) . date ( )
end_date = datetime . strptime ( end_date_str , " % Y- % m- %d " ) . date ( )
date_range_forecast = [ ]
2024-03-03 10:03:32 +01:00
2024-02-25 16:47:28 +01:00
for data in self . forecast_data :
2024-08-30 11:49:44 +02:00
data_date = data . get_date_time ( ) . date ( ) #parser.parse(data.get_date_time()).date()
2024-02-25 16:47:28 +01:00
if start_date < = data_date < = end_date :
date_range_forecast . append ( data )
2024-08-30 11:49:44 +02:00
print ( data . get_date_time ( ) , " " , data . get_ac_power ( ) )
2024-02-25 16:47:28 +01:00
ac_power_forecast = np . array ( [ data . get_ac_power ( ) for data in date_range_forecast ] )
2024-03-03 10:03:32 +01:00
return np . array ( ac_power_forecast ) [ : self . prediction_hours ]
2024-02-25 16:47:28 +01:00
def get_temperature_for_date_range ( self , start_date_str , end_date_str ) :
start_date = datetime . strptime ( start_date_str , " % Y- % m- %d " ) . date ( )
end_date = datetime . strptime ( end_date_str , " % Y- % m- %d " ) . date ( )
date_range_forecast = [ ]
for data in self . forecast_data :
2024-08-30 11:49:44 +02:00
data_date = data . get_date_time ( ) . date ( )
2024-02-25 16:47:28 +01:00
if start_date < = data_date < = end_date :
date_range_forecast . append ( data )
2024-08-30 11:49:44 +02:00
temperature_forecast = [ data . get_temperature ( ) for data in date_range_forecast ]
2024-03-03 10:03:32 +01:00
return np . array ( temperature_forecast ) [ : self . prediction_hours ]
2024-08-30 11:49:44 +02:00
def get_forecast_dataframe ( self ) :
# Wandelt die Vorhersagedaten in ein Pandas DataFrame um
data = [ {
' date_time ' : f . get_date_time ( ) ,
' dc_power ' : f . get_dc_power ( ) ,
' ac_power ' : f . get_ac_power ( ) ,
' windspeed_10m ' : f . get_windspeed_10m ( ) ,
' temperature ' : f . get_temperature ( )
} for f in self . forecast_data ]
# Erstelle ein DataFrame
df = pd . DataFrame ( data )
return df
2024-02-25 16:47:28 +01:00
2024-03-31 13:00:01 +02:00
def print_ac_power_and_measurement ( self ) :
2024-08-30 11:49:44 +02:00
""" Druckt die DC-Leistung und den Messwert für jede Stunde. """
2024-03-31 13:00:01 +02:00
for forecast in self . forecast_data :
date_time = forecast . date_time
2024-08-30 11:49:44 +02:00
print ( f " Zeit: { date_time } , DC: { forecast . dc_power } , AC: { forecast . ac_power } , Messwert: { forecast . ac_power_measurement } , AC GET: { forecast . get_ac_power ( ) } " )
2024-02-16 12:57:09 +01:00
# Beispiel für die Verwendung der Klasse
if __name__ == ' __main__ ' :
2024-08-30 11:49:44 +02:00
forecast = PVForecast ( prediction_hours = 24 , url = " https://api.akkudoktor.net/forecast?lat=52.52&lon=13.405&power=5000&azimuth=-10&tilt=7&powerInvertor=10000&horizont=20,27,22,20&power=4800&azimuth=-90&tilt=7&powerInvertor=10000&horizont=30,30,30,50&power=1400&azimuth=-40&tilt=60&powerInvertor=2000&horizont=60,30,0,30&power=1600&azimuth=5&tilt=45&powerInvertor=1400&horizont=45,25,30,60&past_days=5&cellCoEff=-0.36&inverterEfficiency=0.8&albedo=0.25&timezone=Europe %2F Berlin&hourly=relativehumidity_2m % 2Cwindspeed_10m " )
2024-03-31 13:00:01 +02:00
forecast . update_ac_power_measurement ( date_time = datetime . now ( ) , ac_power_measurement = 1000 )
forecast . print_ac_power_and_measurement ( )