Add auto-start targets feature with dashboard section

- Add auto_start boolean field to PictureTarget model (persisted per-target)
- Wire auto_start through API schemas, routes, and store
- Auto-start targets on server boot in main.py lifespan
- Add star toggle button on target cards (next to delete button)
- Add auto-start section on dashboard between performance and profiles
- Remove auto-start section from profiles tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 15:08:01 +03:00
parent 701eac19e5
commit d05b4b78f4
14 changed files with 131 additions and 8 deletions

View File

@@ -100,9 +100,9 @@ class KeyColorsPictureTarget(PictureTarget):
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
settings=None, key_colors_settings=None, description=None,
**_kwargs) -> None:
auto_start=None, **_kwargs) -> None:
"""Apply mutable field updates for KC targets."""
super().update_fields(name=name, description=description)
super().update_fields(name=name, description=description, auto_start=auto_start)
if picture_source_id is not None:
self.picture_source_id = picture_source_id
if key_colors_settings is not None:
@@ -130,6 +130,7 @@ class KeyColorsPictureTarget(PictureTarget):
picture_source_id=data.get("picture_source_id", ""),
settings=settings,
description=data.get("description"),
auto_start=data.get("auto_start", False),
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
)

View File

@@ -15,6 +15,7 @@ class PictureTarget:
created_at: datetime
updated_at: datetime
description: Optional[str] = None
auto_start: bool = False
def register_with_manager(self, manager) -> None:
"""Register this target with the processor manager. Subclasses override."""
@@ -25,12 +26,15 @@ class PictureTarget:
pass
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
settings=None, key_colors_settings=None, description=None) -> None:
settings=None, key_colors_settings=None, description=None,
auto_start=None) -> None:
"""Apply mutable field updates. Base handles common fields; subclasses handle type-specific ones."""
if name is not None:
self.name = name
if description is not None:
self.description = description
if auto_start is not None:
self.auto_start = auto_start
@property
def has_picture_source(self) -> bool:
@@ -44,6 +48,7 @@ class PictureTarget:
"name": self.name,
"target_type": self.target_type,
"description": self.description,
"auto_start": self.auto_start,
"created_at": self.created_at.isoformat(),
"updated_at": self.updated_at.isoformat(),
}

View File

@@ -109,6 +109,7 @@ class PictureTargetStore:
key_colors_settings: Optional[KeyColorsSettings] = None,
description: Optional[str] = None,
picture_source_id: str = "",
auto_start: bool = False,
) -> PictureTarget:
"""Create a new picture target.
@@ -138,6 +139,7 @@ class PictureTargetStore:
keepalive_interval=keepalive_interval,
state_check_interval=state_check_interval,
description=description,
auto_start=auto_start,
created_at=now,
updated_at=now,
)
@@ -149,6 +151,7 @@ class PictureTargetStore:
picture_source_id=picture_source_id,
settings=key_colors_settings or KeyColorsSettings(),
description=description,
auto_start=auto_start,
created_at=now,
updated_at=now,
)
@@ -173,6 +176,7 @@ class PictureTargetStore:
state_check_interval: Optional[int] = None,
key_colors_settings: Optional[KeyColorsSettings] = None,
description: Optional[str] = None,
auto_start: Optional[bool] = None,
) -> PictureTarget:
"""Update a picture target.
@@ -200,6 +204,7 @@ class PictureTargetStore:
state_check_interval=state_check_interval,
key_colors_settings=key_colors_settings,
description=description,
auto_start=auto_start,
)
target.updated_at = datetime.utcnow()

View File

@@ -54,9 +54,9 @@ class WledPictureTarget(PictureTarget):
def update_fields(self, *, name=None, device_id=None, color_strip_source_id=None,
brightness_value_source_id=None,
fps=None, keepalive_interval=None, state_check_interval=None,
description=None, **_kwargs) -> None:
description=None, auto_start=None, **_kwargs) -> None:
"""Apply mutable field updates for WLED targets."""
super().update_fields(name=name, description=description)
super().update_fields(name=name, description=description, auto_start=auto_start)
if device_id is not None:
self.device_id = device_id
if color_strip_source_id is not None:
@@ -109,6 +109,7 @@ class WledPictureTarget(PictureTarget):
keepalive_interval=data.get("keepalive_interval", data.get("standby_interval", 1.0)),
state_check_interval=data.get("state_check_interval", DEFAULT_STATE_CHECK_INTERVAL),
description=data.get("description"),
auto_start=data.get("auto_start", False),
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
)