Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions custom_components/camera_snapshot_processor/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from homeassistant.core import HomeAssistant

from .const import (
CONF_ENTITY_NAME,
CONF_HEIGHT,
CONF_KEEP_RATIO,
CONF_QUALITY,
Expand Down Expand Up @@ -91,19 +92,17 @@ async def post(self, request: web.Request) -> web.Response:

data = await request.json()
source_camera = data.get("source_camera")
if source_camera is not None:
# Remove newlines and carriage returns to prevent log injection
source_camera = source_camera.replace('\r', '').replace('\n', '')

if not source_camera:
return web.json_response(
{"error": "source_camera is required"}, status=400
)

# Check if camera already exists
# Get existing cameras (allow duplicates for multi-processing same source)
cameras = dict(entry.data.get("cameras", {}))
for cam_id, cam_config in cameras.items():
if cam_config.get(CONF_SOURCE_CAMERA) == source_camera:
return web.json_response(
{"error": "Camera already configured"}, status=400
)

# Get camera entity to fetch source dimensions
camera_entity = self._get_camera_entity(source_camera)
Expand Down Expand Up @@ -149,6 +148,27 @@ async def post(self, request: web.Request) -> web.Response:
default_width = DEFAULT_WIDTH
default_height = DEFAULT_HEIGHT

# Generate unique entity name if same source camera is used multiple times
source_name = source_camera.replace("camera.", "")
base_entity_name = f"{source_name}_processed"

# Count existing cameras with the same source
same_source_count = sum(
1 for cam_config in cameras.values()
if cam_config.get(CONF_SOURCE_CAMERA) == source_camera
)

# If this is a duplicate source, add suffix (_2, _3, etc.)
if same_source_count > 0:
entity_name = f"{base_entity_name}_{same_source_count + 1}"
_LOGGER.info(
"Multiple cameras from same source %s detected. Using entity name: %s",
source_camera.replace('\r', '').replace('\n', ''),
entity_name.replace('\r', '').replace('\n', ''),
)
else:
entity_name = base_entity_name

# Create new camera with smart default config
camera_id = str(uuid.uuid4())
cameras[camera_id] = {
Expand All @@ -160,6 +180,7 @@ async def post(self, request: web.Request) -> web.Response:
CONF_KEEP_RATIO: DEFAULT_KEEP_RATIO,
CONF_QUALITY: DEFAULT_QUALITY,
CONF_STATE_ICONS: [],
CONF_ENTITY_NAME: entity_name, # Set custom entity name for duplicates
}

# Update entry
Expand Down
5 changes: 2 additions & 3 deletions custom_components/camera_snapshot_processor/frontend/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,8 @@

availableCameras = data.cameras || [];

// Filter out already configured cameras
const configuredCameras = Object.values(cameras).map(c => c.source_camera);
availableCameras = availableCameras.filter(c => !configuredCameras.includes(c.entity_id));
// Note: We allow selecting the same camera multiple times
// to support multiple processed versions of the same source

// Populate select
const select = document.getElementById('new-camera-select');
Expand Down
Loading