Skip to content

Commit 5c1321f

Browse files
author
jacquesbach
committed
add config.py & utils.py
1 parent 0936a20 commit 5c1321f

3 files changed

Lines changed: 113 additions & 101 deletions

File tree

app.py

Lines changed: 3 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,17 @@
1616
from sklearn.model_selection import train_test_split
1717
import shap
1818
from flask_mqtt import Mqtt
19+
from config import (DB_FILE, ADMIN_PASS, LATITUDE, LONGITUDE, MODEL_FILE, MQTT_CONFIG, TRAPEZOID_SQL, GAP_THRESHOLD)
20+
from utils import (calculate_eur, calculate_sun_elevation, get_historical_avg_temp, get_weather_forecast, trapezoid_wh)
1921

2022
os.environ['TZ'] = 'Europe/Berlin'
2123
time.tzset()
2224
load_dotenv()
2325

2426
app = Flask(__name__, template_folder='.')
27+
app.config.update(MQTT_CONFIG)
2528
loading_status = {"loading": False}
2629

27-
# ================= KONFIGURATION =================
28-
DB_FILE = "solar_data.db"
29-
ADMIN_PASS = os.getenv("ADMIN_PASS")
30-
LATITUDE = float(os.getenv("LATITUDE", 0.0))
31-
LONGITUDE = float(os.getenv("LONGITUDE", 0.0))
32-
GAP_THRESHOLD = 45 # 3 x 15 Sekunden Logging
33-
MODEL_FILE = "pv_model.pkl"
34-
app.config['MQTT_BROKER_URL'] = os.getenv("MQTT_BROKER_URL")
35-
app.config['MQTT_BROKER_PORT'] = int(os.getenv("MQTT_BROKER_PORT", 1883))
36-
app.config['MQTT_USERNAME'] = os.getenv("MQTT_USERNAME")
37-
app.config['MQTT_PASSWORD'] = os.getenv("MQTT_PASSWORD")
38-
app.config['MQTT_TLS_ENABLED'] = False
39-
40-
TRAPEZOID_SQL = f"""
41-
CASE
42-
WHEN prev_t IS NOT NULL
43-
AND dt > 0
44-
AND dt <= {GAP_THRESHOLD}
45-
THEN ((prev_w + w) / 2.0) * (dt / 3600.0)
46-
ELSE 0
47-
END
48-
"""
49-
# =================================================
50-
5130
mqtt = Mqtt(app)
5231

5332
# Globaler Zwischenspeicher
@@ -332,60 +311,6 @@ def self_heal_daily_stats():
332311
finalize_day(day)
333312
print("Self-Heal abgeschlossen.")
334313

335-
def trapezoid_wh(prev_w, w, dt):
336-
if prev_w is None or dt is None:
337-
return 0.0
338-
if 0 < dt <= GAP_THRESHOLD:
339-
return ((prev_w + w) / 2.0) * (dt / 3600.0)
340-
return 0.0
341-
342-
def calculate_eur(kwh, date_str, prices):
343-
"""
344-
Einheitliche Euro-Berechnung mit hoher Präzision.
345-
Rundung immer auf 6 Nachkommastellen.
346-
"""
347-
for p in prices:
348-
if date_str >= p["date"]:
349-
return round(kwh * p["price"], 6)
350-
return round(kwh * 0.329, 6)
351-
352-
def calculate_sun_elevation(date):
353-
day_of_year = date.timetuple().tm_yday
354-
355-
# vereinfachtes astronomisches Modell
356-
decl = -23.44 * math.cos(math.radians((360/365) * (day_of_year + 10)))
357-
358-
elevation = 90 - abs(LATITUDE - decl)
359-
360-
return max(elevation, 0)
361-
362-
def get_historical_avg_temp(day):
363-
"""
364-
Holt Tagesmitteltemperatur von OpenMeteo Historical API.
365-
"""
366-
try:
367-
url = (
368-
f"https://archive-api.open-meteo.com/v1/archive"
369-
f"?latitude={LATITUDE}"
370-
f"&longitude={LONGITUDE}"
371-
f"&start_date={day}"
372-
f"&end_date={day}"
373-
f"&daily=temperature_2m_mean"
374-
f"&timezone=Europe/Berlin"
375-
)
376-
377-
r = requests.get(url, timeout=5)
378-
data = r.json().get("daily", {})
379-
temps = data.get("temperature_2m_mean", [])
380-
381-
if temps:
382-
return float(temps[0])
383-
384-
except Exception as e:
385-
print("Historical Temp Error:", e)
386-
387-
return 0.0
388-
389314
def build_training_data():
390315
conn = sqlite3.connect(DB_FILE)
391316
c = conn.cursor()
@@ -507,29 +432,6 @@ def load_or_train_model():
507432
train_model()
508433
return joblib.load(MODEL_FILE)
509434

510-
def get_weather_forecast(days=7):
511-
try:
512-
url = (
513-
f"https://api.open-meteo.com/v1/forecast"
514-
f"?latitude={LATITUDE}"
515-
f"&longitude={LONGITUDE}"
516-
f"&daily=cloud_cover_mean,temperature_2m_mean"
517-
f"&timezone=Europe/Berlin"
518-
)
519-
520-
r = requests.get(url, timeout=5)
521-
data = r.json().get("daily", {})
522-
523-
dates = data.get("time", [])
524-
clouds = data.get("cloud_cover_mean", [])
525-
temps = data.get("temperature_2m_mean", [])
526-
527-
return list(zip(dates[:days], clouds[:days], temps[:days]))
528-
529-
except Exception as e:
530-
print("Forecast Weather Error:", e)
531-
return []
532-
533435
@app.route('/')
534436
def index():
535437
return render_template('templates/index.html')

