From 9c2855fa98d39c1a195961ce7f9cce8f79523ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20X=2E=20F=C3=BCrst?= Date: Mon, 1 Jun 2026 17:31:07 +0200 Subject: [PATCH] =?UTF-8?q?V=201.6.0=20fix:=20Tagesregen=20per=20MAX=20(ku?= =?UTF-8?q?mulierter=20Tagesz=C3=A4hler,=20Reset=20um=20Mitternacht)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wochenwerte als Summe täglicher Maxima; /weather/stats mit Subquery über tägliche Maxima. Co-Authored-By: Claude Sonnet 4.6 --- api/main.py | 48 +++++++++++++------- docker-compose_postgres.yml | 2 - frontend/package.json | 2 +- frontend/src/App.jsx | 4 +- frontend/src/components/WeatherDashboard.jsx | 12 +++-- 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/api/main.py b/api/main.py index 5b16d7d..10d3a3a 100644 --- a/api/main.py +++ b/api/main.py @@ -270,11 +270,17 @@ async def get_weather_statistics( AVG(pressure) as avg_pressure, AVG(wind_speed * 1.60934) as avg_wind_speed, 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 d2 + WHERE d2.datetime >= NOW() - make_interval(hours => %s) + GROUP BY DATE(d2.datetime) + ) sub) as total_rain, COUNT(*) as data_points FROM weather_data WHERE datetime >= NOW() - make_interval(hours => %s) - """, (hours,)) + """, (hours, hours)) result = cursor.fetchone() if not result or result['data_points'] == 0: @@ -300,7 +306,7 @@ async def get_daily_statistics( AVG(pressure) as avg_pressure, AVG(wind_speed * 1.60934) as avg_wind_speed, MAX(wind_gust * 1.60934) as max_wind_gust, - SUM(rain) as total_rain, + MAX(rain) as total_rain, COUNT(*) as data_points FROM weather_data WHERE datetime >= NOW() - make_interval(days => %s) @@ -387,7 +393,7 @@ async def get_hourly_aggregated_data( AVG(wind_speed * 1.60934) as wind_speed, MAX(wind_gust * 1.60934) as wind_gust, AVG(wind_dir) as wind_dir, - AVG(rain) as rain, + MAX(rain) as rain, AVG(rain_rate) as rain_rate, MAX(received_at) as received_at FROM weather_data @@ -429,7 +435,7 @@ async def get_daily_aggregated_data( 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, AVG(wind_dir)::float as wind_dir, - SUM(rain)::float as total_rain + MAX(rain)::float as total_rain FROM weather_data WHERE datetime >= NOW() - make_interval(days => %s) GROUP BY date_trunc('day', datetime) @@ -469,7 +475,7 @@ async def get_daily_with_minmax_data( 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, AVG(wind_dir)::float as wind_dir, - SUM(rain)::float as total_rain + MAX(rain)::float as total_rain FROM weather_data WHERE datetime >= NOW() - make_interval(days => %s) GROUP BY date_trunc('day', datetime) @@ -490,7 +496,7 @@ async def get_daily_rain_data( cursor.execute(""" SELECT date_trunc('day', datetime) as date, - SUM(rain) as total_rain + MAX(rain) as total_rain FROM weather_data WHERE datetime >= NOW() - make_interval(days => %s) GROUP BY date_trunc('day', datetime) @@ -512,20 +518,28 @@ async def get_weekly_rain_data( if days >= 365: cursor.execute(""" SELECT - date_trunc('week', datetime) as week_start, - SUM(rain) as total_rain - FROM weather_data - GROUP BY date_trunc('week', datetime) + date_trunc('week', day) as week_start, + SUM(daily_rain) as total_rain + FROM ( + SELECT DATE(datetime) as day, MAX(rain) as daily_rain + FROM weather_data + GROUP BY DATE(datetime) + ) sub + GROUP BY date_trunc('week', day) ORDER BY week_start ASC """) else: cursor.execute(""" SELECT - date_trunc('week', datetime) as week_start, - SUM(rain) as total_rain - FROM weather_data - WHERE datetime >= NOW() - make_interval(days => %s) - GROUP BY date_trunc('week', datetime) + date_trunc('week', day) as week_start, + SUM(daily_rain) as total_rain + FROM ( + SELECT DATE(datetime) as day, MAX(rain) as daily_rain + FROM weather_data + WHERE datetime >= NOW() - make_interval(days => %s) + GROUP BY DATE(datetime) + ) sub + GROUP BY date_trunc('week', day) ORDER BY week_start ASC """, (days,)) results = cursor.fetchall() @@ -596,7 +610,7 @@ async def get_daily_aggregated_range( 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, AVG(wind_dir)::float as wind_dir, - SUM(rain)::float as total_rain + MAX(rain)::float as total_rain FROM weather_data WHERE datetime BETWEEN %s AND %s GROUP BY date_trunc('day', datetime) diff --git a/docker-compose_postgres.yml b/docker-compose_postgres.yml index 412785b..d60dfb2 100644 --- a/docker-compose_postgres.yml +++ b/docker-compose_postgres.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: postgres: image: postgres:16-alpine diff --git a/frontend/package.json b/frontend/package.json index 941bef8..77373c2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "wetterstation-frontend", "private": true, - "version": "1.5.9", + "version": "1.6.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 700b093..0ccef6f 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -26,8 +26,8 @@ function buildUrls(timeRange) { const days = timeRange.days || 1 const path = days >= 7 ? 'daily-aggregated-range' : 'hourly-aggregated-range' return { - weatherUrl: `${API_BASE}/weather/${path}?start=${start}&end=${end}`, - rainUrl: null, // TODO: Regen-Aggregation fuer Range implementieren + weatherUrl: `${API_BASE}/weather/${path}?start=${start}&end=${end}`, + rainUrl: days < 7 ? `${API_BASE}/weather/daily-aggregated-range?start=${start}&end=${end}` : null, needsCurrent: true, } } diff --git a/frontend/src/components/WeatherDashboard.jsx b/frontend/src/components/WeatherDashboard.jsx index a0c3cdc..1d94239 100644 --- a/frontend/src/components/WeatherDashboard.jsx +++ b/frontend/src/components/WeatherDashboard.jsx @@ -171,14 +171,14 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = ' // Spezieller Suffix für Regen const rainSuffix = useMemo(() => { if (typeof timeRange === 'object' && timeRange.type === 'custom') { - const days = timeRange.days || 1 - return days >= 7 ? ' (pro Tag)' : '' + return ' (pro Tag)' } switch (timeRange) { case '7d': case '30d': - case '365d': return ' (pro Tag)' + case '365d': + return ' (pro Woche)' default: return '' } @@ -639,11 +639,13 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = ' } }] } else if (typeof timeRange === 'object' && timeRange.type === 'custom') { - // Custom range: tägliche Summen aus sortedData (total_rain ist im daily-aggregated-range enthalten) + // Custom range: tägliche Summen — bei kurzen Ranges (<7d) aus rainData (extra Fetch), + // bei langen Ranges aus sortedData (daily-aggregated-range enthält total_rain) yAxisTitle = 'Regen (mm pro Tag)' + const rainSource = rainData.length > 0 ? rainData : sortedData series = [{ name: 'Regen', - data: sortedData + data: rainSource .filter(item => item.total_rain != null && item.total_rain > 0) .map(item => [new Date(item.datetime).getTime(), item.total_rain]), color: 'rgb(54, 162, 235)',