Add adaptive FPS and honest device reachability during streaming
DDP uses fire-and-forget UDP, so when a WiFi device becomes overwhelmed by sustained traffic, sends appear successful while the device is actually unreachable. This adds: - HTTP liveness probe (GET /json/info, 2s timeout) every 10s during streaming, exposed as device_streaming_reachable in target state - Adaptive FPS (opt-in): exponential backoff when device is unreachable, gradual recovery when it stabilizes — finds sustainable send rate - Honest health checks: removed the lie that forced device_online=true during streaming; now runs actual health checks regardless - Target editor toggle, FPS display shows effective rate when throttled, health dot reflects streaming reachability, red highlight when unreachable - Auto-backup scheduling support in settings modal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,8 @@ import wled_controller.core.audio # noqa: F401 — trigger engine auto-registra
|
||||
from wled_controller.storage.value_source_store import ValueSourceStore
|
||||
from wled_controller.storage.profile_store import ProfileStore
|
||||
from wled_controller.core.profiles.profile_engine import ProfileEngine
|
||||
from wled_controller.core.backup.auto_backup import AutoBackupEngine
|
||||
from wled_controller.api.routes.system import STORE_MAP
|
||||
from wled_controller.utils import setup_logging, get_logger
|
||||
|
||||
# Initialize logging
|
||||
@@ -101,6 +103,14 @@ async def lifespan(app: FastAPI):
|
||||
# Create profile engine (needs processor_manager)
|
||||
profile_engine = ProfileEngine(profile_store, processor_manager)
|
||||
|
||||
# Create auto-backup engine
|
||||
auto_backup_engine = AutoBackupEngine(
|
||||
settings_path=Path("data/auto_backup_settings.json"),
|
||||
backup_dir=Path("data/backups"),
|
||||
store_map=STORE_MAP,
|
||||
storage_config=config.storage,
|
||||
)
|
||||
|
||||
# Initialize API dependencies
|
||||
init_dependencies(
|
||||
device_store, template_store, processor_manager,
|
||||
@@ -114,6 +124,7 @@ async def lifespan(app: FastAPI):
|
||||
value_source_store=value_source_store,
|
||||
profile_store=profile_store,
|
||||
profile_engine=profile_engine,
|
||||
auto_backup_engine=auto_backup_engine,
|
||||
)
|
||||
|
||||
# Register devices in processor manager for health monitoring
|
||||
@@ -154,6 +165,9 @@ async def lifespan(app: FastAPI):
|
||||
# Start profile engine (evaluates conditions and auto-starts/stops targets)
|
||||
await profile_engine.start()
|
||||
|
||||
# Start auto-backup engine (periodic configuration backups)
|
||||
await auto_backup_engine.start()
|
||||
|
||||
# Auto-start targets with auto_start=True
|
||||
auto_started = 0
|
||||
for target in targets:
|
||||
@@ -172,6 +186,12 @@ async def lifespan(app: FastAPI):
|
||||
# Shutdown
|
||||
logger.info("Shutting down LED Grab")
|
||||
|
||||
# Stop auto-backup engine
|
||||
try:
|
||||
await auto_backup_engine.stop()
|
||||
except Exception as e:
|
||||
logger.error(f"Error stopping auto-backup engine: {e}")
|
||||
|
||||
# Stop profile engine first (deactivates profile-managed targets)
|
||||
try:
|
||||
await profile_engine.stop()
|
||||
|
||||
Reference in New Issue
Block a user