numbers/src/run.py
Wolfgang Hottgenroth 2c78fba3a6
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
timing
2025-01-30 17:37:55 +01:00

155 lines
5.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Flask, session, g, render_template_string
from flask_session import Session
from flask_oidc import OpenIDConnect
from werkzeug.middleware.proxy_fix import ProxyFix
from loguru import logger
import redis
import json
import os
import plotly.express as px
import pandas as pd
import psycopg
import sqlalchemy
import time
try:
redis_url = os.environ['REDIS_URL']
oidc_client_secrets = os.environ['OIDC_CLIENT_SECRETS']
secret_key = os.environ['SECRET_KEY']
except KeyError as e:
logger.error(f"Required environment variable not set ({e})")
raise e
app = Flask(__name__)
app.config.update({
'SECRET_KEY': secret_key,
'SESSION_TYPE': 'redis',
'SESSION_REDIS': redis.from_url(redis_url),
'OIDC_CLIENT_SECRETS': json.loads(oidc_client_secrets),
'OIDC_SCOPES': 'openid email',
'OIDC_USER_INFO_ENABLED': True,
'SESSION_USE_SIGNER': True,
})
Session(app)
oidc = OpenIDConnect(app)
@app.route('/token_debug', methods=['GET'])
@oidc.require_login
def token_debug():
# Access Token vom Identity Provider abrufen
access_token = oidc.get_access_token()
return json.dumps({
"access_token": access_token
})
@app.route('/')
@oidc.require_login
def index():
try:
stepX_time = time.time()
dbh = psycopg.connect()
engine = sqlalchemy.create_engine("postgresql+psycopg://", creator=lambda: dbh)
step0_time = time.time()
df = pd.read_sql("SELECT month, cast(year AS varchar), current_energy AS value FROM pv_energy_by_month", con=engine)
step1_time = time.time()
duration1 = step1_time - step0_time
logger.info(f"{duration1=}")
fig_1 = px.bar(df, x='month', y='value', color='year', barmode='group')
step2_time = time.time()
duration2 = step2_time - step1_time
logger.info(f"{duration2=}")
fig_1.update_layout(
title=f"Jahreswerte Exportierte Energie {duration1:.3f}, {duration2:.3f}",
xaxis_title="",
yaxis_title="",
legend_title="Jahr",
xaxis=dict(
tickmode="array",
tickvals=list(range(1, 13)), # Monate 112
ticktext=["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"]
),
yaxis=dict(ticksuffix=" kWh")
)
graph_html_1 = fig_1.to_html(full_html=False, default_height='30%')
step3_time = time.time()
df = pd.read_sql("SELECT time_bucket('5 minutes', time) AS bucket, AVG(power) AS avg_power FROM pv_power_v WHERE time >= date_trunc('day', now()) - '1 day'::interval AND time < date_trunc('day', now()) GROUP BY bucket ORDER BY bucket", con=engine)
step4_time = time.time()
duration3 = step4_time - step3_time
logger.info(f"{duration3=}")
fig_2 = px.line(df, x='bucket', y='avg_power')
step5_time = time.time()
duration4 = step5_time - step4_time
logger.info(f"{duration4=}")
fig_2.update_layout(
xaxis_title="",
yaxis_title="",
title=f"Export gestern {duration3:.3f}, {duration4:.3f}",
yaxis=dict(ticksuffix=" W")
)
graph_html_2 = fig_2.to_html(full_html=False, default_height='30%')
step6_time = time.time()
df = pd.read_sql("SELECT time_bucket('5 minutes', time) AS bucket, AVG(power) AS avg_power FROM pv_power_v WHERE time >= date_trunc('day', now()) AND time < date_trunc('day', now()) + '1 day'::interval GROUP BY bucket ORDER BY bucket", con=engine)
step7_time = time.time()
duration5 = step7_time - step6_time
logger.info(f"{duration5=}")
fig_3 = px.line(df, x='bucket', y='avg_power')
step8_time = time.time()
duration6 = step8_time - step7_time
logger.info(f"{duration6=}")
fig_3.update_layout(
xaxis_title="",
yaxis_title="",
title=f"Export heute {duration5:.3f}, {duration6:.3f}",
yaxis=dict(ticksuffix=" W")
)
graph_html_3 = fig_3.to_html(full_html=False, default_height='30%')
stepZ_time = time.time()
duration7 = stepZ_time - stepX_time
logger.info(f"{duration7=}")
return render_template_string(f"""
<html>
<head>
<title>Jahreswerte PV-Energie</title>
</head>
<body>
{graph_html_1}
{graph_html_2}
{graph_html_3}
<div style="height:9vh; background-color:lightgrey; font-family: Courier, Consolas, monospace;">
<table style="border-collapse: collapse;">
<style>table td {{ padding-right: 100px }}</style>
<tr>
<td>Query 1: {duration1:.3f} s</td><td>Graph 1: {duration2:.3f} s</td>
</tr><tr>
<td>Query 2: {duration3:.3f} s</td><td>Graph 2: {duration4:.3f} s</td>
</tr><tr>
<td>Query 3: {duration5:.3f} s</td><td>Graph 3: {duration6:.3f} s</td>
</tr><tr>
<td>Total: {duration7:.3f} s</td><td></td>
</tr>
</table>
</div>
</body>
</html>
""")
except Exception as e:
raise Exception(f"Error when querying energy export values: {e}")
finally:
if dbh is not None:
dbh.close()
if __name__ == '__main__':
app.run(port=8080)
else:
exposed_app = ProxyFix(app, x_for=1, x_host=1)