Change video storage directory from /storage to /mnt/nfs_share

- Update StorageConfig default base_path in core/config.py
- Update base_path and camera storage_paths in config.json and config.compose.json
- Update Docker Compose volume mounts to use /mnt/nfs_share
- Update start_system.sh to create /mnt/nfs_share directory
- Update convert_avi_to_mp4.sh to use new NFS path
- Update all documentation files to reflect new storage paths
- Videos now stored on NFS server at 192.168.1.249:/mnt/nfs_share/
This commit is contained in:
salirezav
2025-10-14 16:28:00 -04:00
parent e675423258
commit 98c93f9e0e
17 changed files with 48 additions and 50 deletions

View File

@@ -142,9 +142,9 @@ Ensure the `camera_sdk` directory contains the mvsdk library for your GigE camer
### 4. Configure Storage Directory ### 4. Configure Storage Directory
```bash ```bash
# Create storage directory (adjust path as needed) # Create storage directory (adjust path as needed)
mkdir -p ./storage mkdir -p ./mnt/nfs_share
# Or for system-wide storage: # Or for system-wide storage:
# sudo mkdir -p /storage && sudo chown $USER:$USER /storage # sudo mkdir -p /mnt/nfs_share && sudo chown $USER:$USER /mnt/nfs_share
``` ```
### 5. Setup Time Synchronization (Recommended) ### 5. Setup Time Synchronization (Recommended)
@@ -169,7 +169,7 @@ Edit `config.json` to match your setup:
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "machine1", "machine_topic": "machine1",
"storage_path": "./storage/camera1", "storage_path": "./mnt/nfs_share/camera1",
"enabled": true "enabled": true
} }
] ]
@@ -201,7 +201,7 @@ Edit `config.json` to match your setup:
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "./storage/camera1", "storage_path": "./mnt/nfs_share/camera1",
"exposure_ms": 1.0, "exposure_ms": 1.0,
"gain": 3.5, "gain": 3.5,
"target_fps": 3.0, "target_fps": 3.0,

View File