config.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import os
2+
import time
3+
from dotenv import load_dotenv
4+
5+
# Zeitzone setzen
6+
os.environ['TZ'] = 'Europe/Berlin'
7+
time.tzset()
8+
9+
# Umgebungsvariablen laden
10+
load_dotenv()
11+
12+
# ================= KONFIGURATION =================
13+
DB_FILE = "solar_data.db"
14+
ADMIN_PASS = os.getenv("ADMIN_PASS")
15+
LATITUDE = float(os.getenv("LATITUDE", 0.0))
16+
LONGITUDE = float(os.getenv("LONGITUDE", 0.0))
17+
GAP_THRESHOLD = 45 # 3 x 15 Sekunden Logging
18+
MODEL_FILE = "pv_model.pkl"
19+
20+
# MQTT Konfiguration (für die Flask-App Initialisierung)
21+
MQTT_CONFIG = {
22+
'MQTT_BROKER_URL': os.getenv("MQTT_BROKER_URL"),
23+
'MQTT_BROKER_PORT': int(os.getenv("MQTT_BROKER_PORT", 1883)),
24+
'MQTT_USERNAME': os.getenv("MQTT_USERNAME"),
25+
'MQTT_PASSWORD': os.getenv("MQTT_PASSWORD"),
26+
'MQTT_TLS_ENABLED': False
27+
}
28+
29+
# ================= SQL SCHNIPSEL =================
30+
TRAPEZOID_SQL = f"""
31+
CASE
32+
WHEN prev_t IS NOT NULL
33+
AND dt > 0
34+
AND dt <= {GAP_THRESHOLD}
35+
THEN ((prev_w + w) / 2.0) * (dt / 3600.0)
36+
ELSE 0
37+
END
38+
"""

utils.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import math
2+
import requests
3+
from config import LATITUDE, LONGITUDE, GAP_THRESHOLD
4+
5+
def trapezoid_wh(prev_w, w, dt):
6+
"""Manuelle Trapez-Berechnung in Python (falls benötigt)"""
7+
if prev_w is None or dt is None:
8+
return 0.0
9+
if 0 < dt <= GAP_THRESHOLD:
10+
return ((prev_w + w) / 2.0) * (dt / 3600.0)
11+
return 0.0
12+
13+
def calculate_eur(kwh, date_str, prices):
14+
"""
15+
Einheitliche Euro-Berechnung mit hoher Präzision.
16+
Rundung immer auf 6 Nachkommastellen.
17+
"""
18+
for p in prices:
19+
if date_str >= p["date"]:
20+
return round(kwh * p["price"], 6)
21+
return round(kwh * 0.329, 6)
22+
23+
def calculate_sun_elevation(date):
24+
"""Berechnet den ungefähren Sonnenstand basierend auf Breitengrad und Tag im Jahr."""
25+
day_of_year = date.timetuple().tm_yday
26+
# vereinfachtes astronomisches Modell
27+
decl = -23.44 * math.cos(math.radians((360/365) * (day_of_year + 10)))
28+
elevation = 90 - abs(LATITUDE - decl)
29+
return max(elevation, 0)
30+
31+
def get_historical_avg_temp(day):
32+
"""
33+
Holt Tagesmitteltemperatur von OpenMeteo Historical API.
34+
"""
35+
try:
36+
url = (
37+
f"https://archive-api.open-meteo.com/v1/archive"
38+
f"?latitude={LATITUDE}"
39+
f"&longitude={LONGITUDE}"
40+
f"&start_date={day}"
41+
f"&end_date={day}"
42+
f"&daily=temperature_2m_mean"
43+
f"&timezone=Europe/Berlin"
44+
)
45+
r = requests.get(url, timeout=5)
46+
data = r.json().get("daily", {})
47+
temps = data.get("temperature_2m_mean", [])
48+
if temps:
49+
return float(temps[0])
50+
except Exception as e:
51+
print("Historical Temp Error:", e)
52+
return 0.0
53+
54+
def get_weather_forecast(days=7):
55+
"""Holt die Wettervorhersage für die nächsten Tage."""
56+
try:
57+
url = (
58+
f"https://api.open-meteo.com/v1/forecast"
59+
f"?latitude={LATITUDE}"
60+
f"&longitude={LONGITUDE}"
61+
f"&daily=cloud_cover_mean,temperature_2m_mean"
62+
f"&timezone=Europe/Berlin"
63+
)
64+
r = requests.get(url, timeout=5)
65+
data = r.json().get("daily", {})
66+
dates = data.get("time", [])
67+
clouds = data.get("cloud_cover_mean", [])
68+
temps = data.get("temperature_2m_mean", [])
69+
return list(zip(dates[:days], clouds[:days], temps[:days]))
70+
except Exception as e:
71+
print("Forecast Weather Error:", e)
72+
return []

0 commit comments

Comments
 (0)