Add weather sync job, API endpoints and settings UI

Fetches daily ERA5 weather from Open-Meteo (no API key).
Configurable location, timezone and sync time via Settings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-13 21:10:03 +00:00
parent fc15bc5d9a
commit 5fbf155f62
4 changed files with 671 additions and 1 deletions

View file

@ -1145,6 +1145,79 @@ async def delete_key(
# AI INSIGHTS SETTINGS
# ============================================
class WeatherSettingsResponse(BaseModel):
enabled: bool = True
location_name: str = "Stow on the Wold, GL54 1JX"
latitude: float = 51.9253
longitude: float = -1.7272
timezone: str = "Europe/London"
sync_time: str = "05:15"
class WeatherSettingsUpdate(BaseModel):
enabled: Optional[bool] = None
location_name: Optional[str] = None
latitude: Optional[float] = None
longitude: Optional[float] = None
timezone: Optional[str] = None
sync_time: Optional[str] = None
@router.get("/settings/weather", response_model=WeatherSettingsResponse)
async def get_weather_settings(
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user)
):
"""Get weather sync configuration."""
result = await db.execute(
text("SELECT config_key, config_value FROM system_config WHERE config_key LIKE 'weather_%'")
)
cfg = {row.config_key: row.config_value for row in result.fetchall()}
return WeatherSettingsResponse(
enabled=cfg.get("weather_sync_enabled", "true").lower() in ("true", "1", "yes"),
location_name=cfg.get("weather_location_name", "Stow on the Wold, GL54 1JX"),
latitude=float(cfg.get("weather_latitude", "51.9253")),
longitude=float(cfg.get("weather_longitude", "-1.7272")),
timezone=cfg.get("weather_timezone", "Europe/London"),
sync_time=cfg.get("weather_sync_time", "05:15"),
)
@router.post("/settings/weather")
async def update_weather_settings(
settings: WeatherSettingsUpdate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user)
):
"""Update weather sync configuration."""
updates = {}
if settings.enabled is not None:
updates["weather_sync_enabled"] = "true" if settings.enabled else "false"
if settings.location_name is not None:
updates["weather_location_name"] = settings.location_name
if settings.latitude is not None:
updates["weather_latitude"] = str(settings.latitude)
if settings.longitude is not None:
updates["weather_longitude"] = str(settings.longitude)
if settings.timezone is not None:
updates["weather_timezone"] = settings.timezone
if settings.sync_time is not None:
updates["weather_sync_time"] = settings.sync_time
for key, value in updates.items():
await db.execute(
text("""
INSERT INTO system_config (config_key, config_value, updated_at)
VALUES (:key, :value, NOW())
ON CONFLICT (config_key) DO UPDATE
SET config_value = :value, updated_at = NOW()
"""),
{"key": key, "value": value}
)
await db.commit()
return {"status": "saved", "keys_updated": list(updates.keys())}
class AIInsightsSettingsResponse(BaseModel):
enabled: bool = False
api_key_set: bool = False