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:
@@ -16,7 +16,7 @@ class Device:
|
||||
|
||||
A device holds connection state and output settings.
|
||||
Calibration, processing settings, and picture source assignments
|
||||
now live on ColorStripSource and WledPictureTarget respectively.
|
||||
now live on ColorStripSource and WledOutputTarget respectively.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""Key colors picture target — extracts key colors from image rectangles."""
|
||||
"""Key colors output target — extracts key colors from image rectangles."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from wled_controller.storage.picture_target import PictureTarget
|
||||
from wled_controller.storage.output_target import OutputTarget
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -71,7 +71,7 @@ class KeyColorsSettings:
|
||||
|
||||
|
||||
@dataclass
|
||||
class KeyColorsPictureTarget(PictureTarget):
|
||||
class KeyColorsOutputTarget(OutputTarget):
|
||||
"""Key colors extractor target — extracts key colors from image rectangles."""
|
||||
|
||||
picture_source_id: str = ""
|
||||
@@ -119,7 +119,7 @@ class KeyColorsPictureTarget(PictureTarget):
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "KeyColorsPictureTarget":
|
||||
def from_dict(cls, data: dict) -> "KeyColorsOutputTarget":
|
||||
settings_data = data.get("settings", {})
|
||||
settings = KeyColorsSettings.from_dict(settings_data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Picture target base data model."""
|
||||
"""Output target base data model."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
@@ -6,8 +6,8 @@ from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class PictureTarget:
|
||||
"""Base class for picture targets."""
|
||||
class OutputTarget:
|
||||
"""Base class for output targets."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
@@ -50,13 +50,13 @@ class PictureTarget:
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "PictureTarget":
|
||||
def from_dict(cls, data: dict) -> "OutputTarget":
|
||||
"""Create from dictionary, dispatching to the correct subclass."""
|
||||
target_type = data.get("target_type", "led")
|
||||
if target_type == "led":
|
||||
from wled_controller.storage.wled_picture_target import WledPictureTarget
|
||||
return WledPictureTarget.from_dict(data)
|
||||
from wled_controller.storage.wled_output_target import WledOutputTarget
|
||||
return WledOutputTarget.from_dict(data)
|
||||
if target_type == "key_colors":
|
||||
from wled_controller.storage.key_colors_picture_target import KeyColorsPictureTarget
|
||||
return KeyColorsPictureTarget.from_dict(data)
|
||||
from wled_controller.storage.key_colors_output_target import KeyColorsOutputTarget
|
||||
return KeyColorsOutputTarget.from_dict(data)
|
||||
raise ValueError(f"Unknown target type: {target_type}")
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Picture target storage using JSON files."""
|
||||
"""Output target storage using JSON files."""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
@@ -6,11 +6,11 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from wled_controller.storage.picture_target import PictureTarget
|
||||
from wled_controller.storage.wled_picture_target import WledPictureTarget
|
||||
from wled_controller.storage.key_colors_picture_target import (
|
||||
from wled_controller.storage.output_target import OutputTarget
|
||||
from wled_controller.storage.wled_output_target import WledOutputTarget
|
||||
from wled_controller.storage.key_colors_output_target import (
|
||||
KeyColorsSettings,
|
||||
KeyColorsPictureTarget,
|
||||
KeyColorsOutputTarget,
|
||||
)
|
||||
from wled_controller.utils import atomic_write_json, get_logger
|
||||
|
||||
@@ -19,17 +19,17 @@ logger = get_logger(__name__)
|
||||
DEFAULT_STATE_CHECK_INTERVAL = 30 # seconds
|
||||
|
||||
|
||||
class PictureTargetStore:
|
||||
"""Persistent storage for picture targets."""
|
||||
class OutputTargetStore:
|
||||
"""Persistent storage for output targets."""
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
"""Initialize picture target store.
|
||||
"""Initialize output target store.
|
||||
|
||||
Args:
|
||||
file_path: Path to targets JSON file
|
||||
"""
|
||||
self.file_path = Path(file_path)
|
||||
self._targets: Dict[str, PictureTarget] = {}
|
||||
self._targets: Dict[str, OutputTarget] = {}
|
||||
self._load()
|
||||
|
||||
def _load(self) -> None:
|
||||
@@ -41,52 +41,53 @@ class PictureTargetStore:
|
||||
with open(self.file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
targets_data = data.get("picture_targets", {})
|
||||
# Support both new "output_targets" and legacy "picture_targets" keys
|
||||
targets_data = data.get("output_targets") or data.get("picture_targets", {})
|
||||
loaded = 0
|
||||
for target_id, target_dict in targets_data.items():
|
||||
try:
|
||||
target = PictureTarget.from_dict(target_dict)
|
||||
target = OutputTarget.from_dict(target_dict)
|
||||
self._targets[target_id] = target
|
||||
loaded += 1
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load picture target {target_id}: {e}", exc_info=True)
|
||||
logger.error(f"Failed to load output target {target_id}: {e}", exc_info=True)
|
||||
|
||||
if loaded > 0:
|
||||
logger.info(f"Loaded {loaded} picture targets from storage")
|
||||
logger.info(f"Loaded {loaded} output targets from storage")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load picture targets from {self.file_path}: {e}")
|
||||
logger.error(f"Failed to load output targets from {self.file_path}: {e}")
|
||||
raise
|
||||
|
||||
logger.info(f"Picture target store initialized with {len(self._targets)} targets")
|
||||
logger.info(f"Output target store initialized with {len(self._targets)} targets")
|
||||
|
||||
def _save(self) -> None:
|
||||
"""Save all targets to file."""
|
||||
try:
|
||||
data = {
|
||||
"version": "1.0.0",
|
||||
"picture_targets": {
|
||||
"output_targets": {
|
||||
target_id: target.to_dict()
|
||||
for target_id, target in self._targets.items()
|
||||
},
|
||||
}
|
||||
atomic_write_json(self.file_path, data)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to save picture targets to {self.file_path}: {e}")
|
||||
logger.error(f"Failed to save output targets to {self.file_path}: {e}")
|
||||
raise
|
||||
|
||||
def get_all_targets(self) -> List[PictureTarget]:
|
||||
"""Get all picture targets."""
|
||||
def get_all_targets(self) -> List[OutputTarget]:
|
||||
"""Get all output targets."""
|
||||
return list(self._targets.values())
|
||||
|
||||
def get_target(self, target_id: str) -> PictureTarget:
|
||||
def get_target(self, target_id: str) -> OutputTarget:
|
||||
"""Get target by ID.
|
||||
|
||||
Raises:
|
||||
ValueError: If target not found
|
||||
"""
|
||||
if target_id not in self._targets:
|
||||
raise ValueError(f"Picture target not found: {target_id}")
|
||||
raise ValueError(f"Output target not found: {target_id}")
|
||||
return self._targets[target_id]
|
||||
|
||||
def create_target(
|
||||
@@ -105,8 +106,8 @@ class PictureTargetStore:
|
||||
key_colors_settings: Optional[KeyColorsSettings] = None,
|
||||
description: Optional[str] = None,
|
||||
picture_source_id: str = "",
|
||||
) -> PictureTarget:
|
||||
"""Create a new picture target.
|
||||
) -> OutputTarget:
|
||||
"""Create a new output target.
|
||||
|
||||
Raises:
|
||||
ValueError: If validation fails
|
||||
@@ -117,13 +118,13 @@ class PictureTargetStore:
|
||||
# Check for duplicate name
|
||||
for target in self._targets.values():
|
||||
if target.name == name:
|
||||
raise ValueError(f"Picture target with name '{name}' already exists")
|
||||
raise ValueError(f"Output target with name '{name}' already exists")
|
||||
|
||||
target_id = f"pt_{uuid.uuid4().hex[:8]}"
|
||||
now = datetime.utcnow()
|
||||
|
||||
if target_type == "led":
|
||||
target: PictureTarget = WledPictureTarget(
|
||||
target: OutputTarget = WledOutputTarget(
|
||||
id=target_id,
|
||||
name=name,
|
||||
target_type="led",
|
||||
@@ -141,7 +142,7 @@ class PictureTargetStore:
|
||||
updated_at=now,
|
||||
)
|
||||
elif target_type == "key_colors":
|
||||
target = KeyColorsPictureTarget(
|
||||
target = KeyColorsOutputTarget(
|
||||
id=target_id,
|
||||
name=name,
|
||||
target_type="key_colors",
|
||||
@@ -157,7 +158,7 @@ class PictureTargetStore:
|
||||
self._targets[target_id] = target
|
||||
self._save()
|
||||
|
||||
logger.info(f"Created picture target: {name} ({target_id}, type={target_type})")
|
||||
logger.info(f"Created output target: {name} ({target_id}, type={target_type})")
|
||||
return target
|
||||
|
||||
def update_target(
|
||||
@@ -175,14 +176,14 @@ class PictureTargetStore:
|
||||
protocol: Optional[str] = None,
|
||||
key_colors_settings: Optional[KeyColorsSettings] = None,
|
||||
description: Optional[str] = None,
|
||||
) -> PictureTarget:
|
||||
"""Update a picture target.
|
||||
) -> OutputTarget:
|
||||
"""Update an output target.
|
||||
|
||||
Raises:
|
||||
ValueError: If target not found or validation fails
|
||||
"""
|
||||
if target_id not in self._targets:
|
||||
raise ValueError(f"Picture target not found: {target_id}")
|
||||
raise ValueError(f"Output target not found: {target_id}")
|
||||
|
||||
target = self._targets[target_id]
|
||||
|
||||
@@ -190,7 +191,7 @@ class PictureTargetStore:
|
||||
# Check for duplicate name (exclude self)
|
||||
for other in self._targets.values():
|
||||
if other.id != target_id and other.name == name:
|
||||
raise ValueError(f"Picture target with name '{name}' already exists")
|
||||
raise ValueError(f"Output target with name '{name}' already exists")
|
||||
|
||||
target.update_fields(
|
||||
name=name,
|
||||
@@ -210,42 +211,42 @@ class PictureTargetStore:
|
||||
target.updated_at = datetime.utcnow()
|
||||
self._save()
|
||||
|
||||
logger.info(f"Updated picture target: {target_id}")
|
||||
logger.info(f"Updated output target: {target_id}")
|
||||
return target
|
||||
|
||||
def delete_target(self, target_id: str) -> None:
|
||||
"""Delete a picture target.
|
||||
"""Delete an output target.
|
||||
|
||||
Raises:
|
||||
ValueError: If target not found
|
||||
"""
|
||||
if target_id not in self._targets:
|
||||
raise ValueError(f"Picture target not found: {target_id}")
|
||||
raise ValueError(f"Output target not found: {target_id}")
|
||||
|
||||
del self._targets[target_id]
|
||||
self._save()
|
||||
|
||||
logger.info(f"Deleted picture target: {target_id}")
|
||||
logger.info(f"Deleted output target: {target_id}")
|
||||
|
||||
def get_targets_for_device(self, device_id: str) -> List[PictureTarget]:
|
||||
def get_targets_for_device(self, device_id: str) -> List[OutputTarget]:
|
||||
"""Get all targets that reference a specific device."""
|
||||
return [
|
||||
t for t in self._targets.values()
|
||||
if isinstance(t, WledPictureTarget) and t.device_id == device_id
|
||||
if isinstance(t, WledOutputTarget) and t.device_id == device_id
|
||||
]
|
||||
|
||||
def get_targets_referencing_source(self, source_id: str) -> List[str]:
|
||||
"""Return names of KC targets that reference a picture source."""
|
||||
return [
|
||||
target.name for target in self._targets.values()
|
||||
if isinstance(target, KeyColorsPictureTarget) and target.picture_source_id == source_id
|
||||
if isinstance(target, KeyColorsOutputTarget) and target.picture_source_id == source_id
|
||||
]
|
||||
|
||||
def get_targets_referencing_css(self, css_id: str) -> List[str]:
|
||||
"""Return names of LED targets that reference a color strip source."""
|
||||
return [
|
||||
target.name for target in self._targets.values()
|
||||
if isinstance(target, WledPictureTarget)
|
||||
if isinstance(target, WledOutputTarget)
|
||||
and target.color_strip_source_id == css_id
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from wled_controller.storage.key_colors_picture_target import KeyColorRectangle
|
||||
from wled_controller.storage.key_colors_output_target import KeyColorRectangle
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -6,7 +6,7 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from wled_controller.storage.key_colors_picture_target import KeyColorRectangle
|
||||
from wled_controller.storage.key_colors_output_target import KeyColorRectangle
|
||||
from wled_controller.storage.pattern_template import PatternTemplate
|
||||
from wled_controller.utils import atomic_write_json, get_logger
|
||||
|
||||
@@ -203,11 +203,11 @@ class PatternTemplateStore:
|
||||
|
||||
logger.info(f"Deleted pattern template: {template_id}")
|
||||
|
||||
def get_targets_referencing(self, template_id: str, picture_target_store) -> List[str]:
|
||||
def get_targets_referencing(self, template_id: str, output_target_store) -> List[str]:
|
||||
"""Return names of KC targets that reference this template."""
|
||||
from wled_controller.storage.key_colors_picture_target import KeyColorsPictureTarget
|
||||
from wled_controller.storage.key_colors_output_target import KeyColorsOutputTarget
|
||||
|
||||
return [
|
||||
target.name for target in picture_target_store.get_all_targets()
|
||||
if isinstance(target, KeyColorsPictureTarget) and target.settings.pattern_template_id == template_id
|
||||
target.name for target in output_target_store.get_all_targets()
|
||||
if isinstance(target, KeyColorsOutputTarget) and target.settings.pattern_template_id == template_id
|
||||
]
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
"""LED picture target — sends color strip sources to an LED device."""
|
||||
"""LED output target — sends color strip sources to an LED device."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from wled_controller.storage.picture_target import PictureTarget
|
||||
from wled_controller.storage.output_target import OutputTarget
|
||||
|
||||
DEFAULT_STATE_CHECK_INTERVAL = 30 # seconds
|
||||
|
||||
|
||||
@dataclass
|
||||
class WledPictureTarget(PictureTarget):
|
||||
"""LED picture target — pairs an LED device with a ColorStripSource."""
|
||||
class WledOutputTarget(OutputTarget):
|
||||
"""LED output target — pairs an LED device with a ColorStripSource."""
|
||||
|
||||
device_id: str = ""
|
||||
color_strip_source_id: str = ""
|
||||
@@ -104,7 +104,7 @@ class WledPictureTarget(PictureTarget):
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "WledPictureTarget":
|
||||
def from_dict(cls, data: dict) -> "WledOutputTarget":
|
||||
"""Create from dictionary."""
|
||||
return cls(
|
||||
id=data["id"],
|
||||
Reference in New Issue
Block a user