Update Docker configuration, enhance error handling, and improve logging

- Added health check to the camera management API service in docker-compose.yml for better container reliability.
- Updated installation scripts in Dockerfile to check for existing dependencies before installation, improving efficiency.
- Enhanced error handling in the USDAVisionSystem class to allow partial operation if some components fail to start, preventing immediate shutdown.
- Improved logging throughout the application, including more detailed error messages and critical error handling in the main loop.
- Refactored WebSocketManager and CameraMonitor classes to use debug logging for connection events, reducing log noise.
This commit is contained in:
salirezav
2025-12-03 17:23:31 -05:00
parent 2bce817b4e
commit 933d4417a5
30 changed files with 4314 additions and 220 deletions

View File

@@ -90,8 +90,20 @@ class CameraStreamer:
"""Start streaming preview frames"""
with self._lock:
if self.streaming:
self.logger.warning("Streaming already active")
return True
self.logger.warning("Streaming already active - checking if thread is alive")
# Check if thread is actually running
if self._streaming_thread and self._streaming_thread.is_alive():
self.logger.info("Streaming thread is alive, returning success")
return True
else:
# Thread died but flag wasn't reset - clean up and restart
self.logger.warning("Streaming flag set but thread is dead - cleaning up and restarting")
self.streaming = False
if self.hCamera is not None:
try:
self._cleanup_camera()
except Exception as e:
self.logger.error(f"Error cleaning up stale camera handle: {e}")
try:
# Initialize camera for streaming
@@ -249,6 +261,15 @@ class CameraStreamer:
try:
self.logger.info(f"Initializing camera for streaming: {self.camera_config.name}")
# Safety check: ensure no stale camera handle exists
if self.hCamera is not None and not self._using_shared_camera:
self.logger.warning("Stale camera handle detected during initialization - cleaning up first")
try:
mvsdk.CameraUnInit(self.hCamera)
except Exception as e:
self.logger.warning(f"Error cleaning up stale handle: {e}")
self.hCamera = None
# Check if recorder is active and has camera open - if so, share it
if self.recorder and self.recorder.hCamera and self.recorder.recording:
self.logger.info("Recorder is active with camera open - will share recorder's camera connection")
@@ -423,11 +444,41 @@ class CameraStreamer:
time.sleep(STREAMING_LOOP_SLEEP) # Just wait, recorder populates queues
continue
# Safety check: ensure camera handle is valid before use
if self.hCamera is None:
self.logger.error("Camera handle is None in streaming loop - stopping")
break
# Capture frame with timeout
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, CAMERA_GET_BUFFER_TIMEOUT)
try:
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, CAMERA_GET_BUFFER_TIMEOUT)
except mvsdk.CameraException as e:
if e.error_code == mvsdk.CAMERA_STATUS_TIME_OUT:
continue # Timeout is normal, continue
else:
self.logger.error(f"CameraGetImageBuffer failed: {e.message} (error_code: {e.error_code})")
# If camera is invalid, break to prevent segfault
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
self.logger.error("Invalid camera handle detected - stopping streaming loop")
break
time.sleep(BRIEF_PAUSE_SLEEP)
continue
# Process frame
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.frame_buffer, FrameHead)
try:
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.frame_buffer, FrameHead)
except mvsdk.CameraException as e:
self.logger.error(f"CameraImageProcess failed: {e.message} (error_code: {e.error_code})")
# Release buffer before continuing
try:
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
except:
pass
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
self.logger.error("Invalid camera handle in image process - stopping streaming loop")
break
time.sleep(BRIEF_PAUSE_SLEEP)
continue
# Convert to OpenCV format
frame = self._convert_frame_to_opencv(FrameHead)
@@ -477,7 +528,14 @@ class CameraStreamer:
pass
# Release buffer
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
try:
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
except mvsdk.CameraException as e:
self.logger.error(f"CameraReleaseImageBuffer failed: {e.message} (error_code: {e.error_code})")
# If handle is invalid, break to prevent further issues
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
self.logger.error("Invalid camera handle when releasing buffer - stopping streaming loop")
break
# Control frame rate
time.sleep(1.0 / self.preview_fps)
@@ -491,6 +549,15 @@ class CameraStreamer:
self.logger.error(f"Fatal error in streaming loop: {e}")
finally:
self.logger.info("Streaming loop ended")
# Reset streaming flag when loop ends
with self._lock:
self.streaming = False
# Cleanup camera resources if not already done
if self.hCamera is not None and not self._using_shared_camera:
try:
self._cleanup_camera()
except Exception as cleanup_e:
self.logger.error(f"Error during cleanup after loop ended: {cleanup_e}")
def _convert_frame_to_opencv(self, FrameHead) -> Optional[np.ndarray]:
"""Convert camera frame to OpenCV format"""