fix(starlark): blank app locations use the device location, not San Francisco

A Starlark (Tidbyt) app whose Location field is blank rendered at its
author's hard-coded DEFAULT_LOCATION -- usually San Francisco -- even with
the device city set under General settings. A user in Charlotte, NC got San
Francisco weather and radar with nothing in config.json to explain it.

src/device_location.py fills unset location fields at render time (display
plugin and the web standalone render): the device city is geocoded once via
Open-Meteo, preferring a match in the configured state/country, and cached
permanently. A saved location always wins; if the lookup fails the field is
dropped so the app uses its own default, and the failure is not retried for
30 minutes.

Also fixes the config form: clearing a location omitted the key, and the
save merges, so the old value could never be removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-23 11:32:41 -04:00
co-authored by Claude Opus 5.5
parent e1ce7189f1
commit b076313392
9 changed files with 758 additions and 6 deletions
+9
View File
@@ -18,6 +18,7 @@ from PIL import Image
from src.plugin_system.base_plugin import BasePlugin, VegasDisplayMode
from src.logging_config import get_logger
from src.device_location import DeviceLocationResolver, apply_device_location
from pixlet_renderer import PixletRenderer
from frame_extractor import FrameExtractor
@@ -228,6 +229,10 @@ class StarlarkAppsPlugin(BasePlugin):
self.current_app: Optional[StarlarkApp] = None
self.last_update_check = 0
# Unset location fields render at the device's location, not the
# app author's default (usually San Francisco).
self.device_location = DeviceLocationResolver(cache_manager, self.logger)
# Check Pixlet availability
if not self.pixlet.is_available():
self.logger.error("Pixlet not available - Starlark apps will not work")
@@ -816,6 +821,10 @@ class StarlarkAppsPlugin(BasePlugin):
# Filter out LEDMatrix-internal timing/sizing keys before passing to pixlet
INTERNAL_KEYS = {'render_interval', 'display_duration', 'render_width', 'render_height'}
pixlet_config = {k: v for k, v in app.config.items() if k not in INTERNAL_KEYS}
# Applied here rather than saved into config.json, so a later
# change to the device location reaches the next render.
pixlet_config = apply_device_location(
pixlet_config, app.schema, self.device_location, self.global_config)
success, error = self.pixlet.render(
star_file=str(app.star_file),