Add scheduling-remote service to docker-compose and enhance camera error handling
- Introduced a new service for scheduling-remote in docker-compose.yml, allowing for better management of scheduling functionalities. - Enhanced error handling in CameraMonitor and CameraStreamer classes to improve robustness during camera initialization and streaming processes. - Updated various components in the management dashboard to support dark mode and improve user experience with consistent styling. - Implemented feature flags for enabling/disabling modules, including the new scheduling module.
This commit is contained in:
@@ -196,7 +196,13 @@ class CameraMonitor:
|
||||
self.logger.info(f"Camera {camera_name} initialized successfully, starting test capture...")
|
||||
except mvsdk.CameraException as init_e:
|
||||
self.logger.warning(f"CameraInit failed for {camera_name}: {init_e.message} (error_code: {init_e.error_code})")
|
||||
return "error", f"Camera initialization failed: {init_e.message}", self._get_device_info_dict(device_info)
|
||||
# Get device info dict before returning - wrap in try/except in case device_info is corrupted
|
||||
try:
|
||||
device_info_dict = self._get_device_info_dict(device_info)
|
||||
except Exception as dev_info_e:
|
||||
self.logger.warning(f"Failed to get device info dict after CameraInit failure: {dev_info_e}")
|
||||
device_info_dict = None
|
||||
return "error", f"Camera initialization failed: {init_e.message}", device_info_dict
|
||||
|
||||
# Quick test - try to get one frame
|
||||
try:
|
||||
@@ -232,10 +238,38 @@ class CameraMonitor:
|
||||
|
||||
def _get_device_info_dict(self, device_info) -> Dict[str, Any]:
|
||||
"""Convert device info to dictionary"""
|
||||
if device_info is None:
|
||||
return {"error": "device_info is None"}
|
||||
|
||||
try:
|
||||
return {"friendly_name": device_info.GetFriendlyName(), "port_type": device_info.GetPortType(), "serial_number": getattr(device_info, "acSn", "Unknown"), "last_checked": time.time()}
|
||||
# Safely access device info methods - wrap each in try/except to prevent segfaults
|
||||
friendly_name = "Unknown"
|
||||
port_type = "Unknown"
|
||||
serial_number = "Unknown"
|
||||
|
||||
try:
|
||||
friendly_name = device_info.GetFriendlyName()
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Failed to get friendly name: {e}")
|
||||
|
||||
try:
|
||||
port_type = device_info.GetPortType()
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Failed to get port type: {e}")
|
||||
|
||||
try:
|
||||
serial_number = getattr(device_info, "acSn", "Unknown")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Failed to get serial number: {e}")
|
||||
|
||||
return {
|
||||
"friendly_name": friendly_name,
|
||||
"port_type": port_type,
|
||||
"serial_number": serial_number,
|
||||
"last_checked": time.time()
|
||||
}
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device info: {e}")
|
||||
self.logger.error(f"Error getting device info: {e}", exc_info=True)
|
||||
return {"error": str(e)}
|
||||
|
||||
def check_camera_now(self, camera_name: str) -> Dict[str, Any]:
|
||||
|
||||
@@ -273,33 +273,99 @@ class CameraStreamer:
|
||||
return False
|
||||
|
||||
# Initialize camera (suppress output to avoid MVCAMAPI error messages)
|
||||
with suppress_camera_errors():
|
||||
self.hCamera = mvsdk.CameraInit(self.device_info, -1, -1)
|
||||
self.logger.info("Camera initialized successfully for streaming")
|
||||
try:
|
||||
with suppress_camera_errors():
|
||||
self.hCamera = mvsdk.CameraInit(self.device_info, -1, -1)
|
||||
self.logger.info("Camera initialized successfully for streaming")
|
||||
except mvsdk.CameraException as init_e:
|
||||
self.logger.error(f"CameraInit failed for streaming {self.camera_config.name}: {init_e.message} (error_code: {init_e.error_code})")
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
# Ensure hCamera is valid before proceeding
|
||||
if self.hCamera is None:
|
||||
self.logger.error("Camera initialization returned None handle")
|
||||
return False
|
||||
|
||||
# Get camera capabilities
|
||||
self.cap = mvsdk.CameraGetCapability(self.hCamera)
|
||||
try:
|
||||
self.cap = mvsdk.CameraGetCapability(self.hCamera)
|
||||
except mvsdk.CameraException as cap_e:
|
||||
self.logger.error(f"CameraGetCapability failed for {self.camera_config.name}: {cap_e.message} (error_code: {cap_e.error_code})")
|
||||
if self.hCamera:
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except:
|
||||
pass
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
# Determine if camera is monochrome
|
||||
self.monoCamera = self.cap.sIspCapacity.bMonoSensor != 0
|
||||
|
||||
# Set output format based on camera type and bit depth
|
||||
if self.monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
try:
|
||||
if self.monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
except mvsdk.CameraException as fmt_e:
|
||||
self.logger.error(f"CameraSetIspOutFormat failed for {self.camera_config.name}: {fmt_e.message} (error_code: {fmt_e.error_code})")
|
||||
if self.hCamera:
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except:
|
||||
pass
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
# Configure camera settings for streaming (optimized for preview)
|
||||
self._configure_streaming_settings()
|
||||
try:
|
||||
self._configure_streaming_settings()
|
||||
except Exception as config_e:
|
||||
self.logger.error(f"Failed to configure streaming settings for {self.camera_config.name}: {config_e}")
|
||||
if self.hCamera:
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except:
|
||||
pass
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
# Allocate frame buffer
|
||||
bytes_per_pixel = 1 if self.monoCamera else 3
|
||||
self.frame_buffer_size = self.cap.sResolutionRange.iWidthMax * self.cap.sResolutionRange.iHeightMax * bytes_per_pixel
|
||||
self.frame_buffer = mvsdk.CameraAlignMalloc(self.frame_buffer_size, 16)
|
||||
try:
|
||||
bytes_per_pixel = 1 if self.monoCamera else 3
|
||||
self.frame_buffer_size = self.cap.sResolutionRange.iWidthMax * self.cap.sResolutionRange.iHeightMax * bytes_per_pixel
|
||||
self.frame_buffer = mvsdk.CameraAlignMalloc(self.frame_buffer_size, 16)
|
||||
except Exception as buf_e:
|
||||
self.logger.error(f"Failed to allocate frame buffer for {self.camera_config.name}: {buf_e}")
|
||||
if self.hCamera:
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except:
|
||||
pass
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
# Start camera
|
||||
mvsdk.CameraPlay(self.hCamera)
|
||||
self.logger.info("Camera started successfully for streaming")
|
||||
try:
|
||||
mvsdk.CameraPlay(self.hCamera)
|
||||
self.logger.info("Camera started successfully for streaming")
|
||||
except mvsdk.CameraException as play_e:
|
||||
self.logger.error(f"CameraPlay failed for {self.camera_config.name}: {play_e.message} (error_code: {play_e.error_code})")
|
||||
if self.frame_buffer:
|
||||
try:
|
||||
mvsdk.CameraAlignFree(self.frame_buffer)
|
||||
except:
|
||||
pass
|
||||
self.frame_buffer = None
|
||||
if self.hCamera:
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except:
|
||||
pass
|
||||
self.hCamera = None
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user