@@ -10,7 +10,7 @@
} }
}, },
"storage": { "storage": {
"base_path": "/storage", "base_path": "/mnt/nfs_share",
"max_file_size_mb": 1000, "max_file_size_mb": 1000,
"max_recording_duration_minutes": 60, "max_recording_duration_minutes": 60,
"cleanup_older_than_days": 30 "cleanup_older_than_days": 30
@@ -29,7 +29,7 @@
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,
@@ -60,7 +60,7 @@
{ {
"name": "camera2", "name": "camera2",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera2", "storage_path": "/mnt/nfs_share/camera2",
"exposure_ms": 0.2, "exposure_ms": 0.2,
"gain": 2.0, "gain": 2.0,
"target_fps": 0, "target_fps": 0,

View File

@@ -10,7 +10,7 @@
} }
}, },
"storage": { "storage": {
"base_path": "/storage", "base_path": "/mnt/nfs_share",
"max_file_size_mb": 1000, "max_file_size_mb": 1000,
"max_recording_duration_minutes": 60, "max_recording_duration_minutes": 60,
"cleanup_older_than_days": 30 "cleanup_older_than_days": 30
@@ -29,7 +29,7 @@
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,
@@ -60,7 +60,7 @@
{ {
"name": "camera2", "name": "camera2",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera2", "storage_path": "/mnt/nfs_share/camera2",
"exposure_ms": 0.2, "exposure_ms": 0.2,
"gain": 2.0, "gain": 2.0,
"target_fps": 0, "target_fps": 0,

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Script to convert AVI files to MP4 using H.264 codec # Script to convert AVI files to MP4 using H.264 codec
# Converts files in /storage directory and saves them in the same location # Converts files in /mnt/nfs_share directory and saves them in the same location
# Colors for output # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
@@ -54,19 +54,19 @@ if ! command -v ffmpeg &> /dev/null; then
exit 1 exit 1
fi fi
# Check if /storage directory exists # Check if /mnt/nfs_share directory exists
if [ ! -d "/storage" ]; then if [ ! -d "/mnt/nfs_share" ]; then
print_error "/storage directory does not exist." print_error "/mnt/nfs_share directory does not exist."
exit 1 exit 1
fi fi
# Check if we have read/write permissions to /storage # Check if we have read/write permissions to /mnt/nfs_share
if [ ! -r "/storage" ] || [ ! -w "/storage" ]; then if [ ! -r "/mnt/nfs_share" ] || [ ! -w "/mnt/nfs_share" ]; then
print_error "No read/write permissions for /storage directory." print_error "No read/write permissions for /mnt/nfs_share directory."
exit 1 exit 1
fi fi
print_status "Starting AVI to MP4 conversion in /storage directory..." print_status "Starting AVI to MP4 conversion in /mnt/nfs_share directory..."
# Counter variables # Counter variables
total_files=0 total_files=0
@@ -74,7 +74,7 @@ converted_files=0
skipped_files=0 skipped_files=0
failed_files=0 failed_files=0
# Find all AVI files in /storage directory (including subdirectories) # Find all AVI files in /mnt/nfs_share directory (including subdirectories)
while IFS= read -r -d '' avi_file; do while IFS= read -r -d '' avi_file; do
total_files=$((total_files + 1)) total_files=$((total_files + 1))
@@ -163,7 +163,7 @@ while IFS= read -r -d '' avi_file; do
echo # Add blank line between files echo # Add blank line between files
done < <(find /storage -name "*.avi" -type f -print0) done < <(find /mnt/nfs_share -name "*.avi" -type f -print0)
# Print summary # Print summary
echo echo
@@ -174,7 +174,7 @@ echo "Skipped (MP4 exists): $skipped_files"
echo "Failed conversions: $failed_files" echo "Failed conversions: $failed_files"
if [ $total_files -eq 0 ]; then if [ $total_files -eq 0 ]; then
print_warning "No AVI files found in /storage directory." print_warning "No AVI files found in /mnt/nfs_share directory."
elif [ $failed_files -eq 0 ] && [ $converted_files -gt 0 ]; then elif [ $failed_files -eq 0 ] && [ $converted_files -gt 0 ]; then
print_success "All conversions completed successfully!" print_success "All conversions completed successfully!"
elif [ $failed_files -gt 0 ]; then elif [ $failed_files -gt 0 ]; then

View File

@@ -196,7 +196,7 @@ GET /cameras/{camera_name}/config
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,
@@ -306,7 +306,7 @@ GET /storage/stats
**Response**: `StorageStatsResponse` **Response**: `StorageStatsResponse`
```json ```json
{ {
"base_path": "/storage", "base_path": "/mnt/nfs_share",
"total_files": 150, "total_files": 150,
"total_size_bytes": 5368709120, "total_size_bytes": 5368709120,
"cameras": { "cameras": {

View File

@@ -20,7 +20,7 @@ This document shows the exact current configuration structure of the USDA Vision
} }
}, },
"storage": { "storage": {
"base_path": "/storage", "base_path": "/mnt/nfs_share",
"max_file_size_mb": 1000, "max_file_size_mb": 1000,
"max_recording_duration_minutes": 60, "max_recording_duration_minutes": 60,
"cleanup_older_than_days": 30 "cleanup_older_than_days": 30
@@ -39,7 +39,7 @@ This document shows the exact current configuration structure of the USDA Vision
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,
@@ -70,7 +70,7 @@ This document shows the exact current configuration structure of the USDA Vision
{ {
"name": "camera2", "name": "camera2",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera2", "storage_path": "/mnt/nfs_share/camera2",
"exposure_ms": 0.2, "exposure_ms": 0.2,
"gain": 2.0, "gain": 2.0,
"target_fps": 0, "target_fps": 0,
@@ -121,7 +121,7 @@ This document shows the exact current configuration structure of the USDA Vision
### Storage Settings ### Storage Settings
| Field | Value | Description | | Field | Value | Description |
|-------|-------|-------------| |-------|-------|-------------|
| `base_path` | `"/storage"` | Root storage directory | | `base_path` | `"/mnt/nfs_share"` | Root storage directory |
| `max_file_size_mb` | `1000` | Maximum file size (1GB) | | `max_file_size_mb` | `1000` | Maximum file size (1GB) |
| `max_recording_duration_minutes` | `60` | Maximum recording duration | | `max_recording_duration_minutes` | `60` | Maximum recording duration |
| `cleanup_older_than_days` | `30` | Auto-cleanup threshold | | `cleanup_older_than_days` | `30` | Auto-cleanup threshold |
@@ -144,7 +144,7 @@ This document shows the exact current configuration structure of the USDA Vision
| **Basic Settings** | | | | **Basic Settings** | | |
| `name` | `"camera1"` | Camera identifier | | `name` | `"camera1"` | Camera identifier |
| `machine_topic` | `"blower_separator"` | MQTT topic to monitor | | `machine_topic` | `"blower_separator"` | MQTT topic to monitor |
| `storage_path` | `"/storage/camera1"` | Video storage location | | `storage_path` | `"/mnt/nfs_share/camera1"` | Video storage location |
| `exposure_ms` | `0.3` | Exposure time (milliseconds) | | `exposure_ms` | `0.3` | Exposure time (milliseconds) |
| `gain` | `4.0` | Camera gain multiplier | | `gain` | `4.0` | Camera gain multiplier |
| `target_fps` | `0` | Target FPS (0 = unlimited) | | `target_fps` | `0` | Target FPS (0 = unlimited) |
@@ -176,7 +176,7 @@ This document shows the exact current configuration structure of the USDA Vision
|---------|-------|--------------------------| |---------|-------|--------------------------|
| `name` | `"camera2"` | Different identifier | | `name` | `"camera2"` | Different identifier |
| `machine_topic` | `"vibratory_conveyor"` | Different MQTT topic | | `machine_topic` | `"vibratory_conveyor"` | Different MQTT topic |
| `storage_path` | `"/storage/camera2"` | Different storage path | | `storage_path` | `"/mnt/nfs_share/camera2"` | Different storage path |
| `exposure_ms` | `0.2` | Faster exposure (0.2 vs 0.3) | | `exposure_ms` | `0.2` | Faster exposure (0.2 vs 0.3) |
| `gain` | `2.0` | Lower gain (2.0 vs 4.0) | | `gain` | `2.0` | Lower gain (2.0 vs 4.0) |
| `wb_red_gain` | `1.01` | Different red balance (1.01 vs 0.94) | | `wb_red_gain` | `1.01` | Different red balance (1.01 vs 0.94) |

View File

@@ -78,7 +78,7 @@ const videoUrl = `/api/videos/${videoId}/stream`;
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,

View File

@@ -100,7 +100,7 @@ const CameraConfigForm = () => {
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,

View File

@@ -41,7 +41,7 @@ GET /cameras/{camera_name}/config
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 0.3, "exposure_ms": 0.3,
"gain": 4.0, "gain": 4.0,
"target_fps": 0, "target_fps": 0,

View File

@@ -65,7 +65,7 @@ The current config.json for camera1 includes:
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "blower_separator", "machine_topic": "blower_separator",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 1.0, "exposure_ms": 1.0,
"gain": 3.5, "gain": 3.5,
"target_fps": 0, "target_fps": 0,

View File

@@ -61,7 +61,7 @@ The current config.json for camera2 includes:
{ {
"name": "camera2", "name": "camera2",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera2", "storage_path": "/mnt/nfs_share/camera2",
"exposure_ms": 0.5, "exposure_ms": 0.5,
"gain": 0.3, "gain": 0.3,
"target_fps": 0, "target_fps": 0,

View File

@@ -57,8 +57,8 @@ This system integrates MQTT machine monitoring with automated video recording fr
3. **Setup Storage Directory**: 3. **Setup Storage Directory**:
```bash ```bash
sudo mkdir -p /storage sudo mkdir -p /mnt/nfs_share
sudo chown $USER:$USER /storage sudo chown $USER:$USER /mnt/nfs_share
``` ```
## Configuration ## Configuration
@@ -79,7 +79,7 @@ Edit `config.json` to configure your system:
{ {
"name": "camera1", "name": "camera1",
"machine_topic": "vibratory_conveyor", "machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1", "storage_path": "/mnt/nfs_share/camera1",
"exposure_ms": 1.0, "exposure_ms": 1.0,
"gain": 3.5, "gain": 3.5,
"target_fps": 3.0, "target_fps": 3.0,
@@ -117,7 +117,7 @@ The system provides a REST API on port 8000:
- `GET /machines` - All machine states - `GET /machines` - All machine states
- `POST /cameras/{name}/start-recording` - Manual recording start - `POST /cameras/{name}/start-recording` - Manual recording start
- `POST /cameras/{name}/stop-recording` - Manual recording stop - `POST /cameras/{name}/stop-recording` - Manual recording stop
- `GET /storage/stats` - Storage statistics - `GET /mnt/nfs_share/stats` - Storage statistics
- `WebSocket /ws` - Real-time updates - `WebSocket /ws` - Real-time updates
### Dashboard Integration ### Dashboard Integration
@@ -131,7 +131,7 @@ The system is designed to integrate with your existing React + Vite + Tailwind +
## File Organization ## File Organization
``` ```
/storage/ /mnt/nfs_share/
├── camera1/ ├── camera1/
│ ├── camera1_recording_20250726_143022.avi │ ├── camera1_recording_20250726_143022.avi
│ └── camera1_recording_20250726_143155.avi │ └── camera1_recording_20250726_143155.avi

View File

@@ -29,11 +29,11 @@ if [ ! -f "config.json" ]; then
fi fi
# Check storage directory # Check storage directory
if [ ! -d "/storage" ]; then if [ ! -d "/mnt/nfs_share" ]; then
echo "📁 Creating storage directory..." echo "📁 Creating storage directory..."
sudo mkdir -p /storage sudo mkdir -p /mnt/nfs_share
sudo chown $USER:$USER /storage sudo chown $USER:$USER /mnt/nfs_share
echo "✅ Storage directory created at /storage" echo "✅ Storage directory created at /mnt/nfs_share"
fi fi
# Check time synchronization # Check time synchronization

View File

@@ -85,7 +85,7 @@ class CameraConfig:
class StorageConfig: class StorageConfig:
"""Storage configuration""" """Storage configuration"""
base_path: str = "/storage" base_path: str = "/mnt/nfs_share"
max_file_size_mb: int = 1000 # Max size per video file max_file_size_mb: int = 1000 # Max size per video file
max_recording_duration_minutes: int = 60 # Max recording duration max_recording_duration_minutes: int = 60 # Max recording duration
cleanup_older_than_days: int = 30 # Auto cleanup old files cleanup_older_than_days: int = 30 # Auto cleanup old files

View File

@@ -6,7 +6,7 @@ services:
working_dir: /app working_dir: /app
volumes: volumes:
- ./camera-management-api:/app - ./camera-management-api:/app
- /storage:/storage - /mnt/nfs_share:/mnt/nfs_share
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
environment: environment:

View File

@@ -6,7 +6,7 @@ services:
working_dir: /app working_dir: /app
volumes: volumes:
- ./camera-management-api:/app - ./camera-management-api:/app
- /storage:/storage - /mnt/nfs_share:/mnt/nfs_share
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
environment: environment:
@@ -62,5 +62,3 @@ services:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
ports: ports:
- "8080:8080" - "8080:8080"

View File

@@ -121,7 +121,7 @@ This document shows the exact current configuration structure of the USDA Vision
### Storage Settings ### Storage Settings
| Field | Value | Description | | Field | Value | Description |
|-------|-------|-------------| |-------|-------|-------------|
| `base_path` | `"/storage"` | Root storage directory | | `base_path` | `"/mnt/nfs_share"` | Root storage directory |
| `max_file_size_mb` | `1000` | Maximum file size (1GB) | | `max_file_size_mb` | `1000` | Maximum file size (1GB) |
| `max_recording_duration_minutes` | `60` | Maximum recording duration | | `max_recording_duration_minutes` | `60` | Maximum recording duration |
| `cleanup_older_than_days` | `30` | Auto-cleanup threshold | | `cleanup_older_than_days` | `30` | Auto-cleanup threshold |
@@ -144,7 +144,7 @@ This document shows the exact current configuration structure of the USDA Vision
| **Basic Settings** | | | | **Basic Settings** | | |
| `name` | `"camera1"` | Camera identifier | | `name` | `"camera1"` | Camera identifier |
| `machine_topic` | `"blower_separator"` | MQTT topic to monitor | | `machine_topic` | `"blower_separator"` | MQTT topic to monitor |
| `storage_path` | `"/storage/camera1"` | Video storage location | | `storage_path` | `"/mnt/nfs_share/camera1"` | Video storage location |
| `exposure_ms` | `0.3` | Exposure time (milliseconds) | | `exposure_ms` | `0.3` | Exposure time (milliseconds) |
| `gain` | `4.0` | Camera gain multiplier | | `gain` | `4.0` | Camera gain multiplier |
| `target_fps` | `0` | Target FPS (0 = unlimited) | | `target_fps` | `0` | Target FPS (0 = unlimited) |