"""Weather widget: one of four display modes (see models. WeatherWidgetConfig) backed by a pluggable provider (app/weather/'s PROVIDERS registry -- Open-Meteo or NWS) and drawn by app/weather_render. py's build() dispatch -- or, for "current"/"daily" modes with render_style="modern", by app/html_render.py's Jinja2/headless-Chromium renderer instead (experimental; hourly/multi_city always render classic regardless of render_style, see html_render's module docstring). No real "next"/"back" concept (same as whiteboard) -- a single "check now" action forces a re-fetch bypassing the normal throttle.""" from __future__ import annotations from PIL import Image from sqlalchemy.orm import Session from .. import weather_render from ..models import Frame, WeatherWidgetConfig, Widget from ..routers.common import get_or_refresh_weather_widget_data from ._shared import placeholder_image ACTION_LABELS = {"check_now": "Check for updates"} def render(db: Session, frame: Frame, widget: Widget, target_w: int, target_h: int, is_normal_wake: bool = True) -> Image.Image: """is_normal_wake is unused here -- see app/widgets/photos.py's identical note; every widget type's render() shares one call signature regardless of which ones actually care.""" cfg = db.get(WeatherWidgetConfig, widget.id) data = get_or_refresh_weather_widget_data(db, frame, widget) if data is None: return placeholder_image(target_w, target_h, ["Weather widget", "not configured yet"]) if cfg.render_style == "modern" and cfg.mode in ("current", "daily"): # Local import: html_render pulls in Playwright, a real headless- # Chromium dependency -- every other widget type, and this one's # own classic/hourly/multi_city paths, should never pay for it # (same reasoning as image_pipeline.render_placeholder's local # `import qrcode`). from .. import html_render return html_render.build(cfg.mode, data, target_w, target_h, frame.palette_rgb, cfg.units, city_label=cfg.city_label or "", theme_name=frame.theme) return weather_render.build( cfg.mode, data, target_w, target_h, frame.palette_rgb, cfg.units, city_label=cfg.city_label or "", interval_hours=cfg.hourly_interval_hours, ) def _check_now(db: Session, frame: Frame, widget: Widget) -> None: get_or_refresh_weather_widget_data(db, frame, widget, force=True) ACTIONS = {"check_now": _check_now}