import json import logging import threading import time from config import Config from camera import VideoStream logger = logging.getLogger(__name__) class CameraManager: def __init__(self): # State containers # Replaces global 'cameras', 'rois', 'camera_results' self.cameras = {} self.rois = {} self.results = {} # Load initial configuration immediately self.load_camera_config() self.load_roi_config() def load_camera_config(self): """Load settings from JSON and initialize VideoStream objects.""" try: with open(Config.CAMERA_CONFIG_PATH, 'r') as f: config_data = json.load(f) for cam_conf in config_data: cam_id = cam_conf['id'] if not cam_conf.get("active", False): continue # Initialize stream only if new if cam_id not in self.cameras: logger.info(f"Initializing new camera manager entry: {cam_id}") stream = VideoStream( camera_id=cam_id, rtsp_url=cam_conf['rtsp_url'], flip_type=cam_conf.get("flip_type", "None") ) stream.start() self.cameras[cam_id] = { "id": cam_id, "name": cam_conf['name'], "stream": stream, "width": stream.width or 640, "height": stream.height or 360, "active": True, "rtsp_url": cam_conf['rtsp_url'], "flip_type": cam_conf.get("flip_type", "None") } # Ensure ROI list exists if cam_id not in self.rois: self.rois[cam_id] = [] except Exception as e: logger.error(f"Failed to load camera config: {e}") def load_roi_config(self): """Reload ROI definitions from disk.""" try: with open(Config.ROI_CONFIG_PATH, 'r') as f: self.rois = json.load(f) # logger.info(f"ROIs loaded/reloaded.") # Optional logging except Exception as e: logger.error(f"Error loading ROI config: {e}") self.rois = {} def save_roi_config(self): """Save current ROIs to disk.""" try: with open(Config.ROI_CONFIG_PATH, 'w') as f: json.dump(self.rois, f, indent=4) return {"success": True} except Exception as e: logger.error(f"Error saving ROI config: {e}") return {"success": False, "error": str(e)} def get_frame(self, camera_id): """Helper to get the latest frame from a specific camera.""" cam = self.cameras.get(camera_id) if not cam or not cam.get('stream'): return None return cam['stream'].read() def get_camera_list(self): """Return simple list of cameras for API.""" return [{"id": c['id'], "name": c['name']} for c in self.cameras.values()] def update_camera_flip(self, camera_id, flip_type): """Update flip settings for a camera.""" if camera_id in self.cameras: self.cameras[camera_id]["flip_type"] = flip_type stream = self.cameras[camera_id].get("stream") if stream: stream.set_flip(flip_type) # Persist to disk try: with open(Config.CAMERA_CONFIG_PATH, 'r') as f: config = json.load(f) for c in config: if c['id'] == camera_id: c['flip_type'] = flip_type with open(Config.CAMERA_CONFIG_PATH, 'w') as f: json.dump(config, f, indent=4) return True except Exception as e: logger.error(f"Failed to save flip config: {e}") return False