Compare commits
5 Commits
d12228e662
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f4fa3df73a | |||
| db8feb317e | |||
| 91f4a7e4d2 | |||
| 37127fada3 | |||
| 396587554a |
@@ -5,6 +5,9 @@ WORKDIR /app
|
|||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
ARG VERSION=unknown
|
||||||
|
ENV APP_VERSION=${VERSION}
|
||||||
|
|
||||||
COPY weather_report.py .
|
COPY weather_report.py .
|
||||||
|
|
||||||
RUN mkdir -p images
|
RUN mkdir -p images
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "weather2oag"
|
name = "weather2oag"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
description = "Monatlicher Wetterbericht der Sternwarte Welzheim"
|
description = "Monatlicher Wetterbericht der Sternwarte Welzheim"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
+18
-26
@@ -2,11 +2,9 @@
|
|||||||
"""Erstellt einen kombinierten Wetterbericht für den letzten Kalendermonat."""
|
"""Erstellt einen kombinierten Wetterbericht für den letzten Kalendermonat."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
|
||||||
import re
|
|
||||||
import smtplib
|
import smtplib
|
||||||
import tempfile
|
import tempfile
|
||||||
from collections import defaultdict
|
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from email.mime.image import MIMEImage
|
from email.mime.image import MIMEImage
|
||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
@@ -20,9 +18,7 @@ from dotenv import load_dotenv
|
|||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
_v = re.search(r'^version\s*=\s*"([^"]+)"',
|
VERSION = os.getenv("APP_VERSION", "?")
|
||||||
pathlib.Path("pyproject.toml").read_text(), re.MULTILINE)
|
|
||||||
VERSION = _v.group(1) if _v else "?"
|
|
||||||
|
|
||||||
API_BASE_URL = os.getenv("API_BASE_URL", "https://stwwetter.fuerst-stuttgart.de/api")
|
API_BASE_URL = os.getenv("API_BASE_URL", "https://stwwetter.fuerst-stuttgart.de/api")
|
||||||
MAIL_SERVER = os.getenv("MAIL_SERVER")
|
MAIL_SERVER = os.getenv("MAIL_SERVER")
|
||||||
@@ -52,8 +48,8 @@ plt.rcParams.update({
|
|||||||
def last_month_range() -> tuple[datetime, datetime, str]:
|
def last_month_range() -> tuple[datetime, datetime, str]:
|
||||||
today = datetime.now(timezone.utc)
|
today = datetime.now(timezone.utc)
|
||||||
first_of_this = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
first_of_this = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||||
end = first_of_this - timedelta(seconds=1)
|
start = (first_of_this - timedelta(days=1)).replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||||
start = end.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
end = first_of_this + timedelta(days=1) # inkl. 1. Folgemonat
|
||||||
label = f"{MONTHS_DE[start.month - 1]} {start.year}"
|
label = f"{MONTHS_DE[start.month - 1]} {start.year}"
|
||||||
return start, end, label
|
return start, end, label
|
||||||
|
|
||||||
@@ -89,23 +85,19 @@ def _data_temp_hourly(start: datetime, end: datetime):
|
|||||||
|
|
||||||
|
|
||||||
def _data_rain_daily(start: datetime, end: datetime):
|
def _data_rain_daily(start: datetime, end: datetime):
|
||||||
data = fetch("/weather/range", {
|
today = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
"start": start.isoformat(), "end": end.isoformat(), "limit": 50000,
|
days = min((today - start).days + 2, 365)
|
||||||
})
|
data = fetch("/weather/rain-daily", {"days": days})
|
||||||
by_day: dict[str, list[float]] = defaultdict(list)
|
pairs = []
|
||||||
for d in data:
|
for d in data:
|
||||||
if d.get("rain") is not None:
|
day_dt = parse_dt(d["date"]).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
by_day[parse_dt(d["datetime"]).strftime("%Y-%m-%d")].append(d["rain"])
|
if start <= day_dt < end:
|
||||||
|
pairs.append((day_dt, round(d["total_rain"], 1)))
|
||||||
dates, rain = [], []
|
pairs.sort()
|
||||||
for day_key in sorted(by_day):
|
if not pairs:
|
||||||
vals = by_day[day_key]
|
return [], []
|
||||||
daily = max(vals) - min(vals)
|
dates, rain = zip(*pairs)
|
||||||
if daily < 0:
|
return list(dates), list(rain)
|
||||||
daily = max(vals)
|
|
||||||
dates.append(datetime.fromisoformat(day_key).replace(tzinfo=timezone.utc))
|
|
||||||
rain.append(round(daily, 1))
|
|
||||||
return dates, rain
|
|
||||||
|
|
||||||
|
|
||||||
def create_combined_chart(start: datetime, end: datetime, label: str) -> bytes:
|
def create_combined_chart(start: datetime, end: datetime, label: str) -> bytes:
|
||||||
@@ -125,7 +117,7 @@ def create_combined_chart(start: datetime, end: datetime, label: str) -> bytes:
|
|||||||
ax.fill_between(dates_mm, t_min, t_max, alpha=0.12, color="#888888")
|
ax.fill_between(dates_mm, t_min, t_max, alpha=0.12, color="#888888")
|
||||||
ax.set_title("Temperaturverlauf (Tages-Min / Tages-Max)", fontweight="bold", pad=10)
|
ax.set_title("Temperaturverlauf (Tages-Min / Tages-Max)", fontweight="bold", pad=10)
|
||||||
ax.set_ylabel("Temperatur (°C)")
|
ax.set_ylabel("Temperatur (°C)")
|
||||||
ax.set_xlim(start, end)
|
ax.set_xlim(start - timedelta(hours=12), end + timedelta(hours=12))
|
||||||
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
|
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
|
||||||
ax.xaxis.set_major_locator(mdates.DayLocator(interval=3))
|
ax.xaxis.set_major_locator(mdates.DayLocator(interval=3))
|
||||||
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
|
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
|
||||||
@@ -136,7 +128,7 @@ def create_combined_chart(start: datetime, end: datetime, label: str) -> bytes:
|
|||||||
ax.plot(dates_h, temps, color="#2a7be0", linewidth=1.5, label="Stundenmittel")
|
ax.plot(dates_h, temps, color="#2a7be0", linewidth=1.5, label="Stundenmittel")
|
||||||
ax.set_title("Temperaturverlauf (Stundenmittel)", fontweight="bold", pad=10)
|
ax.set_title("Temperaturverlauf (Stundenmittel)", fontweight="bold", pad=10)
|
||||||
ax.set_ylabel("Temperatur (°C)")
|
ax.set_ylabel("Temperatur (°C)")
|
||||||
ax.set_xlim(start, end)
|
ax.set_xlim(start - timedelta(hours=12), end + timedelta(hours=12))
|
||||||
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
|
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m."))
|
||||||
ax.xaxis.set_major_locator(mdates.DayLocator(interval=3))
|
ax.xaxis.set_major_locator(mdates.DayLocator(interval=3))
|
||||||
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
|
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
|
||||||
|
|||||||
Reference in New Issue
Block a user