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:
salirezav
2025-11-02 19:33:13 -05:00
parent f6a37ca1ba
commit 868aa3f036
33 changed files with 7471 additions and 136 deletions

View File

@@ -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]:

View File

@@ -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