Make weather update interval configurable, was hardcoded to 30 min
Screen.poll_interval was a fixed class attribute the scheduler read directly -- added Screen.get_poll_interval(settings) so a screen can make it settings-driven instead. WeatherScreen overrides it to read a new "update_minutes" field (default 30, matching the old hardcoded value). New number input on the Weather settings page. Caught a real edge case while testing: `raw or 30` treats an explicit 0 as falsy and silently replaces it with 30 instead of clamping to the 1-minute floor. Not reachable via the UI (min="1" on the input) but the method should still be correct standalone -- fixed with an explicit None-check instead.
This commit is contained in:
1 parent
15c7c38d86
commit
889c062212
5 files changed
+29
-3
No files matched your search
+2
-1
@@ -180,8 +180,9 @@ class Scheduler:
|
|||||||
def _poll_screen(self, screen_id: str) -> tuple[str, object, bool]:
|
def _poll_screen(self, screen_id: str) -> tuple[str, object, bool]:
|
||||||
cache = self._caches[screen_id]
|
cache = self._caches[screen_id]
|
||||||
screen = self.screens[screen_id]
|
screen = self.screens[screen_id]
|
||||||
|
settings = self.config.get_screen_settings(screen_id)
|
||||||
checked = False
|
checked = False
|
||||||
if cache.is_stale(screen.poll_interval):
|
if cache.is_stale(screen.get_poll_interval(settings)):
|
||||||
cache.state = self._check(screen_id)
|
cache.state = self._check(screen_id)
|
||||||
cache.checked_at = time.time()
|
cache.checked_at = time.time()
|
||||||
checked = True
|
checked = True
|
||||||
|
|||||||
@@ -26,3 +26,9 @@ class Screen(ABC):
|
|||||||
"""Settings this screen needs, with defaults, merged under config.json's
|
"""Settings this screen needs, with defaults, merged under config.json's
|
||||||
settings[self.id] on first run."""
|
settings[self.id] on first run."""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def get_poll_interval(self, settings: dict) -> int:
|
||||||
|
"""Seconds between check() calls. Override to make it configurable
|
||||||
|
via settings (e.g. a user-facing "update every N minutes" field);
|
||||||
|
defaults to the fixed class-level poll_interval."""
|
||||||
|
return self.poll_interval
|
||||||
+13
-2
@@ -22,10 +22,21 @@ WEEKDAY_ABBR_DE = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
|
|||||||
class WeatherScreen(Screen):
|
class WeatherScreen(Screen):
|
||||||
id = "weather"
|
id = "weather"
|
||||||
display_name = "Weather"
|
display_name = "Weather"
|
||||||
poll_interval = 1800 # 30 minutes -- weather doesn't need to be fresher
|
poll_interval = 1800 # fallback default (30 min) if settings has no update_minutes yet
|
||||||
|
|
||||||
def default_settings(self) -> dict:
|
def default_settings(self) -> dict:
|
||||||
return {"city": "", "latitude": None, "longitude": None, "forecast_days": 3}
|
return {"city": "", "latitude": None, "longitude": None, "forecast_days": 3, "update_minutes": 30}
|
||||||
|
|
||||||
|
def get_poll_interval(self, settings: dict) -> int:
|
||||||
|
raw = settings.get("update_minutes")
|
||||||
|
try:
|
||||||
|
# `raw or 30` would also catch a legitimate 0 (falsy) and silently
|
||||||
|
# replace it with 30 instead of clamping to the 1-minute floor
|
||||||
|
# below -- only fall back to the default when it's genuinely unset.
|
||||||
|
minutes = int(raw) if raw is not None else 30
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
minutes = 30
|
||||||
|
return max(1, minutes) * 60
|
||||||
|
|
||||||
def geocode(self, city: str):
|
def geocode(self, city: str):
|
||||||
"""Resolve a city name to coordinates via Open-Meteo's free geocoding
|
"""Resolve a city name to coordinates via Open-Meteo's free geocoding
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ def create_app(config, screens: dict, scheduler) -> Flask:
|
|||||||
forecast_days = int(request.form.get("forecast_days", 3) or 3)
|
forecast_days = int(request.form.get("forecast_days", 3) or 3)
|
||||||
if forecast_days not in (3, 5, 7):
|
if forecast_days not in (3, 5, 7):
|
||||||
forecast_days = 3
|
forecast_days = 3
|
||||||
|
update_minutes = max(1, int(request.form.get("update_minutes", 30) or 30))
|
||||||
|
|
||||||
if city:
|
if city:
|
||||||
try:
|
try:
|
||||||
@@ -82,6 +83,7 @@ def create_app(config, screens: dict, scheduler) -> Flask:
|
|||||||
"latitude": result["latitude"],
|
"latitude": result["latitude"],
|
||||||
"longitude": result["longitude"],
|
"longitude": result["longitude"],
|
||||||
"forecast_days": forecast_days,
|
"forecast_days": forecast_days,
|
||||||
|
"update_minutes": update_minutes,
|
||||||
})
|
})
|
||||||
return redirect(url_for("settings_weather", saved=1))
|
return redirect(url_for("settings_weather", saved=1))
|
||||||
else:
|
else:
|
||||||
@@ -90,6 +92,7 @@ def create_app(config, screens: dict, scheduler) -> Flask:
|
|||||||
"latitude": float(lat_raw) if lat_raw else None,
|
"latitude": float(lat_raw) if lat_raw else None,
|
||||||
"longitude": float(lon_raw) if lon_raw else None,
|
"longitude": float(lon_raw) if lon_raw else None,
|
||||||
"forecast_days": forecast_days,
|
"forecast_days": forecast_days,
|
||||||
|
"update_minutes": update_minutes,
|
||||||
})
|
})
|
||||||
return redirect(url_for("settings_weather", saved=1))
|
return redirect(url_for("settings_weather", saved=1))
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
<option value="7" {{ "selected" if settings.forecast_days == 7 }}>7 days</option>
|
<option value="7" {{ "selected" if settings.forecast_days == 7 }}>7 days</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="update_minutes">Update every (minutes)</label>
|
||||||
|
<input type="number" id="update_minutes" name="update_minutes" min="1" value="{{ settings.update_minutes or 30 }}">
|
||||||
|
<p class="hint">Weather itself only refreshes the panel when something actually changed, so a shorter interval here mostly just means fresher data, not more flashing.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|||||||
Reference in new issue
Block a user