mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-10 17:16:36 +00:00
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:
@@ -49,6 +49,7 @@ from src.web_interface.validators import (
|
||||
from src.error_aggregator import get_error_aggregator
|
||||
from src.common.permission_utils import install_requirements_file
|
||||
from src.common.path_safety import resolve_under
|
||||
from src.device_location import DeviceLocationResolver, apply_device_location
|
||||
_SUDO = shutil.which('sudo')
|
||||
_JOURNALCTL = shutil.which('journalctl')
|
||||
_GIT = shutil.which('git')
|
||||
@@ -1719,6 +1720,32 @@ def _validate_starlark_app_path(app_id: str) -> Tuple[Optional[Path], Optional[s
|
||||
except OSError as e:
|
||||
logger.warning("Path validation error for app_id %r: %s", app_id, e)
|
||||
return None, "Invalid app_id"
|
||||
_starlark_device_location: Optional[DeviceLocationResolver] = None
|
||||
|
||||
|
||||
def _get_starlark_device_location() -> DeviceLocationResolver:
|
||||
"""One resolver per process, so a geocode failure's backoff is shared."""
|
||||
global _starlark_device_location
|
||||
if _starlark_device_location is None:
|
||||
_starlark_device_location = DeviceLocationResolver(
|
||||
getattr(api_v3, 'cache_manager', None) or _ensure_cache_manager(), logger)
|
||||
return _starlark_device_location
|
||||
|
||||
|
||||
def _read_starlark_schema(app_dir: Path) -> Optional[Dict[str, Any]]:
|
||||
"""An installed app's schema.json, or None if it has none or it's unreadable."""
|
||||
schema_file = app_dir / 'schema.json'
|
||||
if not schema_file.exists():
|
||||
return None
|
||||
try:
|
||||
with open(schema_file) as f:
|
||||
schema = json.load(f)
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
logger.warning("Could not read schema.json at %s: %s", schema_file, e)
|
||||
return None
|
||||
return schema if isinstance(schema, dict) else None
|
||||
|
||||
|
||||
def _standalone_render_starlark_app(app_id: str) -> Tuple[bool, int, Optional[str]]:
|
||||
"""Render a Starlark app via pixlet directly (no plugin required).
|
||||
|
||||
@@ -1790,6 +1817,9 @@ def _standalone_render_starlark_app(app_id: str) -> Tuple[bool, int, Optional[st
|
||||
|
||||
INTERNAL_KEYS = {'render_interval', 'display_duration'}
|
||||
pixlet_config = {k: v for k, v in app_config.items() if k not in INTERNAL_KEYS}
|
||||
pixlet_config = apply_device_location(
|
||||
pixlet_config, _read_starlark_schema(app_dir),
|
||||
_get_starlark_device_location(), full_config)
|
||||
|
||||
output_path = str(app_dir / 'cached_render.webp')
|
||||
cmd = [pixlet_path, 'render', str(star_file)]
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
data-starlark-location-key="timezone">
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">Leave latitude and longitude blank to use this device's location (City / State / Country in General settings).</p>
|
||||
{% if field_desc %}
|
||||
<p class="text-xs text-gray-400 mt-1">{{ field_desc }}</p>
|
||||
{% endif %}
|
||||
@@ -421,9 +422,10 @@ function saveStarlarkConfig(appId) {
|
||||
var locKey = sub.getAttribute('data-starlark-location-key');
|
||||
if (sub.value) loc[locKey] = sub.value;
|
||||
});
|
||||
if (Object.keys(loc).length > 0) {
|
||||
config[fieldId] = JSON.stringify(loc);
|
||||
}
|
||||
// Blank still has to be sent: the save merges into the stored config,
|
||||
// so leaving the key out kept the old location with no way to clear
|
||||
// it back to the device's.
|
||||
config[fieldId] = Object.keys(loc).length > 0 ? JSON.stringify(loc) : '';
|
||||
});
|
||||
|
||||
fetch('/api/v3/starlark/apps/' + encodeURIComponent(appId) + '/config', {
|
||||
|
||||
Reference in New Issue
Block a user