Rename picture-targets to output-targets across entire codebase

Rename all Python modules, classes, API endpoints, config keys, frontend
fetch URLs, and Home Assistant integration URLs from picture-targets to
output-targets. Store loads both new and legacy JSON keys for backward
compatibility with existing data files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 10:55:36 +03:00
parent 5b4813368b
commit 353a1c2d85
37 changed files with 243 additions and 244 deletions

View File

@@ -8,7 +8,7 @@ from .routes.templates import router as templates_router
from .routes.postprocessing import router as postprocessing_router
from .routes.picture_sources import router as picture_sources_router
from .routes.pattern_templates import router as pattern_templates_router
from .routes.picture_targets import router as picture_targets_router
from .routes.output_targets import router as output_targets_router
from .routes.color_strip_sources import router as color_strip_sources_router
from .routes.audio import router as audio_router
from .routes.audio_sources import router as audio_sources_router
@@ -31,7 +31,7 @@ router.include_router(audio_router)
router.include_router(audio_sources_router)
router.include_router(audio_templates_router)
router.include_router(value_sources_router)
router.include_router(picture_targets_router)
router.include_router(output_targets_router)
router.include_router(automations_router)
router.include_router(scene_presets_router)
router.include_router(webhooks_router)

View File

@@ -6,7 +6,7 @@ from wled_controller.storage.template_store import TemplateStore
from wled_controller.storage.postprocessing_template_store import PostprocessingTemplateStore
from wled_controller.storage.pattern_template_store import PatternTemplateStore
from wled_controller.storage.picture_source_store import PictureSourceStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.storage.color_strip_store import ColorStripStore
from wled_controller.storage.audio_source_store import AudioSourceStore
from wled_controller.storage.audio_template_store import AudioTemplateStore
@@ -25,7 +25,7 @@ _template_store: TemplateStore | None = None
_pp_template_store: PostprocessingTemplateStore | None = None
_pattern_template_store: PatternTemplateStore | None = None
_picture_source_store: PictureSourceStore | None = None
_picture_target_store: PictureTargetStore | None = None
_output_target_store: OutputTargetStore | None = None
_color_strip_store: ColorStripStore | None = None
_audio_source_store: AudioSourceStore | None = None
_audio_template_store: AudioTemplateStore | None = None
@@ -73,11 +73,11 @@ def get_picture_source_store() -> PictureSourceStore:
return _picture_source_store
def get_picture_target_store() -> PictureTargetStore:
"""Get picture target store dependency."""
if _picture_target_store is None:
def get_output_target_store() -> OutputTargetStore:
"""Get output target store dependency."""
if _output_target_store is None:
raise RuntimeError("Picture target store not initialized")
return _picture_target_store
return _output_target_store
def get_color_strip_store() -> ColorStripStore:
@@ -164,7 +164,7 @@ def init_dependencies(
pp_template_store: PostprocessingTemplateStore | None = None,
pattern_template_store: PatternTemplateStore | None = None,
picture_source_store: PictureSourceStore | None = None,
picture_target_store: PictureTargetStore | None = None,
output_target_store: OutputTargetStore | None = None,
color_strip_store: ColorStripStore | None = None,
audio_source_store: AudioSourceStore | None = None,
audio_template_store: AudioTemplateStore | None = None,
@@ -178,7 +178,7 @@ def init_dependencies(
):
"""Initialize global dependencies."""
global _device_store, _template_store, _processor_manager
global _pp_template_store, _pattern_template_store, _picture_source_store, _picture_target_store
global _pp_template_store, _pattern_template_store, _picture_source_store, _output_target_store
global _color_strip_store, _audio_source_store, _audio_template_store
global _value_source_store, _automation_store, _scene_preset_store, _automation_engine, _auto_backup_engine
global _sync_clock_store, _sync_clock_manager
@@ -188,7 +188,7 @@ def init_dependencies(
_pp_template_store = pp_template_store
_pattern_template_store = pattern_template_store
_picture_source_store = picture_source_store
_picture_target_store = picture_target_store
_output_target_store = output_target_store
_color_strip_store = color_strip_store
_audio_source_store = audio_source_store
_audio_template_store = audio_template_store

View File

@@ -9,7 +9,7 @@ from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
get_color_strip_store,
get_picture_source_store,
get_picture_target_store,
get_output_target_store,
get_processor_manager,
)
from wled_controller.api.schemas.color_strip_sources import (
@@ -35,7 +35,7 @@ from wled_controller.storage.color_strip_source import ApiInputColorStripSource,
from wled_controller.storage.color_strip_store import ColorStripStore
from wled_controller.storage.picture_source import ProcessedPictureSource, ScreenCapturePictureSource
from wled_controller.storage.picture_source_store import PictureSourceStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.utils import get_logger
from wled_controller.config import get_config
@@ -295,7 +295,7 @@ async def delete_color_strip_source(
source_id: str,
_auth: AuthRequired,
store: ColorStripStore = Depends(get_color_strip_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""Delete a color strip source. Returns 409 if referenced by any LED target."""
try:

View File

@@ -13,7 +13,7 @@ from wled_controller.core.devices.led_client import (
)
from wled_controller.api.dependencies import (
get_device_store,
get_picture_target_store,
get_output_target_store,
get_processor_manager,
)
from wled_controller.api.schemas.devices import (
@@ -29,7 +29,7 @@ from wled_controller.api.schemas.devices import (
)
from wled_controller.core.processing.processor_manager import ProcessorManager
from wled_controller.storage import DeviceStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.utils import get_logger
logger = get_logger(__name__)
@@ -342,7 +342,7 @@ async def delete_device(
device_id: str,
_auth: AuthRequired,
store: DeviceStore = Depends(get_device_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Delete/detach a device. Returns 409 if referenced by a target."""

View File

@@ -1,4 +1,4 @@
"""Picture target routes: CRUD, processing control, settings, state, metrics."""
"""Output target routes: CRUD, processing control, settings, state, metrics."""
import asyncio
import base64
@@ -16,21 +16,21 @@ from wled_controller.api.dependencies import (
get_device_store,
get_pattern_template_store,
get_picture_source_store,
get_picture_target_store,
get_output_target_store,
get_pp_template_store,
get_processor_manager,
get_template_store,
)
from wled_controller.api.schemas.picture_targets import (
from wled_controller.api.schemas.output_targets import (
ExtractedColorResponse,
KCTestRectangleResponse,
KCTestResponse,
KeyColorsResponse,
KeyColorsSettingsSchema,
PictureTargetCreate,
PictureTargetListResponse,
PictureTargetResponse,
PictureTargetUpdate,
OutputTargetCreate,
OutputTargetListResponse,
OutputTargetResponse,
OutputTargetUpdate,
TargetMetricsResponse,
TargetProcessingState,
)
@@ -51,12 +51,12 @@ from wled_controller.storage.pattern_template_store import PatternTemplateStore
from wled_controller.storage.picture_source import ScreenCapturePictureSource, StaticImagePictureSource
from wled_controller.storage.picture_source_store import PictureSourceStore
from wled_controller.storage.template_store import TemplateStore
from wled_controller.storage.wled_picture_target import WledPictureTarget
from wled_controller.storage.key_colors_picture_target import (
from wled_controller.storage.wled_output_target import WledOutputTarget
from wled_controller.storage.key_colors_output_target import (
KeyColorsSettings,
KeyColorsPictureTarget,
KeyColorsOutputTarget,
)
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.utils import get_logger
logger = get_logger(__name__)
@@ -88,10 +88,10 @@ def _kc_schema_to_settings(schema: KeyColorsSettingsSchema) -> KeyColorsSettings
)
def _target_to_response(target) -> PictureTargetResponse:
"""Convert a PictureTarget to PictureTargetResponse."""
if isinstance(target, WledPictureTarget):
return PictureTargetResponse(
def _target_to_response(target) -> OutputTargetResponse:
"""Convert an OutputTarget to OutputTargetResponse."""
if isinstance(target, WledOutputTarget):
return OutputTargetResponse(
id=target.id,
name=target.name,
target_type=target.target_type,
@@ -109,8 +109,8 @@ def _target_to_response(target) -> PictureTargetResponse:
created_at=target.created_at,
updated_at=target.updated_at,
)
elif isinstance(target, KeyColorsPictureTarget):
return PictureTargetResponse(
elif isinstance(target, KeyColorsOutputTarget):
return OutputTargetResponse(
id=target.id,
name=target.name,
target_type=target.target_type,
@@ -122,7 +122,7 @@ def _target_to_response(target) -> PictureTargetResponse:
updated_at=target.updated_at,
)
else:
return PictureTargetResponse(
return OutputTargetResponse(
id=target.id,
name=target.name,
target_type=target.target_type,
@@ -135,15 +135,15 @@ def _target_to_response(target) -> PictureTargetResponse:
# ===== CRUD ENDPOINTS =====
@router.post("/api/v1/picture-targets", response_model=PictureTargetResponse, tags=["Targets"], status_code=201)
@router.post("/api/v1/output-targets", response_model=OutputTargetResponse, tags=["Targets"], status_code=201)
async def create_target(
data: PictureTargetCreate,
data: OutputTargetCreate,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
device_store: DeviceStore = Depends(get_device_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Create a new picture target."""
"""Create a new output target."""
try:
# Validate device exists if provided
if data.device_id:
@@ -188,18 +188,18 @@ async def create_target(
raise HTTPException(status_code=500, detail=str(e))
@router.get("/api/v1/picture-targets", response_model=PictureTargetListResponse, tags=["Targets"])
@router.get("/api/v1/output-targets", response_model=OutputTargetListResponse, tags=["Targets"])
async def list_targets(
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""List all picture targets."""
"""List all output targets."""
targets = target_store.get_all_targets()
responses = [_target_to_response(t) for t in targets]
return PictureTargetListResponse(targets=responses, count=len(responses))
return OutputTargetListResponse(targets=responses, count=len(responses))
@router.get("/api/v1/picture-targets/batch/states", tags=["Processing"])
@router.get("/api/v1/output-targets/batch/states", tags=["Processing"])
async def batch_target_states(
_auth: AuthRequired,
manager: ProcessorManager = Depends(get_processor_manager),
@@ -208,7 +208,7 @@ async def batch_target_states(
return {"states": manager.get_all_target_states()}
@router.get("/api/v1/picture-targets/batch/metrics", tags=["Metrics"])
@router.get("/api/v1/output-targets/batch/metrics", tags=["Metrics"])
async def batch_target_metrics(
_auth: AuthRequired,
manager: ProcessorManager = Depends(get_processor_manager),
@@ -217,13 +217,13 @@ async def batch_target_metrics(
return {"metrics": manager.get_all_target_metrics()}
@router.get("/api/v1/picture-targets/{target_id}", response_model=PictureTargetResponse, tags=["Targets"])
@router.get("/api/v1/output-targets/{target_id}", response_model=OutputTargetResponse, tags=["Targets"])
async def get_target(
target_id: str,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""Get a picture target by ID."""
"""Get a output target by ID."""
try:
target = target_store.get_target(target_id)
return _target_to_response(target)
@@ -231,16 +231,16 @@ async def get_target(
raise HTTPException(status_code=404, detail=str(e))
@router.put("/api/v1/picture-targets/{target_id}", response_model=PictureTargetResponse, tags=["Targets"])
@router.put("/api/v1/output-targets/{target_id}", response_model=OutputTargetResponse, tags=["Targets"])
async def update_target(
target_id: str,
data: PictureTargetUpdate,
data: OutputTargetUpdate,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
device_store: DeviceStore = Depends(get_device_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Update a picture target."""
"""Update a output target."""
try:
# Validate device exists if changing
if data.device_id is not None and data.device_id:
@@ -258,7 +258,7 @@ async def update_target(
except ValueError:
existing_target = None
if isinstance(existing_target, KeyColorsPictureTarget):
if isinstance(existing_target, KeyColorsOutputTarget):
ex = existing_target.settings
merged = KeyColorsSettingsSchema(
fps=incoming.get("fps", ex.fps),
@@ -325,14 +325,14 @@ async def update_target(
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/api/v1/picture-targets/{target_id}", status_code=204, tags=["Targets"])
@router.delete("/api/v1/output-targets/{target_id}", status_code=204, tags=["Targets"])
async def delete_target(
target_id: str,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Delete a picture target. Stops processing first if active."""
"""Delete a output target. Stops processing first if active."""
try:
# Stop processing if running
try:
@@ -360,14 +360,14 @@ async def delete_target(
# ===== PROCESSING CONTROL ENDPOINTS =====
@router.post("/api/v1/picture-targets/{target_id}/start", tags=["Processing"])
@router.post("/api/v1/output-targets/{target_id}/start", tags=["Processing"])
async def start_processing(
target_id: str,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Start processing for a picture target."""
"""Start processing for a output target."""
try:
# Verify target exists in store
target_store.get_target(target_id)
@@ -386,13 +386,13 @@ async def start_processing(
raise HTTPException(status_code=500, detail=str(e))
@router.post("/api/v1/picture-targets/{target_id}/stop", tags=["Processing"])
@router.post("/api/v1/output-targets/{target_id}/stop", tags=["Processing"])
async def stop_processing(
target_id: str,
_auth: AuthRequired,
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Stop processing for a picture target."""
"""Stop processing for a output target."""
try:
await manager.stop_processing(target_id)
@@ -408,7 +408,7 @@ async def stop_processing(
# ===== STATE & METRICS ENDPOINTS =====
@router.get("/api/v1/picture-targets/{target_id}/state", response_model=TargetProcessingState, tags=["Processing"])
@router.get("/api/v1/output-targets/{target_id}/state", response_model=TargetProcessingState, tags=["Processing"])
async def get_target_state(
target_id: str,
_auth: AuthRequired,
@@ -426,7 +426,7 @@ async def get_target_state(
raise HTTPException(status_code=500, detail=str(e))
@router.get("/api/v1/picture-targets/{target_id}/metrics", response_model=TargetMetricsResponse, tags=["Metrics"])
@router.get("/api/v1/output-targets/{target_id}/metrics", response_model=TargetMetricsResponse, tags=["Metrics"])
async def get_target_metrics(
target_id: str,
_auth: AuthRequired,
@@ -446,7 +446,7 @@ async def get_target_metrics(
# ===== KEY COLORS ENDPOINTS =====
@router.get("/api/v1/picture-targets/{target_id}/colors", response_model=KeyColorsResponse, tags=["Key Colors"])
@router.get("/api/v1/output-targets/{target_id}/colors", response_model=KeyColorsResponse, tags=["Key Colors"])
async def get_target_colors(
target_id: str,
_auth: AuthRequired,
@@ -471,11 +471,11 @@ async def get_target_colors(
raise HTTPException(status_code=404, detail=str(e))
@router.post("/api/v1/picture-targets/{target_id}/test", response_model=KCTestResponse, tags=["Key Colors"])
@router.post("/api/v1/output-targets/{target_id}/test", response_model=KCTestResponse, tags=["Key Colors"])
async def test_kc_target(
target_id: str,
_auth: AuthRequired,
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
source_store: PictureSourceStore = Depends(get_picture_source_store),
template_store: TemplateStore = Depends(get_template_store),
pattern_store: PatternTemplateStore = Depends(get_pattern_template_store),
@@ -494,7 +494,7 @@ async def test_kc_target(
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
if not isinstance(target, KeyColorsPictureTarget):
if not isinstance(target, KeyColorsOutputTarget):
raise HTTPException(status_code=400, detail="Target is not a key_colors target")
settings = target.settings
@@ -670,7 +670,7 @@ async def test_kc_target(
logger.error(f"Error cleaning up test stream: {e}")
@router.websocket("/api/v1/picture-targets/{target_id}/ws")
@router.websocket("/api/v1/output-targets/{target_id}/ws")
async def target_colors_ws(
websocket: WebSocket,
target_id: str,
@@ -710,7 +710,7 @@ async def target_colors_ws(
manager.remove_kc_ws_client(target_id, websocket)
@router.websocket("/api/v1/picture-targets/{target_id}/led-preview/ws")
@router.websocket("/api/v1/output-targets/{target_id}/led-preview/ws")
async def led_preview_ws(
websocket: WebSocket,
target_id: str,
@@ -788,12 +788,12 @@ async def events_ws(
# ===== OVERLAY VISUALIZATION =====
@router.post("/api/v1/picture-targets/{target_id}/overlay/start", tags=["Visualization"])
@router.post("/api/v1/output-targets/{target_id}/overlay/start", tags=["Visualization"])
async def start_target_overlay(
target_id: str,
_auth: AuthRequired,
manager: ProcessorManager = Depends(get_processor_manager),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
color_strip_store: ColorStripStore = Depends(get_color_strip_store),
picture_source_store: PictureSourceStore = Depends(get_picture_source_store),
):
@@ -815,7 +815,7 @@ async def start_target_overlay(
# can start even when processing is not currently running.
calibration = None
display_info = None
if isinstance(target, WledPictureTarget) and target.color_strip_source_id:
if isinstance(target, WledOutputTarget) and target.color_strip_source_id:
first_css_id = target.color_strip_source_id
if first_css_id:
try:
@@ -844,7 +844,7 @@ async def start_target_overlay(
raise HTTPException(status_code=500, detail=str(e))
@router.post("/api/v1/picture-targets/{target_id}/overlay/stop", tags=["Visualization"])
@router.post("/api/v1/output-targets/{target_id}/overlay/stop", tags=["Visualization"])
async def stop_target_overlay(
target_id: str,
_auth: AuthRequired,
@@ -862,7 +862,7 @@ async def stop_target_overlay(
raise HTTPException(status_code=500, detail=str(e))
@router.get("/api/v1/picture-targets/{target_id}/overlay/status", tags=["Visualization"])
@router.get("/api/v1/output-targets/{target_id}/overlay/status", tags=["Visualization"])
async def get_overlay_status(
target_id: str,
_auth: AuthRequired,

View File

@@ -5,7 +5,7 @@ from fastapi import APIRouter, HTTPException, Depends
from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
get_pattern_template_store,
get_picture_target_store,
get_output_target_store,
)
from wled_controller.api.schemas.pattern_templates import (
PatternTemplateCreate,
@@ -13,10 +13,10 @@ from wled_controller.api.schemas.pattern_templates import (
PatternTemplateResponse,
PatternTemplateUpdate,
)
from wled_controller.api.schemas.picture_targets import KeyColorRectangleSchema
from wled_controller.storage.key_colors_picture_target import KeyColorRectangle
from wled_controller.api.schemas.output_targets import KeyColorRectangleSchema
from wled_controller.storage.key_colors_output_target import KeyColorRectangle
from wled_controller.storage.pattern_template_store import PatternTemplateStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.utils import get_logger
logger = get_logger(__name__)
@@ -127,7 +127,7 @@ async def delete_pattern_template(
template_id: str,
_auth: AuthRequired,
store: PatternTemplateStore = Depends(get_pattern_template_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""Delete a pattern template."""
try:

View File

@@ -13,7 +13,7 @@ from fastapi.responses import Response
from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
get_picture_source_store,
get_picture_target_store,
get_output_target_store,
get_pp_template_store,
get_template_store,
)
@@ -33,7 +33,7 @@ from wled_controller.api.schemas.picture_sources import (
)
from wled_controller.core.capture_engines import EngineRegistry
from wled_controller.core.filters import FilterRegistry, ImagePool
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.storage.template_store import TemplateStore
from wled_controller.storage.postprocessing_template_store import PostprocessingTemplateStore
from wled_controller.storage.picture_source_store import PictureSourceStore
@@ -254,7 +254,7 @@ async def delete_picture_source(
stream_id: str,
_auth: AuthRequired,
store: PictureSourceStore = Depends(get_picture_source_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""Delete a picture source."""
try:

View File

@@ -7,7 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException
from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
get_picture_target_store,
get_output_target_store,
get_processor_manager,
get_scene_preset_store,
)
@@ -23,7 +23,7 @@ from wled_controller.core.scenes.scene_activator import (
apply_scene_state,
capture_current_snapshot,
)
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.storage.scene_preset import ScenePreset
from wled_controller.storage.scene_preset_store import ScenePresetStore
from wled_controller.utils import get_logger
@@ -62,7 +62,7 @@ async def create_scene_preset(
data: ScenePresetCreate,
_auth: AuthRequired,
store: ScenePresetStore = Depends(get_scene_preset_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Capture current state as a new scene preset."""
@@ -176,7 +176,7 @@ async def recapture_scene_preset(
preset_id: str,
_auth: AuthRequired,
store: ScenePresetStore = Depends(get_scene_preset_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Re-capture current state into an existing preset (updates snapshot)."""
@@ -214,7 +214,7 @@ async def activate_scene_preset(
preset_id: str,
_auth: AuthRequired,
store: ScenePresetStore = Depends(get_scene_preset_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
manager: ProcessorManager = Depends(get_processor_manager),
):
"""Activate a scene preset — restore the captured state."""

View File

@@ -265,7 +265,7 @@ STORE_MAP = {
"capture_templates": "templates_file",
"postprocessing_templates": "postprocessing_templates_file",
"picture_sources": "picture_sources_file",
"picture_targets": "picture_targets_file",
"output_targets": "output_targets_file",
"pattern_templates": "pattern_templates_file",
"color_strip_sources": "color_strip_sources_file",
"audio_sources": "audio_sources_file",

View File

@@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSock
from wled_controller.api.auth import AuthRequired
from wled_controller.api.dependencies import (
get_picture_target_store,
get_output_target_store,
get_processor_manager,
get_value_source_store,
)
@@ -21,7 +21,7 @@ from wled_controller.api.schemas.value_sources import (
)
from wled_controller.storage.value_source import ValueSource
from wled_controller.storage.value_source_store import ValueSourceStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.storage.output_target_store import OutputTargetStore
from wled_controller.core.processing.processor_manager import ProcessorManager
from wled_controller.utils import get_logger
@@ -157,14 +157,14 @@ async def delete_value_source(
source_id: str,
_auth: AuthRequired,
store: ValueSourceStore = Depends(get_value_source_store),
target_store: PictureTargetStore = Depends(get_picture_target_store),
target_store: OutputTargetStore = Depends(get_output_target_store),
):
"""Delete a value source."""
try:
# Check if any targets reference this value source
from wled_controller.storage.wled_picture_target import WledPictureTarget
from wled_controller.storage.wled_output_target import WledOutputTarget
for target in target_store.get_all_targets():
if isinstance(target, WledPictureTarget):
if isinstance(target, WledOutputTarget):
if getattr(target, "brightness_value_source_id", "") == source_id:
raise ValueError(
f"Cannot delete: referenced by target '{target.name}'"

View File

@@ -30,11 +30,11 @@ from .color_strip_sources import (
ColorStripSourceUpdate,
CSSCalibrationTestRequest,
)
from .picture_targets import (
PictureTargetCreate,
PictureTargetListResponse,
PictureTargetResponse,
PictureTargetUpdate,
from .output_targets import (
OutputTargetCreate,
OutputTargetListResponse,
OutputTargetResponse,
OutputTargetUpdate,
TargetMetricsResponse,
TargetProcessingState,
)
@@ -100,10 +100,10 @@ __all__ = [
"ColorStripSourceResponse",
"ColorStripSourceUpdate",
"CSSCalibrationTestRequest",
"PictureTargetCreate",
"PictureTargetListResponse",
"PictureTargetResponse",
"PictureTargetUpdate",
"OutputTargetCreate",
"OutputTargetListResponse",
"OutputTargetResponse",
"OutputTargetUpdate",
"TargetMetricsResponse",
"TargetProcessingState",
"EngineInfo",

View File

@@ -1,4 +1,4 @@
"""Picture target schemas (CRUD, processing state, metrics)."""
"""Output target schemas (CRUD, processing state, metrics)."""
from datetime import datetime
from typing import Dict, Optional, List
@@ -46,8 +46,8 @@ class KeyColorsResponse(BaseModel):
timestamp: Optional[datetime] = Field(None, description="Extraction timestamp")
class PictureTargetCreate(BaseModel):
"""Request to create a picture target."""
class OutputTargetCreate(BaseModel):
"""Request to create an output target."""
name: str = Field(description="Target name", min_length=1, max_length=100)
target_type: str = Field(default="led", description="Target type (led, key_colors)")
@@ -67,8 +67,8 @@ class PictureTargetCreate(BaseModel):
description: Optional[str] = Field(None, description="Optional description", max_length=500)
class PictureTargetUpdate(BaseModel):
"""Request to update a picture target."""
class OutputTargetUpdate(BaseModel):
"""Request to update an output target."""
name: Optional[str] = Field(None, description="Target name", min_length=1, max_length=100)
# LED target fields
@@ -87,8 +87,8 @@ class PictureTargetUpdate(BaseModel):
description: Optional[str] = Field(None, description="Optional description", max_length=500)
class PictureTargetResponse(BaseModel):
"""Picture target response."""
class OutputTargetResponse(BaseModel):
"""Output target response."""
id: str = Field(description="Target ID")
name: str = Field(description="Target name")
@@ -111,15 +111,15 @@ class PictureTargetResponse(BaseModel):
updated_at: datetime = Field(description="Last update timestamp")
class PictureTargetListResponse(BaseModel):
"""List of picture targets response."""
class OutputTargetListResponse(BaseModel):
"""List of output targets response."""
targets: List[PictureTargetResponse] = Field(description="List of picture targets")
targets: List[OutputTargetResponse] = Field(description="List of output targets")
count: int = Field(description="Number of targets")
class TargetProcessingState(BaseModel):
"""Processing state for a picture target."""
"""Processing state for an output target."""
target_id: str = Field(description="Target ID")
device_id: Optional[str] = Field(None, description="Device ID")

View File

@@ -5,7 +5,7 @@ from typing import List, Optional
from pydantic import BaseModel, Field
from .picture_targets import KeyColorRectangleSchema
from .output_targets import KeyColorRectangleSchema
class PatternTemplateCreate(BaseModel):