modified: app.py

modified:   static/css/style.css
This commit is contained in:
simon
2026-04-24 11:40:50 +02:00
parent 7c7c1a7208
commit 919908e4c2
2 changed files with 34 additions and 3 deletions

35
app.py
View File

@@ -72,6 +72,7 @@ MOSMIX_PARAMS = [
"hourly/large/sunshine_duration",
"hourly/large/probability_precipitation_height_gt_0_1mm_last_1h",
"hourly/large/uv_index",
"hourly/large/visibility",
]
def _get_berlin():
@@ -335,14 +336,24 @@ def _parse_warning_datetime(value):
# regen heavy rain
# schnee snow
# blitz thunderstorm (needs additional MOSMIX parameter)
# wolkig_nebel_sonne fog / mist
# nebel dense fog (visibility < 1000 m)
# nebel_wolkig foggy + overcast (1000-5000 m, cloud > 60 %)
# wolkig_nebel_sonne patchy fog / haze (1000-5000 m, less cloud)
# nacht clear night (moon)
# nacht(1) moon behind cloud
# nacht(2) moon+cloud+rain
# nacht(3) moon+cloud+snow
def weather_icon(cloud_pct, precip_mm, rain_prob, temp_c, is_night=False):
def weather_icon(cloud_pct, precip_mm, rain_prob, temp_c, is_night=False, visibility_m=None):
"""Return the icon key for static/icons/{key}.png."""
# Fog (takes priority; fog unlikely when precipitating heavily)
if visibility_m is not None and visibility_m < 5000 and not (precip_mm and precip_mm > 0.5):
if visibility_m < 1000:
return "nebel"
if cloud_pct is not None and cloud_pct > 60:
return "nebel_wolkig"
return "wolkig_nebel_sonne"
# Snow / sleet (day and night)
if temp_c is not None and temp_c <= 2 and (
(precip_mm and precip_mm > 0.1) or (rain_prob and rain_prob >= 40)
@@ -375,6 +386,21 @@ def pick_daily_icon(hours):
"""Choose the most representative icon key for a whole day."""
if not hours:
return "sonne"
# Fog: majority of hours with reduced visibility and no heavy precipitation
fog_hours = [
h for h in hours
if h.get("visibility_m") is not None
and h["visibility_m"] < 5000
and (h.get("precip_mm") or 0) <= 0.5
]
if len(fog_hours) >= len(hours) // 2 and fog_hours:
avg_vis = sum(h["visibility_m"] for h in fog_hours) / len(fog_hours)
avg_cloud_fog = sum(h.get("cloud_pct") or 0 for h in fog_hours) / len(fog_hours)
if avg_vis < 1000:
return "nebel"
if avg_cloud_fog > 60:
return "nebel_wolkig"
return "wolkig_nebel_sonne"
# Snow / sleet
if any(
h.get("temp_c") is not None and h["temp_c"] <= 2
@@ -590,6 +616,8 @@ def get_mosmix_forecast(lat, lon, hours=72):
sun_min = round(float(sun)/60) if not _isnan(sun) else 0
wd = p.get("wind_direction")
wind_dir = float(wd) if not _isnan(wd) else None
vis_raw = p.get("visibility")
visibility_m = round(float(vis_raw)) if not _isnan(vis_raw) else None
uv_raw = p.get("uv_index")
dt_local = pd.Timestamp(date_val).tz_convert(berlin).tz_localize(None)
# Determine day/night for icon selection
@@ -624,7 +652,8 @@ def get_mosmix_forecast(lat, lon, hours=72):
"confidence": confidence_score,
"confidence_label": confidence_label,
"activity_score": a_score,
"icon": weather_icon(clouds, precip, rain_prob, temp_c, is_night=is_night),
"visibility_m": visibility_m,
"icon": weather_icon(clouds, precip, rain_prob, temp_c, is_night=is_night, visibility_m=visibility_m),
})
result_data = (forecast, station_info)
_forecast_cache[cache_key] = result_data