Compare commits

...

2 Commits

Author SHA1 Message Date
admin 4abaf5ee17 fix: pgAdmin nur intern erreichbar (kein öffentlicher Traefik-Zugang)
Zugriff nur noch per SSH-Tunnel, nicht mehr über stwwetter.fuerst-stuttgart.de/pgadmin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:09:48 +02:00
admin 779a76dd92 V 1.5.7 fix: Tagesregen per MAX statt SUM (Server kumuliert selbst)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:53:00 +02:00
3 changed files with 49 additions and 21 deletions
+29 -20
View File
@@ -270,11 +270,16 @@ async def get_weather_statistics(
AVG(pressure) as avg_pressure, AVG(pressure) as avg_pressure,
AVG(wind_speed * 1.60934) as avg_wind_speed, AVG(wind_speed * 1.60934) as avg_wind_speed,
MAX(wind_gust * 1.60934) as max_wind_gust, MAX(wind_gust * 1.60934) as max_wind_gust,
SUM(rain) as total_rain, (SELECT COALESCE(SUM(daily_max), 0) FROM (
SELECT MAX(rain) as daily_max
FROM weather_data
WHERE datetime >= NOW() - make_interval(hours => %s)
GROUP BY DATE(datetime)
) sub) as total_rain,
COUNT(*) as data_points COUNT(*) as data_points
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(hours => %s) WHERE datetime >= NOW() - make_interval(hours => %s)
""", (hours,)) """, (hours, hours))
result = cursor.fetchone() result = cursor.fetchone()
if not result or result['data_points'] == 0: if not result or result['data_points'] == 0:
@@ -300,7 +305,7 @@ async def get_daily_statistics(
AVG(pressure) as avg_pressure, AVG(pressure) as avg_pressure,
AVG(wind_speed * 1.60934) as avg_wind_speed, AVG(wind_speed * 1.60934) as avg_wind_speed,
MAX(wind_gust * 1.60934) as max_wind_gust, MAX(wind_gust * 1.60934) as max_wind_gust,
SUM(rain) as total_rain, MAX(rain) as total_rain,
COUNT(*) as data_points COUNT(*) as data_points
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(days => %s) WHERE datetime >= NOW() - make_interval(days => %s)
@@ -429,14 +434,14 @@ async def get_daily_aggregated_data(
MAX(wind_gust * 1.60934)::float as wind_gust, MAX(wind_gust * 1.60934)::float as wind_gust,
(array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time,
AVG(wind_dir)::float as wind_dir, AVG(wind_dir)::float as wind_dir,
SUM(rain)::float as total_rain MAX(rain)::float as total_rain
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(days => %s) WHERE datetime >= NOW() - make_interval(days => %s)
GROUP BY date_trunc('day', datetime) GROUP BY date_trunc('day', datetime)
ORDER BY datetime ASC ORDER BY datetime ASC
""", (days,)) """, (days,))
results = cursor.fetchall() results = cursor.fetchall()
return [dict(row) for row in results] return [dict(row) for row in results]
@@ -469,7 +474,7 @@ async def get_daily_with_minmax_data(
MAX(wind_gust * 1.60934)::float as wind_gust, MAX(wind_gust * 1.60934)::float as wind_gust,
(array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time,
AVG(wind_dir)::float as wind_dir, AVG(wind_dir)::float as wind_dir,
SUM(rain)::float as total_rain MAX(rain)::float as total_rain
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(days => %s) WHERE datetime >= NOW() - make_interval(days => %s)
GROUP BY date_trunc('day', datetime) GROUP BY date_trunc('day', datetime)
@@ -488,9 +493,9 @@ async def get_daily_rain_data(
"""Gibt tägliche Regensummen zurück""" """Gibt tägliche Regensummen zurück"""
with conn.cursor() as cursor: with conn.cursor() as cursor:
cursor.execute(""" cursor.execute("""
SELECT SELECT
date_trunc('day', datetime) as date, date_trunc('day', datetime) as date,
SUM(rain) as total_rain MAX(rain) as total_rain
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(days => %s) WHERE datetime >= NOW() - make_interval(days => %s)
GROUP BY date_trunc('day', datetime) GROUP BY date_trunc('day', datetime)
@@ -511,21 +516,25 @@ async def get_weekly_rain_data(
# Bei 365 Tagen: alle verfügbaren Daten zurückgeben # Bei 365 Tagen: alle verfügbaren Daten zurückgeben
if days >= 365: if days >= 365:
cursor.execute(""" cursor.execute("""
SELECT SELECT week_start, SUM(daily_max) as total_rain
date_trunc('week', datetime) as week_start, FROM (
SUM(rain) as total_rain SELECT date_trunc('week', datetime) as week_start, MAX(rain) as daily_max
FROM weather_data FROM weather_data
GROUP BY date_trunc('week', datetime) GROUP BY date_trunc('week', datetime), DATE(datetime)
) sub
GROUP BY week_start
ORDER BY week_start ASC ORDER BY week_start ASC
""") """)
else: else:
cursor.execute(""" cursor.execute("""
SELECT SELECT week_start, SUM(daily_max) as total_rain
date_trunc('week', datetime) as week_start, FROM (
SUM(rain) as total_rain SELECT date_trunc('week', datetime) as week_start, MAX(rain) as daily_max
FROM weather_data FROM weather_data
WHERE datetime >= NOW() - make_interval(days => %s) WHERE datetime >= NOW() - make_interval(days => %s)
GROUP BY date_trunc('week', datetime) GROUP BY date_trunc('week', datetime), DATE(datetime)
) sub
GROUP BY week_start
ORDER BY week_start ASC ORDER BY week_start ASC
""", (days,)) """, (days,))
results = cursor.fetchall() results = cursor.fetchall()
@@ -596,7 +605,7 @@ async def get_daily_aggregated_range(
MAX(wind_gust * 1.60934)::float as wind_gust, MAX(wind_gust * 1.60934)::float as wind_gust,
(array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time,
AVG(wind_dir)::float as wind_dir, AVG(wind_dir)::float as wind_dir,
SUM(rain)::float as total_rain MAX(rain)::float as total_rain
FROM weather_data FROM weather_data
WHERE datetime BETWEEN %s AND %s WHERE datetime BETWEEN %s AND %s
GROUP BY date_trunc('day', datetime) GROUP BY date_trunc('day', datetime)
+19
View File
@@ -92,6 +92,23 @@ services:
- "traefik.http.routers.wetterstation.tls.certresolver=letsencrypt" - "traefik.http.routers.wetterstation.tls.certresolver=letsencrypt"
- "traefik.http.services.wetterstation.loadbalancer.server.port=80" - "traefik.http.services.wetterstation.loadbalancer.server.port=80"
pgadmin:
image: dpage/pgadmin4:latest
container_name: wetterstation_pgadmin_prod
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
PGADMIN_CONFIG_SERVER_MODE: 'True'
volumes:
- pgadmin_data:/var/lib/pgadmin
depends_on:
- postgres
networks:
- internal
labels:
- "traefik.enable=false"
monitor: monitor:
image: docker.citysensor.de/wetterstation-monitor:latest image: docker.citysensor.de/wetterstation-monitor:latest
container_name: wetterstation_monitor_prod container_name: wetterstation_monitor_prod
@@ -102,6 +119,8 @@ services:
volumes: volumes:
postgres_data: postgres_data:
name: wetterstation_postgres_data_prod name: wetterstation_postgres_data_prod
pgadmin_data:
name: wetterstation_pgadmin_data_prod
networks: networks:
internal: internal:
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "wetterstation-frontend", "name": "wetterstation-frontend",
"private": true, "private": true,
"version": "1.5.6", "version": "1.5.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",