diff --git a/.gitignore b/.gitignore index 2303924..88dc0d8 100644 --- a/.gitignore +++ b/.gitignore @@ -59,8 +59,8 @@ config_production.json .DS_Store Thumbs.db -# Camera library cache -python demo/__pycache__/ +# Camera SDK cache +camera_sdk/__pycache__/ # Test outputs test_output/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 7fa27ff..806bf53 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "python.analysis.extraPaths": [ - "./python demo" + "./camera_sdk" ] } \ No newline at end of file diff --git a/README.md b/README.md index 86df0d7..770e690 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This system integrates MQTT machine monitoring with automated video recording fr - **🔄 MQTT Integration**: Listens to multiple machine state topics - **📹 Automatic Recording**: Starts/stops recording based on machine states -- **📷 GigE Camera Support**: Uses python demo library (mvsdk) for camera control +- **📷 GigE Camera Support**: Uses camera SDK library (mvsdk) for camera control - **⚡ Multi-threading**: Concurrent MQTT listening, camera monitoring, and recording - **🌐 REST API**: FastAPI server for dashboard integration - **📡 WebSocket Support**: Real-time status updates @@ -19,6 +19,38 @@ This system integrates MQTT machine monitoring with automated video recording fr - **⚙️ Configuration Management**: JSON-based configuration system - **🕐 Timezone Sync**: Proper time synchronization for Atlanta, Georgia +## 📁 Project Structure + +``` +USDA-Vision-Cameras/ +├── README.md # Main documentation (this file) +├── main.py # System entry point +├── config.json # System configuration +├── requirements.txt # Python dependencies +├── pyproject.toml # UV package configuration +├── start_system.sh # Startup script +├── setup_timezone.sh # Time sync setup +├── usda_vision_system/ # Main application +│ ├── core/ # Core functionality +│ ├── mqtt/ # MQTT integration +│ ├── camera/ # Camera management +│ ├── storage/ # File management +│ ├── api/ # REST API server +│ └── main.py # Application coordinator +├── camera_sdk/ # GigE camera SDK library +├── demos/ # Demo and example code +│ ├── cv_grab*.py # Camera SDK usage examples +│ └── mqtt_*.py # MQTT demo scripts +├── tests/ # Test files +│ ├── test_*.py # System tests +│ └── legacy_tests/ # Archived development files +├── notebooks/ # Jupyter notebooks +├── docs/ # Documentation files +└── storage/ # Recording storage + ├── camera1/ # Camera 1 recordings + └── camera2/ # Camera 2 recordings +``` + ## 🏗️ Architecture ``` @@ -46,7 +78,7 @@ This system integrates MQTT machine monitoring with automated video recording fr ## 📋 Prerequisites ### Hardware Requirements -- GigE cameras compatible with python demo library +- GigE cameras compatible with camera SDK library - Network connection to MQTT broker - Sufficient storage space for video recordings @@ -90,7 +122,7 @@ pip install -r requirements.txt ``` ### 3. Setup GigE Camera Library -Ensure the `python demo` directory contains the mvsdk library for your GigE cameras. This should include: +Ensure the `camera_sdk` directory contains the mvsdk library for your GigE cameras. This should include: - `mvsdk.py` - Python SDK wrapper - Camera driver libraries - Any camera-specific configuration files @@ -519,13 +551,13 @@ python check_time.py # Check camera connections ping 192.168.1.165 # Replace with your camera IP -# Verify python demo library -ls -la "python demo/" +# Verify camera SDK library +ls -la "camera_sdk/" # Should contain mvsdk.py and related files # Test camera discovery manually python -c " -import sys; sys.path.append('./python demo') +import sys; sys.path.append('./camera_sdk') import mvsdk devices = mvsdk.CameraEnumerateDevice() print(f'Found {len(devices)} cameras') @@ -579,7 +611,7 @@ df -h storage/ # Test camera initialization python -c " -import sys; sys.path.append('./python demo') +import sys; sys.path.append('./camera_sdk') import mvsdk devices = mvsdk.CameraEnumerateDevice() if devices: diff --git a/camera_sdk/README.md b/camera_sdk/README.md new file mode 100644 index 0000000..c507622 --- /dev/null +++ b/camera_sdk/README.md @@ -0,0 +1,66 @@ +# Camera SDK Library + +This directory contains the core GigE camera SDK library required for the USDA Vision Camera System. + +## Contents + +### Core SDK Library +- **`mvsdk.py`** - Python wrapper for the GigE camera SDK + - Provides Python bindings for camera control functions + - Handles camera initialization, configuration, and image capture + - **Critical dependency** - Required for all camera operations + +## Important Notes + +⚠️ **This is NOT demo code** - This directory contains the core SDK library that the entire system depends on for camera functionality. + +### SDK Library Details +- The `mvsdk.py` file is a Python wrapper around the native camera SDK +- It provides ctypes bindings to the underlying C/C++ camera library +- Contains all camera control functions, constants, and data structures +- Used by all camera modules in `usda_vision_system/camera/` + +### Dependencies +- Requires the native camera SDK library (`libMVSDK.so` on Linux) +- The native library should be installed system-wide or available in the library path + +## Usage + +This SDK is automatically imported by the camera modules: +```python +# Imported by camera modules +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) +import mvsdk +``` + +## Demo Code + +For camera usage examples and demo code, see the `../demos/` directory: +- `cv_grab.py` - Basic camera capture example +- `cv_grab2.py` - Multi-camera capture example +- `cv_grab_callback.py` - Callback-based capture example +- `grab.py` - Simple image capture example + +## Troubleshooting + +If you encounter camera SDK issues: + +1. **Check SDK Installation**: + ```bash + ls -la camera_sdk/mvsdk.py + ``` + +2. **Test SDK Import**: + ```bash + python -c "import sys; sys.path.append('./camera_sdk'); import mvsdk; print('SDK imported successfully')" + ``` + +3. **Check Native Library**: + ```bash + # On Linux + ldconfig -p | grep MVSDK + ``` + +For more troubleshooting, see the main [README.md](../README.md#troubleshooting). diff --git a/python demo/mvsdk.py b/camera_sdk/mvsdk.py similarity index 100% rename from python demo/mvsdk.py rename to camera_sdk/mvsdk.py diff --git a/container_init.sh b/container_init.sh new file mode 100755 index 0000000..f7c792d --- /dev/null +++ b/container_init.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Container initialization script for USDA Vision Camera System +# This script sets up and starts the systemd service in a container environment + +echo "🐳 Container Init - USDA Vision Camera System" +echo "=============================================" + +# Start systemd if not already running (for containers) +if ! pgrep systemd > /dev/null; then + echo "🔧 Starting systemd..." + exec /sbin/init & + sleep 5 +fi + +# Setup the service if not already installed +if [ ! -f "/etc/systemd/system/usda-vision-camera.service" ]; then + echo "📦 Setting up USDA Vision Camera service..." + cd /home/alireza/USDA-vision-cameras + sudo ./setup_service.sh +fi + +# Start the service +echo "🚀 Starting USDA Vision Camera service..." +sudo systemctl start usda-vision-camera + +# Follow the logs +echo "📋 Following service logs (Ctrl+C to exit)..." +sudo journalctl -u usda-vision-camera -f diff --git a/python demo/cv_grab.py b/demos/cv_grab.py similarity index 100% rename from python demo/cv_grab.py rename to demos/cv_grab.py diff --git a/python demo/cv_grab2.py b/demos/cv_grab2.py similarity index 100% rename from python demo/cv_grab2.py rename to demos/cv_grab2.py diff --git a/python demo/cv_grab_callback.py b/demos/cv_grab_callback.py similarity index 100% rename from python demo/cv_grab_callback.py rename to demos/cv_grab_callback.py diff --git a/demo_mqtt_console.py b/demos/demo_mqtt_console.py similarity index 100% rename from demo_mqtt_console.py rename to demos/demo_mqtt_console.py diff --git a/python demo/grab.py b/demos/grab.py similarity index 100% rename from python demo/grab.py rename to demos/grab.py diff --git a/mqtt_publisher_test.py b/demos/mqtt_publisher_test.py similarity index 100% rename from mqtt_publisher_test.py rename to demos/mqtt_publisher_test.py diff --git a/mqtt_test.py b/demos/mqtt_test.py similarity index 100% rename from mqtt_test.py rename to demos/mqtt_test.py diff --git a/python demo/readme.txt b/demos/readme.txt similarity index 100% rename from python demo/readme.txt rename to demos/readme.txt diff --git a/API_CHANGES_SUMMARY.md b/docs/API_CHANGES_SUMMARY.md similarity index 100% rename from API_CHANGES_SUMMARY.md rename to docs/API_CHANGES_SUMMARY.md diff --git a/CAMERA_RECOVERY_GUIDE.md b/docs/CAMERA_RECOVERY_GUIDE.md similarity index 100% rename from CAMERA_RECOVERY_GUIDE.md rename to docs/CAMERA_RECOVERY_GUIDE.md diff --git a/MQTT_LOGGING_GUIDE.md b/docs/MQTT_LOGGING_GUIDE.md similarity index 100% rename from MQTT_LOGGING_GUIDE.md rename to docs/MQTT_LOGGING_GUIDE.md diff --git a/PROJECT_COMPLETE.md b/docs/PROJECT_COMPLETE.md similarity index 93% rename from PROJECT_COMPLETE.md rename to docs/PROJECT_COMPLETE.md index 33f5bf9..0f4df48 100644 --- a/PROJECT_COMPLETE.md +++ b/docs/PROJECT_COMPLETE.md @@ -9,7 +9,7 @@ The USDA Vision Camera System has been successfully implemented, tested, and doc ### ✅ Core Functionality - **MQTT Integration**: Dual topic listening for machine states - **Automatic Recording**: Camera recording triggered by machine on/off states -- **GigE Camera Support**: Full integration with python demo library +- **GigE Camera Support**: Full integration with camera SDK library - **Multi-threading**: Concurrent MQTT + camera monitoring + recording - **File Management**: Timestamp-based naming in organized directories @@ -50,11 +50,16 @@ USDA-Vision-Cameras/ │ ├── storage/ # File management │ ├── api/ # REST API server │ └── main.py # Application coordinator -├── python demo/ # GigE camera library +├── camera_sdk/ # GigE camera SDK library +├── demos/ # Demo and example code +│ ├── cv_grab*.py # Camera SDK usage examples +│ └── mqtt_*.py # MQTT demo scripts ├── storage/ # Recording storage │ ├── camera1/ # Camera 1 recordings │ └── camera2/ # Camera 2 recordings -└── old tests/ # Archived development files +├── tests/ # Test files and legacy tests +├── notebooks/ # Jupyter notebooks +└── docs/ # Documentation files ``` ## 🚀 How to Deploy diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..6dc6beb --- /dev/null +++ b/docs/README.md @@ -0,0 +1,49 @@ +# USDA Vision Camera System - Documentation + +This directory contains detailed documentation for the USDA Vision Camera System. + +## Documentation Files + +### 📋 [PROJECT_COMPLETE.md](PROJECT_COMPLETE.md) +Complete project overview and final status documentation. Contains: +- Project completion status +- Final system architecture +- Deployment instructions +- Production readiness checklist + +### 🔧 [API_CHANGES_SUMMARY.md](API_CHANGES_SUMMARY.md) +Summary of API changes and enhancements made to the system. + +### 📷 [CAMERA_RECOVERY_GUIDE.md](CAMERA_RECOVERY_GUIDE.md) +Guide for camera recovery procedures and troubleshooting camera-related issues. + +### 📡 [MQTT_LOGGING_GUIDE.md](MQTT_LOGGING_GUIDE.md) +Comprehensive guide for MQTT logging configuration and troubleshooting. + +## Main Documentation + +The main system documentation is located in the root directory: +- **[../README.md](../README.md)** - Primary system documentation with installation, configuration, and usage instructions + +## Additional Resources + +### Demo Code +- **[../demos/](../demos/)** - Demo scripts and camera SDK examples + +### Test Files +- **[../tests/](../tests/)** - Test scripts and legacy test files + +### Jupyter Notebooks +- **[../notebooks/](../notebooks/)** - Interactive notebooks for system exploration and testing + +## Quick Links + +- [System Installation](../README.md#installation) +- [Configuration Guide](../README.md#configuration) +- [API Documentation](../README.md#api-reference) +- [Troubleshooting](../README.md#troubleshooting) +- [Camera SDK Examples](../demos/camera_sdk_examples/) + +## Support + +For technical support and questions, refer to the main [README.md](../README.md) troubleshooting section or check the system logs. diff --git a/old tests/camera_status_test.ipynb b/notebooks/camera_status_test.ipynb similarity index 100% rename from old tests/camera_status_test.ipynb rename to notebooks/camera_status_test.ipynb diff --git a/old tests/camera_test_setup.ipynb b/notebooks/camera_test_setup.ipynb similarity index 100% rename from old tests/camera_test_setup.ipynb rename to notebooks/camera_test_setup.ipynb diff --git a/old tests/exposure test.ipynb b/notebooks/exposure test.ipynb similarity index 100% rename from old tests/exposure test.ipynb rename to notebooks/exposure test.ipynb diff --git a/old tests/gige_camera_advanced.ipynb b/notebooks/gige_camera_advanced.ipynb similarity index 100% rename from old tests/gige_camera_advanced.ipynb rename to notebooks/gige_camera_advanced.ipynb diff --git a/old tests/mqtt test.ipynb b/notebooks/mqtt test.ipynb similarity index 100% rename from old tests/mqtt test.ipynb rename to notebooks/mqtt test.ipynb diff --git a/python demo/__pycache__/mvsdk.cpython-311.pyc b/python demo/__pycache__/mvsdk.cpython-311.pyc deleted file mode 100644 index 9c7f50c..0000000 Binary files a/python demo/__pycache__/mvsdk.cpython-311.pyc and /dev/null differ diff --git a/python demo/__pycache__/mvsdk.cpython-313.pyc b/python demo/__pycache__/mvsdk.cpython-313.pyc deleted file mode 100644 index a1b88db..0000000 Binary files a/python demo/__pycache__/mvsdk.cpython-313.pyc and /dev/null differ diff --git a/setup_service.sh b/setup_service.sh new file mode 100755 index 0000000..325cfb6 --- /dev/null +++ b/setup_service.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# USDA Vision Camera System Service Setup Script + +echo "USDA Vision Camera System - Service Setup" +echo "========================================" + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo "❌ This script must be run as root (use sudo)" + exit 1 +fi + +# Get the current directory (where the script is located) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVICE_FILE="$SCRIPT_DIR/usda-vision-camera.service" + +echo "📁 Working directory: $SCRIPT_DIR" + +# Check if service file exists +if [ ! -f "$SERVICE_FILE" ]; then + echo "❌ Service file not found: $SERVICE_FILE" + exit 1 +fi + +# Make start_system.sh executable +echo "🔧 Making start_system.sh executable..." +chmod +x "$SCRIPT_DIR/start_system.sh" + +# Update the service file with the correct path +echo "📝 Updating service file with correct paths..." +sed -i "s|WorkingDirectory=.*|WorkingDirectory=$SCRIPT_DIR|g" "$SERVICE_FILE" +sed -i "s|ExecStart=.*|ExecStart=/bin/bash $SCRIPT_DIR/start_system.sh|g" "$SERVICE_FILE" + +# Copy service file to systemd directory +echo "📋 Installing service file..." +cp "$SERVICE_FILE" /etc/systemd/system/ + +# Reload systemd daemon +echo "🔄 Reloading systemd daemon..." +systemctl daemon-reload + +# Enable the service +echo "✅ Enabling USDA Vision Camera service..." +systemctl enable usda-vision-camera.service + +# Check service status +echo "📊 Service status:" +systemctl status usda-vision-camera.service --no-pager + +echo "" +echo "🎉 Service setup complete!" +echo "" +echo "Available commands:" +echo " sudo systemctl start usda-vision-camera # Start the service" +echo " sudo systemctl stop usda-vision-camera # Stop the service" +echo " sudo systemctl restart usda-vision-camera # Restart the service" +echo " sudo systemctl status usda-vision-camera # Check service status" +echo " sudo journalctl -u usda-vision-camera -f # View live logs" +echo "" +echo "The service will automatically start when the container/system boots." diff --git a/start_system.sh b/start_system.sh index b1c3f25..db61d06 100755 --- a/start_system.sh +++ b/start_system.sh @@ -38,10 +38,18 @@ python test_system.py if [ $? -ne 0 ]; then echo "❌ System tests failed. Please check the configuration." - read -p "Do you want to continue anyway? (y/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 + # When running as a service, don't prompt for user input + if [ -t 0 ]; then + # Interactive mode - prompt user + read -p "Do you want to continue anyway? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi + else + # Non-interactive mode (service) - continue with warning + echo "⚠️ Running in non-interactive mode. Continuing despite test failures..." + sleep 2 fi fi diff --git a/check_time.py b/tests/check_time.py similarity index 100% rename from check_time.py rename to tests/check_time.py diff --git a/old tests/01README.md b/tests/legacy_tests/01README.md similarity index 100% rename from old tests/01README.md rename to tests/legacy_tests/01README.md diff --git a/tests/legacy_tests/Camera/Data/054012620023.mvdat b/tests/legacy_tests/Camera/Data/054012620023.mvdat new file mode 100644 index 0000000..2d2bce7 Binary files /dev/null and b/tests/legacy_tests/Camera/Data/054012620023.mvdat differ diff --git a/tests/legacy_tests/Camera/Data/054052320151.mvdat b/tests/legacy_tests/Camera/Data/054052320151.mvdat new file mode 100644 index 0000000..367dfb3 Binary files /dev/null and b/tests/legacy_tests/Camera/Data/054052320151.mvdat differ diff --git a/tests/legacy_tests/Camera/log/error_20250728-153215.191852 b/tests/legacy_tests/Camera/log/error_20250728-153215.191852 new file mode 100644 index 0000000..1f3054f --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153215.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:32:15 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:32:15.057651 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153233.191852 b/tests/legacy_tests/Camera/log/error_20250728-153233.191852 new file mode 100644 index 0000000..a32f33b --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153233.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:32:33 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:32:33.490923 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153234.191852 b/tests/legacy_tests/Camera/log/error_20250728-153234.191852 new file mode 100644 index 0000000..f6c89e6 --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153234.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:32:34 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:32:34.649940 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153239.191852 b/tests/legacy_tests/Camera/log/error_20250728-153239.191852 new file mode 100644 index 0000000..72724ef --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153239.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:32:39 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:32:39.753448 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153245.191852 b/tests/legacy_tests/Camera/log/error_20250728-153245.191852 new file mode 100644 index 0000000..5eb54c0 --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153245.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:32:45 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:32:45.492905 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153340.191852 b/tests/legacy_tests/Camera/log/error_20250728-153340.191852 new file mode 100644 index 0000000..e43eb01 --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153340.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:33:40 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:33:40.702630 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153418.191852 b/tests/legacy_tests/Camera/log/error_20250728-153418.191852 new file mode 100644 index 0000000..37c64fc --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153418.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:34:18 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:34:18.442386 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153428.191852 b/tests/legacy_tests/Camera/log/error_20250728-153428.191852 new file mode 100644 index 0000000..623da2a --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153428.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:34:28 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:34:28.207051 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153453.191852 b/tests/legacy_tests/Camera/log/error_20250728-153453.191852 new file mode 100644 index 0000000..fb774ca --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153453.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:34:53 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:34:53.315912 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153500.191852 b/tests/legacy_tests/Camera/log/error_20250728-153500.191852 new file mode 100644 index 0000000..b2feb5c --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153500.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:35:00 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:35:00.929268 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153532.191852 b/tests/legacy_tests/Camera/log/error_20250728-153532.191852 new file mode 100644 index 0000000..089956a --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153532.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:35:32 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:35:32.169682 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/tests/legacy_tests/Camera/log/error_20250728-153534.191852 b/tests/legacy_tests/Camera/log/error_20250728-153534.191852 new file mode 100644 index 0000000..cc94c46 --- /dev/null +++ b/tests/legacy_tests/Camera/log/error_20250728-153534.191852 @@ -0,0 +1,4 @@ +Log file created at: 2025/07/28 15:35:34 +Running on machine: vision +Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg +E0728 15:35:34.519351 191852 MVCAMAPI.cpp:369] CameraInit Failed, err:32774,Version:2.1.0.49,FriendlyName:Blower-Yield-Cam,SN:054012620023 diff --git a/old tests/IMPLEMENTATION_SUMMARY.md b/tests/legacy_tests/IMPLEMENTATION_SUMMARY.md similarity index 100% rename from old tests/IMPLEMENTATION_SUMMARY.md rename to tests/legacy_tests/IMPLEMENTATION_SUMMARY.md diff --git a/old tests/README.md b/tests/legacy_tests/README.md similarity index 100% rename from old tests/README.md rename to tests/legacy_tests/README.md diff --git a/old tests/README_SYSTEM.md b/tests/legacy_tests/README_SYSTEM.md similarity index 100% rename from old tests/README_SYSTEM.md rename to tests/legacy_tests/README_SYSTEM.md diff --git a/old tests/TIMEZONE_SETUP_SUMMARY.md b/tests/legacy_tests/TIMEZONE_SETUP_SUMMARY.md similarity index 100% rename from old tests/TIMEZONE_SETUP_SUMMARY.md rename to tests/legacy_tests/TIMEZONE_SETUP_SUMMARY.md diff --git a/old tests/VIDEO_RECORDER_README.md b/tests/legacy_tests/VIDEO_RECORDER_README.md similarity index 100% rename from old tests/VIDEO_RECORDER_README.md rename to tests/legacy_tests/VIDEO_RECORDER_README.md diff --git a/old tests/camera_capture.py b/tests/legacy_tests/camera_capture.py similarity index 100% rename from old tests/camera_capture.py rename to tests/legacy_tests/camera_capture.py diff --git a/old tests/camera_video_recorder.py b/tests/legacy_tests/camera_video_recorder.py similarity index 100% rename from old tests/camera_video_recorder.py rename to tests/legacy_tests/camera_video_recorder.py diff --git a/old tests/main.py b/tests/legacy_tests/main.py similarity index 100% rename from old tests/main.py rename to tests/legacy_tests/main.py diff --git a/old tests/test_exposure.py b/tests/legacy_tests/test_exposure.py similarity index 100% rename from old tests/test_exposure.py rename to tests/legacy_tests/test_exposure.py diff --git a/test_api_changes.py b/tests/test_api_changes.py similarity index 100% rename from test_api_changes.py rename to tests/test_api_changes.py diff --git a/test_camera_recovery_api.py b/tests/test_camera_recovery_api.py similarity index 100% rename from test_camera_recovery_api.py rename to tests/test_camera_recovery_api.py diff --git a/test_max_fps.py b/tests/test_max_fps.py similarity index 100% rename from test_max_fps.py rename to tests/test_max_fps.py diff --git a/test_mqtt_events_api.py b/tests/test_mqtt_events_api.py similarity index 100% rename from test_mqtt_events_api.py rename to tests/test_mqtt_events_api.py diff --git a/test_mqtt_logging.py b/tests/test_mqtt_logging.py similarity index 100% rename from test_mqtt_logging.py rename to tests/test_mqtt_logging.py diff --git a/test_system.py b/tests/test_system.py similarity index 98% rename from test_system.py rename to tests/test_system.py index 5c7deb1..cda4f6c 100644 --- a/test_system.py +++ b/tests/test_system.py @@ -64,7 +64,7 @@ def test_camera_discovery(): """Test camera discovery""" print("\nTesting camera discovery...") try: - sys.path.append("./python demo") + sys.path.append("./camera_sdk") import mvsdk devices = mvsdk.CameraEnumerateDevice() @@ -82,7 +82,7 @@ def test_camera_discovery(): return True except Exception as e: print(f"❌ Camera discovery failed: {e}") - print(" Make sure GigE cameras are connected and python demo library is available") + print(" Make sure GigE cameras are connected and camera SDK library is available") return False diff --git a/test_timezone.py b/tests/test_timezone.py similarity index 100% rename from test_timezone.py rename to tests/test_timezone.py diff --git a/usda-vision-camera.service b/usda-vision-camera.service new file mode 100644 index 0000000..8f39f91 --- /dev/null +++ b/usda-vision-camera.service @@ -0,0 +1,26 @@ +[Unit] +Description=USDA Vision Camera System +After=network.target +Wants=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/home/alireza/USDA-vision-cameras +ExecStart=/bin/bash /home/alireza/USDA-vision-cameras/start_system.sh +Restart=always +RestartSec=10 +StandardOutput=journal +StandardError=journal + +# Environment variables +Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +Environment=HOME=/root + +# Security settings (adjust as needed) +NoNewPrivileges=false +PrivateTmp=false + +[Install] +WantedBy=multi-user.target diff --git a/usda_vision_system/camera/__init__.py b/usda_vision_system/camera/__init__.py index 205313d..df9d25f 100644 --- a/usda_vision_system/camera/__init__.py +++ b/usda_vision_system/camera/__init__.py @@ -2,7 +2,7 @@ Camera module for the USDA Vision Camera System. This module handles GigE camera discovery, management, monitoring, and recording -using the python demo library (mvsdk). +using the camera SDK library (mvsdk). """ from .manager import CameraManager diff --git a/usda_vision_system/camera/__pycache__/__init__.cpython-311.pyc b/usda_vision_system/camera/__pycache__/__init__.cpython-311.pyc index 372f908..6e8702c 100644 Binary files a/usda_vision_system/camera/__pycache__/__init__.cpython-311.pyc and b/usda_vision_system/camera/__pycache__/__init__.cpython-311.pyc differ diff --git a/usda_vision_system/camera/__pycache__/manager.cpython-311.pyc b/usda_vision_system/camera/__pycache__/manager.cpython-311.pyc index b7f9101..22c54b7 100644 Binary files a/usda_vision_system/camera/__pycache__/manager.cpython-311.pyc and b/usda_vision_system/camera/__pycache__/manager.cpython-311.pyc differ diff --git a/usda_vision_system/camera/__pycache__/monitor.cpython-311.pyc b/usda_vision_system/camera/__pycache__/monitor.cpython-311.pyc index 38e71e8..77c29e3 100644 Binary files a/usda_vision_system/camera/__pycache__/monitor.cpython-311.pyc and b/usda_vision_system/camera/__pycache__/monitor.cpython-311.pyc differ diff --git a/usda_vision_system/camera/__pycache__/recorder.cpython-311.pyc b/usda_vision_system/camera/__pycache__/recorder.cpython-311.pyc index c657943..2ca6a05 100644 Binary files a/usda_vision_system/camera/__pycache__/recorder.cpython-311.pyc and b/usda_vision_system/camera/__pycache__/recorder.cpython-311.pyc differ diff --git a/usda_vision_system/camera/manager.py b/usda_vision_system/camera/manager.py index 56dd589..84def7b 100644 --- a/usda_vision_system/camera/manager.py +++ b/usda_vision_system/camera/manager.py @@ -12,8 +12,8 @@ import logging from typing import Dict, List, Optional, Tuple, Any from datetime import datetime -# Add python demo to path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "python demo")) +# Add camera SDK to path +sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) import mvsdk from ..core.config import Config, CameraConfig diff --git a/usda_vision_system/camera/monitor.py b/usda_vision_system/camera/monitor.py index b7f6b22..71fac9f 100644 --- a/usda_vision_system/camera/monitor.py +++ b/usda_vision_system/camera/monitor.py @@ -12,8 +12,8 @@ import logging import contextlib from typing import Dict, List, Optional, Any -# Add python demo to path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "python demo")) +# Add camera SDK to path +sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) import mvsdk from ..core.config import Config diff --git a/usda_vision_system/camera/recorder.py b/usda_vision_system/camera/recorder.py index 80c6fde..187754f 100644 --- a/usda_vision_system/camera/recorder.py +++ b/usda_vision_system/camera/recorder.py @@ -1,7 +1,7 @@ """ Camera Recorder for the USDA Vision Camera System. -This module handles video recording from GigE cameras using the python demo library (mvsdk). +This module handles video recording from GigE cameras using the camera SDK library (mvsdk). """ import sys @@ -16,8 +16,8 @@ from typing import Optional, Dict, Any from datetime import datetime from pathlib import Path -# Add python demo to path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "python demo")) +# Add camera SDK to path +sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) import mvsdk from ..core.config import CameraConfig diff --git a/usda_vision_system/camera/sdk_config.py b/usda_vision_system/camera/sdk_config.py index 9bf97d9..9965244 100644 --- a/usda_vision_system/camera/sdk_config.py +++ b/usda_vision_system/camera/sdk_config.py @@ -8,8 +8,8 @@ import sys import os import logging -# Add python demo to path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "python demo")) +# Add camera SDK to path +sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) import mvsdk logger = logging.getLogger(__name__) @@ -21,62 +21,62 @@ _sdk_initialized = False def initialize_sdk_with_suppression(): """Initialize the camera SDK with error suppression""" global _sdk_initialized - + if _sdk_initialized: return True - + try: # Initialize SDK with English language result = mvsdk.CameraSdkInit(1) if result == 0: logger.info("Camera SDK initialized successfully") - + # Try to set system options to suppress logging try: # These are common options that might control logging # We'll try them and ignore failures since they might not be supported - + # Try to disable debug output try: mvsdk.CameraSetSysOption("DebugLevel", "0") except: pass - + # Try to disable console output try: mvsdk.CameraSetSysOption("ConsoleOutput", "0") except: pass - + # Try to disable error logging try: mvsdk.CameraSetSysOption("ErrorLog", "0") except: pass - + # Try to set log level to none try: mvsdk.CameraSetSysOption("LogLevel", "0") except: pass - + # Try to disable verbose mode try: mvsdk.CameraSetSysOption("Verbose", "0") except: pass - + logger.debug("Attempted to configure SDK logging options") - + except Exception as e: logger.debug(f"Could not configure SDK logging options: {e}") - + _sdk_initialized = True return True else: logger.error(f"SDK initialization failed with code: {result}") return False - + except Exception as e: logger.error(f"SDK initialization failed: {e}") return False diff --git a/usda_vision_system/core/__pycache__/config.cpython-311.pyc b/usda_vision_system/core/__pycache__/config.cpython-311.pyc index d9b3a97..2770314 100644 Binary files a/usda_vision_system/core/__pycache__/config.cpython-311.pyc and b/usda_vision_system/core/__pycache__/config.cpython-311.pyc differ diff --git a/usda_vision_system/core/config.py b/usda_vision_system/core/config.py index 370e0e3..bbde668 100644 --- a/usda_vision_system/core/config.py +++ b/usda_vision_system/core/config.py @@ -16,23 +16,22 @@ from pathlib import Path @dataclass class MQTTConfig: """MQTT broker configuration""" + broker_host: str = "192.168.1.110" broker_port: int = 1883 username: Optional[str] = None password: Optional[str] = None - topics: Dict[str, str] = None - + topics: Optional[Dict[str, str]] = None + def __post_init__(self): if self.topics is None: - self.topics = { - "vibratory_conveyor": "vision/vibratory_conveyor/state", - "blower_separator": "vision/blower_separator/state" - } + self.topics = {"vibratory_conveyor": "vision/vibratory_conveyor/state", "blower_separator": "vision/blower_separator/state"} @dataclass class CameraConfig: """Individual camera configuration""" + name: str machine_topic: str # Which MQTT topic triggers this camera storage_path: str @@ -43,42 +42,44 @@ class CameraConfig: # Image Quality Settings sharpness: int = 100 # 0-200, default 100 (no sharpening) - contrast: int = 100 # 0-200, default 100 (normal contrast) - saturation: int = 100 # 0-200, default 100 (normal saturation, color cameras only) - gamma: int = 100 # 0-300, default 100 (normal gamma) + contrast: int = 100 # 0-200, default 100 (normal contrast) + saturation: int = 100 # 0-200, default 100 (normal saturation, color cameras only) + gamma: int = 100 # 0-300, default 100 (normal gamma) # Noise Reduction noise_filter_enabled: bool = True # Enable basic noise filtering - denoise_3d_enabled: bool = False # Enable advanced 3D denoising (may reduce FPS) + denoise_3d_enabled: bool = False # Enable advanced 3D denoising (may reduce FPS) # Color Settings (for color cameras) - auto_white_balance: bool = True # Enable automatic white balance + auto_white_balance: bool = True # Enable automatic white balance color_temperature_preset: int = 0 # 0=auto, 1=daylight, 2=fluorescent, etc. # Advanced Settings anti_flicker_enabled: bool = True # Reduce artificial lighting flicker - light_frequency: int = 1 # 0=50Hz, 1=60Hz (match local power frequency) + light_frequency: int = 1 # 0=50Hz, 1=60Hz (match local power frequency) # Bit Depth & Format - bit_depth: int = 8 # 8, 10, 12, or 16 bits per channel + bit_depth: int = 8 # 8, 10, 12, or 16 bits per channel # HDR Settings - hdr_enabled: bool = False # Enable High Dynamic Range - hdr_gain_mode: int = 0 # HDR processing mode + hdr_enabled: bool = False # Enable High Dynamic Range + hdr_gain_mode: int = 0 # HDR processing mode @dataclass class StorageConfig: """Storage configuration""" + base_path: str = "/storage" max_file_size_mb: int = 1000 # Max size per video file max_recording_duration_minutes: int = 60 # Max recording duration cleanup_older_than_days: int = 30 # Auto cleanup old files - - + + @dataclass class SystemConfig: """System-wide configuration""" + camera_check_interval_seconds: int = 2 log_level: str = "INFO" log_file: str = "usda_vision_system.log" @@ -90,60 +91,57 @@ class SystemConfig: class Config: """Main configuration manager""" - + def __init__(self, config_file: Optional[str] = None): self.config_file = config_file or "config.json" self.logger = logging.getLogger(__name__) - + # Default configurations self.mqtt = MQTTConfig() self.storage = StorageConfig() self.system = SystemConfig() - + # Camera configurations - will be populated from config file or defaults self.cameras: List[CameraConfig] = [] - + # Load configuration self.load_config() - + # Ensure storage directories exist self._ensure_storage_directories() - + def load_config(self) -> None: """Load configuration from file""" config_path = Path(self.config_file) - + if config_path.exists(): try: - with open(config_path, 'r') as f: + with open(config_path, "r") as f: config_data = json.load(f) - + # Load MQTT config - if 'mqtt' in config_data: - mqtt_data = config_data['mqtt'] + if "mqtt" in config_data: + mqtt_data = config_data["mqtt"] self.mqtt = MQTTConfig(**mqtt_data) - + # Load storage config - if 'storage' in config_data: - storage_data = config_data['storage'] + if "storage" in config_data: + storage_data = config_data["storage"] self.storage = StorageConfig(**storage_data) - + # Load system config - if 'system' in config_data: - system_data = config_data['system'] + if "system" in config_data: + system_data = config_data["system"] self.system = SystemConfig(**system_data) - + # Load camera configs - if 'cameras' in config_data: - self.cameras = [ - CameraConfig(**cam_data) - for cam_data in config_data['cameras'] - ] + if "cameras" in config_data: + self.cameras = [CameraConfig(**cam_data) for cam_data in config_data["cameras"]] else: self._create_default_camera_configs() - + self.logger.info(f"Configuration loaded from {config_path}") - + except Exception as e: self.logger.error(f"Error loading config from {config_path}: {e}") self._create_default_camera_configs() @@ -151,66 +149,50 @@ class Config: self.logger.info(f"Config file {config_path} not found, using defaults") self._create_default_camera_configs() self.save_config() # Save default config - + def _create_default_camera_configs(self) -> None: """Create default camera configurations""" - self.cameras = [ - CameraConfig( - name="camera1", - machine_topic="vibratory_conveyor", - storage_path=os.path.join(self.storage.base_path, "camera1") - ), - CameraConfig( - name="camera2", - machine_topic="blower_separator", - storage_path=os.path.join(self.storage.base_path, "camera2") - ) - ] - + self.cameras = [CameraConfig(name="camera1", machine_topic="vibratory_conveyor", storage_path=os.path.join(self.storage.base_path, "camera1")), CameraConfig(name="camera2", machine_topic="blower_separator", storage_path=os.path.join(self.storage.base_path, "camera2"))] + def save_config(self) -> None: """Save current configuration to file""" - config_data = { - 'mqtt': asdict(self.mqtt), - 'storage': asdict(self.storage), - 'system': asdict(self.system), - 'cameras': [asdict(cam) for cam in self.cameras] - } - + config_data = {"mqtt": asdict(self.mqtt), "storage": asdict(self.storage), "system": asdict(self.system), "cameras": [asdict(cam) for cam in self.cameras]} + try: - with open(self.config_file, 'w') as f: + with open(self.config_file, "w") as f: json.dump(config_data, f, indent=2) self.logger.info(f"Configuration saved to {self.config_file}") except Exception as e: self.logger.error(f"Error saving config to {self.config_file}: {e}") - + def _ensure_storage_directories(self) -> None: """Ensure all storage directories exist""" try: # Create base storage directory Path(self.storage.base_path).mkdir(parents=True, exist_ok=True) - + # Create camera-specific directories for camera in self.cameras: Path(camera.storage_path).mkdir(parents=True, exist_ok=True) - + self.logger.info("Storage directories verified/created") except Exception as e: self.logger.error(f"Error creating storage directories: {e}") - + def get_camera_by_topic(self, topic: str) -> Optional[CameraConfig]: """Get camera configuration by MQTT topic""" for camera in self.cameras: if camera.machine_topic == topic: return camera return None - + def get_camera_by_name(self, name: str) -> Optional[CameraConfig]: """Get camera configuration by name""" for camera in self.cameras: if camera.name == name: return camera return None - + def update_camera_config(self, name: str, **kwargs) -> bool: """Update camera configuration""" camera = self.get_camera_by_name(name) @@ -221,12 +203,7 @@ class Config: self.save_config() return True return False - + def to_dict(self) -> Dict[str, Any]: """Convert configuration to dictionary""" - return { - 'mqtt': asdict(self.mqtt), - 'storage': asdict(self.storage), - 'system': asdict(self.system), - 'cameras': [asdict(cam) for cam in self.cameras] - } + return {"mqtt": asdict(self.mqtt), "storage": asdict(self.storage), "system": asdict(self.system), "cameras": [asdict(cam) for cam in self.cameras]}