feat: add weather source entity and weather-reactive CSS source type
Some checks failed
Lint & Test / test (push) Failing after 34s

New standalone WeatherSource entity with pluggable provider architecture
(Open-Meteo v1, free, no API key). Full CRUD, test endpoint, browser
geolocation, IconSelect provider picker, CardSection with test/clone/edit.

WeatherColorStripStream maps WMO weather codes to ambient color palettes
with temperature hue shifting and thunderstorm flash effects. Ref-counted
WeatherManager polls API and caches data per source.

CSS editor integration: weather type with EntitySelect source picker,
speed and temperature influence sliders. Backup/restore support.

i18n for en/ru/zh.
This commit is contained in:
2026-03-24 18:52:46 +03:00
parent 0723c5c68c
commit ef33935188
31 changed files with 1868 additions and 11 deletions

View File

@@ -33,7 +33,9 @@ from wled_controller.storage.scene_preset_store import ScenePresetStore
from wled_controller.storage.sync_clock_store import SyncClockStore
from wled_controller.storage.color_strip_processing_template_store import ColorStripProcessingTemplateStore
from wled_controller.storage.gradient_store import GradientStore
from wled_controller.storage.weather_source_store import WeatherSourceStore
from wled_controller.core.processing.sync_clock_manager import SyncClockManager
from wled_controller.core.weather.weather_manager import WeatherManager
from wled_controller.core.automations.automation_engine import AutomationEngine
from wled_controller.core.mqtt.mqtt_service import MQTTService
from wled_controller.core.devices.mqtt_client import set_mqtt_service
@@ -72,7 +74,9 @@ sync_clock_store = SyncClockStore(config.storage.sync_clocks_file)
cspt_store = ColorStripProcessingTemplateStore(config.storage.color_strip_processing_templates_file)
gradient_store = GradientStore(config.storage.gradients_file)
gradient_store.migrate_palette_references(color_strip_store)
weather_source_store = WeatherSourceStore(config.storage.weather_sources_file)
sync_clock_manager = SyncClockManager(sync_clock_store)
weather_manager = WeatherManager(weather_source_store)
processor_manager = ProcessorManager(
ProcessorDependencies(
@@ -88,6 +92,7 @@ processor_manager = ProcessorManager(
sync_clock_manager=sync_clock_manager,
cspt_store=cspt_store,
gradient_store=gradient_store,
weather_manager=weather_manager,
)
)
@@ -103,7 +108,7 @@ def _save_all_stores() -> None:
picture_source_store, output_target_store, pattern_template_store,
color_strip_store, audio_source_store, audio_template_store,
value_source_store, automation_store, scene_preset_store,
sync_clock_store, cspt_store, gradient_store,
sync_clock_store, cspt_store, gradient_store, weather_source_store,
]
saved = 0
for store in all_stores:
@@ -195,6 +200,8 @@ async def lifespan(app: FastAPI):
sync_clock_manager=sync_clock_manager,
cspt_store=cspt_store,
gradient_store=gradient_store,
weather_source_store=weather_source_store,
weather_manager=weather_manager,
)
# Register devices in processor manager for health monitoring
@@ -258,6 +265,12 @@ async def lifespan(app: FastAPI):
# where no CRUD happened during the session.
_save_all_stores()
# Stop weather manager
try:
weather_manager.shutdown()
except Exception as e:
logger.error(f"Error stopping weather manager: {e}")
# Stop auto-backup engine
try:
await auto_backup_engine.stop()