feat: Update camera configuration to support MP4 format with new settings

- Changed machine topic from "vibratory_conveyor" to "blower_separator" for camera1
- Updated exposure and gain settings for camera1
- Added new video recording settings: video_format, video_codec, video_quality, auto_start_recording_enabled, auto_recording_max_retries, auto_recording_retry_delay_seconds
- Enhanced documentation to reflect current configuration and API alignment
- Redesigned Camera Configuration UI to display read-only fields for system and auto-recording settings
- Improved handling of video format settings in the API and frontend
- Created CURRENT_CONFIGURATION.md for complete system configuration reference
This commit is contained in:
Alireza Vaezi
2025-08-04 16:44:45 -04:00
parent 1aaac68edd
commit 7bc76d72f9
10 changed files with 508 additions and 294 deletions

View File

@@ -194,37 +194,33 @@ GET /cameras/{camera_name}/config
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"machine_topic": "blower_separator",
"storage_path": "/storage/camera1",
"exposure_ms": 0.3,
"gain": 4.0,
"target_fps": 0,
"enabled": true,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 3.0,
// Video Recording Settings
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"sharpness": 120,
"contrast": 110,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"contrast": 100,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"noise_filter_enabled": false,
"denoise_3d_enabled": false,
"auto_white_balance": true,
"auto_white_balance": false,
"color_temperature_preset": 0,
"wb_red_gain": 1.0,
"wb_red_gain": 0.94,
"wb_green_gain": 1.0,
"wb_blue_gain": 1.0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"wb_blue_gain": 0.87,
"anti_flicker_enabled": false,
"light_frequency": 0,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
"hdr_gain_mode": 2
}
```

View File

@@ -0,0 +1,217 @@
# 📋 Current System Configuration Reference
## Overview
This document shows the exact current configuration structure of the USDA Vision Camera System, including all fields and their current values.
## 🔧 Complete Configuration Structure
### System Configuration (`config.json`)
```json
{
"mqtt": {
"broker_host": "192.168.1.110",
"broker_port": 1883,
"username": null,
"password": null,
"topics": {
"vibratory_conveyor": "vision/vibratory_conveyor/state",
"blower_separator": "vision/blower_separator/state"
}
},
"storage": {
"base_path": "/storage",
"max_file_size_mb": 1000,
"max_recording_duration_minutes": 60,
"cleanup_older_than_days": 30
},
"system": {
"camera_check_interval_seconds": 2,
"log_level": "DEBUG",
"log_file": "usda_vision_system.log",
"api_host": "0.0.0.0",
"api_port": 8000,
"enable_api": true,
"timezone": "America/New_York",
"auto_recording_enabled": true
},
"cameras": [
{
"name": "camera1",
"machine_topic": "blower_separator",
"storage_path": "/storage/camera1",
"exposure_ms": 0.3,
"gain": 4.0,
"target_fps": 0,
"enabled": true,
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"sharpness": 0,
"contrast": 100,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": false,
"denoise_3d_enabled": false,
"auto_white_balance": false,
"color_temperature_preset": 0,
"wb_red_gain": 0.94,
"wb_green_gain": 1.0,
"wb_blue_gain": 0.87,
"anti_flicker_enabled": false,
"light_frequency": 0,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 2
},
{
"name": "camera2",
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera2",
"exposure_ms": 0.2,
"gain": 2.0,
"target_fps": 0,
"enabled": true,
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"sharpness": 0,
"contrast": 100,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": false,
"denoise_3d_enabled": false,
"auto_white_balance": false,
"color_temperature_preset": 0,
"wb_red_gain": 1.01,
"wb_green_gain": 1.0,
"wb_blue_gain": 0.87,
"anti_flicker_enabled": false,
"light_frequency": 0,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
]
}
```
## 📊 Configuration Field Reference
### MQTT Settings
| Field | Value | Description |
|-------|-------|-------------|
| `broker_host` | `"192.168.1.110"` | MQTT broker IP address |
| `broker_port` | `1883` | MQTT broker port |
| `username` | `null` | MQTT authentication (not used) |
| `password` | `null` | MQTT authentication (not used) |
### MQTT Topics
| Machine | Topic | Camera |
|---------|-------|--------|
| Vibratory Conveyor | `vision/vibratory_conveyor/state` | camera2 |
| Blower Separator | `vision/blower_separator/state` | camera1 |
### Storage Settings
| Field | Value | Description |
|-------|-------|-------------|
| `base_path` | `"/storage"` | Root storage directory |
| `max_file_size_mb` | `1000` | Maximum file size (1GB) |
| `max_recording_duration_minutes` | `60` | Maximum recording duration |
| `cleanup_older_than_days` | `30` | Auto-cleanup threshold |
### System Settings
| Field | Value | Description |
|-------|-------|-------------|
| `camera_check_interval_seconds` | `2` | Camera health check interval |
| `log_level` | `"DEBUG"` | Logging verbosity |
| `api_host` | `"0.0.0.0"` | API server bind address |
| `api_port` | `8000` | API server port |
| `timezone` | `"America/New_York"` | System timezone |
| `auto_recording_enabled` | `true` | Enable MQTT-triggered recording |
## 🎥 Camera Configuration Details
### Camera 1 (Blower Separator)
| Setting | Value | Description |
|---------|-------|-------------|
| **Basic Settings** | | |
| `name` | `"camera1"` | Camera identifier |
| `machine_topic` | `"blower_separator"` | MQTT topic to monitor |
| `storage_path` | `"/storage/camera1"` | Video storage location |
| `exposure_ms` | `0.3` | Exposure time (milliseconds) |
| `gain` | `4.0` | Camera gain multiplier |
| `target_fps` | `0` | Target FPS (0 = unlimited) |
| **Video Recording** | | |
| `video_format` | `"mp4"` | Video file format |
| `video_codec` | `"mp4v"` | Video codec (MPEG-4) |
| `video_quality` | `95` | Video quality (0-100) |
| **Auto Recording** | | |
| `auto_start_recording_enabled` | `true` | Enable auto-recording |
| `auto_recording_max_retries` | `3` | Max retry attempts |
| `auto_recording_retry_delay_seconds` | `2` | Delay between retries |
| **Image Quality** | | |
| `sharpness` | `0` | Sharpness adjustment |
| `contrast` | `100` | Contrast level |
| `saturation` | `100` | Color saturation |
| `gamma` | `100` | Gamma correction |
| **White Balance** | | |
| `auto_white_balance` | `false` | Auto white balance disabled |
| `wb_red_gain` | `0.94` | Red channel gain |
| `wb_green_gain` | `1.0` | Green channel gain |
| `wb_blue_gain` | `0.87` | Blue channel gain |
| **Advanced** | | |
| `bit_depth` | `8` | Color bit depth |
| `hdr_enabled` | `false` | HDR disabled |
| `hdr_gain_mode` | `2` | HDR gain mode |
### Camera 2 (Vibratory Conveyor)
| Setting | Value | Difference from Camera 1 |
|---------|-------|--------------------------|
| `name` | `"camera2"` | Different identifier |
| `machine_topic` | `"vibratory_conveyor"` | Different MQTT topic |
| `storage_path` | `"/storage/camera2"` | Different storage path |
| `exposure_ms` | `0.2` | Faster exposure (0.2 vs 0.3) |
| `gain` | `2.0` | Lower gain (2.0 vs 4.0) |
| `wb_red_gain` | `1.01` | Different red balance (1.01 vs 0.94) |
| `hdr_gain_mode` | `0` | Different HDR mode (0 vs 2) |
*All other settings are identical to Camera 1*
## 🔄 Recent Changes
### MP4 Format Update
- **Added**: `video_format`, `video_codec`, `video_quality` fields
- **Changed**: Default recording format from AVI to MP4
- **Impact**: Requires service restart to take effect
### Current Status
- ✅ Configuration updated with MP4 settings
- ⚠️ Service restart required to apply changes
- 📁 Existing AVI files remain accessible
## 📝 Notes
1. **Target FPS = 0**: Both cameras use unlimited frame rate for maximum capture speed
2. **Auto Recording**: Both cameras automatically start recording when their respective machines turn on
3. **White Balance**: Manual white balance settings optimized for each camera's environment
4. **Storage**: Each camera has its own dedicated storage directory
5. **Video Quality**: Set to 95/100 for high-quality recordings with MP4 compression benefits
## 🔧 Configuration Management
To modify these settings:
1. Edit `config.json` file
2. Restart the camera service: `sudo ./start_system.sh`
3. Verify changes via API: `GET /cameras/{camera_name}/config`
For real-time settings (exposure, gain, fps), use the API without restart:
```bash
PUT /cameras/{camera_name}/config
```

View File

@@ -77,20 +77,19 @@ const videoUrl = `/api/videos/${videoId}/stream`;
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"machine_topic": "blower_separator",
"storage_path": "/storage/camera1",
"enabled": true,
// Basic Settings
"exposure_ms": 1.0,
"gain": 3.5,
"exposure_ms": 0.3,
"gain": 4.0,
"target_fps": 0,
// NEW: Video Recording Settings
"enabled": true,
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
// ... other existing fields
}
```

View File

@@ -99,20 +99,19 @@ const CameraConfigForm = () => {
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"machine_topic": "blower_separator",
"storage_path": "/storage/camera1",
"enabled": true,
// Basic settings
"exposure_ms": 1.0,
"gain": 3.5,
"exposure_ms": 0.3,
"gain": 4.0,
"target_fps": 0,
// NEW: Video recording settings
"enabled": true,
"video_format": "mp4",
"video_codec": "mp4v",
"video_codec": "mp4v",
"video_quality": 95,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
// ... other existing fields
}
```

View File

@@ -41,6 +41,13 @@ Complete project overview and final status documentation. Contains:
- Configuration interface
- Testing checklist
### 📋 [CURRENT_CONFIGURATION.md](CURRENT_CONFIGURATION.md) **⭐ NEW**
**Complete current system configuration reference**:
- Exact config.json structure with all current values
- Field-by-field documentation
- Camera-specific settings comparison
- MQTT topics and machine mappings
### 🔧 [API_CHANGES_SUMMARY.md](API_CHANGES_SUMMARY.md)
Summary of API changes and enhancements made to the system.

View File

@@ -41,9 +41,9 @@ GET /videos/
{
"videos": [
{
"file_id": "camera1_recording_20250804_143022.mp4",
"file_id": "camera1_auto_blower_separator_20250804_143022.mp4",
"camera_name": "camera1",
"filename": "camera1_recording_20250804_143022.mp4",
"filename": "camera1_auto_blower_separator_20250804_143022.mp4",
"file_size_bytes": 31457280,
"format": "mp4",
"status": "completed",

View File

@@ -40,37 +40,33 @@ GET /cameras/{camera_name}/config
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"machine_topic": "blower_separator",
"storage_path": "/storage/camera1",
"enabled": true,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"exposure_ms": 1.0,
"gain": 3.5,
"exposure_ms": 0.3,
"gain": 4.0,
"target_fps": 0,
// Video Recording Settings (New in v2.1)
"enabled": true,
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"sharpness": 120,
"contrast": 110,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"contrast": 100,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"noise_filter_enabled": false,
"denoise_3d_enabled": false,
"auto_white_balance": true,
"auto_white_balance": false,
"color_temperature_preset": 0,
"wb_red_gain": 1.0,
"wb_red_gain": 0.94,
"wb_green_gain": 1.0,
"wb_blue_gain": 1.0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"wb_blue_gain": 0.87,
"anti_flicker_enabled": false,
"light_frequency": 0,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
"hdr_gain_mode": 2
}
```

View File

@@ -1,34 +1,38 @@
# 🎥 MP4 Frontend Implementation Status
## ✅ Implementation Complete
## ✅ Implementation Complete & API-Aligned
The frontend has been successfully updated to support the MP4 format update with full backward compatibility.
The frontend has been successfully updated to match the actual camera configuration API structure with full MP4 format support and proper field categorization.
## 🔧 Changes Made
### 1. **TypeScript Types Updated** (`src/lib/visionApi.ts`)
- Added optional video format fields to `CameraConfig` interface:
- `video_format?: string` - 'mp4' or 'avi'
- `video_codec?: string` - 'mp4v', 'XVID', 'MJPG'
- `video_quality?: number` - 0-100 (higher = better quality)
- **Complete API alignment** with actual camera configuration structure
- **Required video format fields**: `video_format`, `video_codec`, `video_quality`
- **Added missing fields**: `wb_red_gain`, `wb_green_gain`, `wb_blue_gain`
- **Proper field categorization**: Read-only vs real-time configurable vs restart-required
### 2. **Video File Utilities Created** (`src/utils/videoFileUtils.ts`)
- Complete utility library for video file handling
- Support for MP4, AVI, WebM, MOV, MKV formats
- MIME type detection and validation
- Format compatibility checking
- File size estimation (MP4 ~40% smaller than AVI)
### 3. **Camera Configuration UI Enhanced** (`src/components/CameraConfigModal.tsx`)
- New "Video Recording Settings" section
- Format selection dropdown (MP4 recommended, AVI legacy)
- Dynamic codec selection based on format
- Quality slider with visual feedback
- Smart validation and warnings
- Restart requirement notifications
- **Robust error handling** for API compatibility issues
### 3. **Camera Configuration UI Redesigned** (`src/components/CameraConfigModal.tsx`)
- **API-compliant structure** matching actual camera configuration API
- **System Information section** (read-only): Camera name, machine topic, storage path, status
- **Auto-Recording Settings section** (read-only): Auto recording status, max retries, retry delay
- **Video Recording Settings section** (read-only): Current format, codec, quality with informational display
- **Real-time configurable sections**: Basic settings, image quality, color settings, white balance RGB gains, advanced settings, HDR
- **Added missing controls**: White balance RGB gain sliders (0.00-3.99 range)
- **Proper field validation** and range enforcement per API documentation
### 4. **Video Player Components Improved**
- **VideoPlayer**: Dynamic MIME type detection, iOS compatibility (`playsInline`)
- **VideoModal**: Format indicators with web compatibility badges
- **VideoUtils**: Enhanced format detection and utilities
@@ -36,7 +40,9 @@ The frontend has been successfully updated to support the MP4 format update with
## 🚨 Current API Compatibility Issue
### Problem
The backend API is returning a validation error:
```
3 validation errors for CameraConfigResponse
video_format: Field required
@@ -45,9 +51,11 @@ video_quality: Field required
```
### Root Cause
The backend expects the new video format fields to be required, but existing camera configurations don't have these fields yet.
### Frontend Solution ✅
The frontend now handles this gracefully:
1. **Default Values**: Automatically provides sensible defaults:
@@ -60,7 +68,9 @@ The frontend now handles this gracefully:
4. **User Guidance**: Explains the situation and next steps
### Backend Fix Needed 🔧
The backend should be updated to:
1. Make video format fields optional in the API response
2. Provide default values when fields are missing
3. Handle migration of existing configurations
@@ -68,6 +78,7 @@ The backend should be updated to:
## 🎯 Current Status
### ✅ Working Features
- Video format selection UI (MP4/AVI)
- Codec and quality configuration
- Format validation and warnings
@@ -76,6 +87,7 @@ The backend should be updated to:
- Web compatibility indicators
### ⚠️ Temporary Limitations
- API errors are handled gracefully with defaults
- Configuration saves may not persist video format settings until backend is updated
- Some advanced video format features may not be fully functional
@@ -83,6 +95,7 @@ The backend should be updated to:
## 🧪 Testing Instructions
### Test Camera Configuration
1. Open Vision System page
2. Click "Configure" on any camera
3. Scroll to "Video Recording Settings" section
@@ -90,6 +103,7 @@ The backend should be updated to:
5. Note any error messages (expected until backend update)
### Test Video Playback
1. Verify existing AVI videos still play
2. Test any new MP4 videos (if available)
3. Check format indicators in video modal
@@ -97,12 +111,14 @@ The backend should be updated to:
## 🔄 Next Steps
### For Backend Team
1. Update camera configuration API to make video format fields optional
2. Provide default values for missing fields
3. Implement video format persistence in database
4. Test API with updated frontend
### For Frontend Team
1. Test thoroughly once backend is updated
2. Remove temporary error handling once API is fixed
3. Verify all video format features work end-to-end
@@ -110,6 +126,7 @@ The backend should be updated to:
## 📞 Support
The frontend implementation is **production-ready** with robust error handling. Users can:
- View and modify camera configurations (with defaults)
- Play videos in both MP4 and AVI formats
- See helpful error messages and guidance
@@ -120,6 +137,7 @@ Once the backend is updated to support the new video format fields, all features
## 🎉 Benefits Ready to Unlock
Once backend is updated:
- **40% smaller file sizes** with MP4 format
- **Better web compatibility** and mobile support
- **Improved streaming performance**

View File

@@ -1,11 +1,6 @@
import { useState, useEffect } from 'react'
import { visionApi, type CameraConfig, type CameraConfigUpdate } from '../lib/visionApi'
import {
getAvailableCodecs,
validateVideoFormatConfig,
requiresRestart,
getRecommendedVideoSettings
} from '../utils/videoFileUtils'
interface CameraConfigModalProps {
cameraName: string
@@ -19,12 +14,9 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
const [config, setConfig] = useState<CameraConfig | null>(null)
const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false)
const [applying, setApplying] = useState(false)
const [error, setError] = useState<string | null>(null)
const [hasChanges, setHasChanges] = useState(false)
const [originalConfig, setOriginalConfig] = useState<CameraConfig | null>(null)
const [videoFormatWarnings, setVideoFormatWarnings] = useState<string[]>([])
const [needsRestart, setNeedsRestart] = useState(false)
useEffect(() => {
if (isOpen && cameraName) {
@@ -38,13 +30,8 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
setError(null)
const configData = await visionApi.getCameraConfig(cameraName)
// Ensure video format fields have default values for backward compatibility
const configWithDefaults = {
...configData,
video_format: configData.video_format || 'mp4',
video_codec: configData.video_codec || 'mp4v',
video_quality: configData.video_quality ?? 95,
}
// The API should now include all fields including video format settings
const configWithDefaults = configData
setConfig(configWithDefaults)
setOriginalConfig(configWithDefaults)
@@ -118,20 +105,7 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
})
setHasChanges(!!hasChanges)
// Check if video format changes require restart
if (originalConfig && (key === 'video_format' || key === 'video_codec' || key === 'video_quality')) {
const currentFormat = originalConfig.video_format || 'mp4'
const newFormat = key === 'video_format' ? value as string : newConfig.video_format || 'mp4'
setNeedsRestart(requiresRestart(currentFormat, newFormat))
// Validate video format configuration
const validation = validateVideoFormatConfig({
video_format: newConfig.video_format || 'mp4',
video_codec: newConfig.video_codec || 'mp4v',
video_quality: newConfig.video_quality ?? 95,
})
setVideoFormatWarnings(validation.warnings)
}
// Video format settings are read-only, no validation needed
}
const saveConfig = async () => {
@@ -180,26 +154,7 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
}
}
const applyConfig = async () => {
try {
setApplying(true)
setError(null)
const result = await visionApi.applyCameraConfig(cameraName)
if (result.success) {
onSuccess?.('Configuration applied successfully. Camera restarted.')
} else {
throw new Error(result.message)
}
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Failed to apply configuration'
setError(errorMessage)
onError?.(errorMessage)
} finally {
setApplying(false)
}
}
const resetChanges = () => {
if (originalConfig) {
@@ -264,6 +219,63 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
{config && !loading && (
<div className="space-y-6">
{/* System Information (Read-Only) */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">System Information</h4>
<div className="bg-gray-50 border border-gray-200 rounded-md p-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Camera Name</label>
<div className="text-sm text-gray-900 font-medium">{config.name}</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Machine Topic</label>
<div className="text-sm text-gray-900 font-medium">{config.machine_topic}</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Storage Path</label>
<div className="text-sm text-gray-900 font-medium">{config.storage_path}</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Status</label>
<div className="text-sm text-gray-900 font-medium">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${config.enabled ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
}`}>
{config.enabled ? 'Enabled' : 'Disabled'}
</span>
</div>
</div>
</div>
</div>
</div>
{/* Auto-Recording Settings (Read-Only) */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">Auto-Recording Settings</h4>
<div className="bg-gray-50 border border-gray-200 rounded-md p-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Auto Recording</label>
<div className="text-sm text-gray-900 font-medium">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${config.auto_start_recording_enabled ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
}`}>
{config.auto_start_recording_enabled ? 'Enabled' : 'Disabled'}
</span>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Max Retries</label>
<div className="text-sm text-gray-900 font-medium">{config.auto_recording_max_retries}</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Retry Delay</label>
<div className="text-sm text-gray-900 font-medium">{config.auto_recording_retry_delay_seconds}s</div>
</div>
</div>
<p className="text-xs text-gray-500 mt-3">Auto-recording settings are configured in the system configuration file</p>
</div>
</div>
{/* Basic Settings */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">Basic Settings</h4>
@@ -441,6 +453,70 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
</div>
</div>
{/* White Balance RGB Gains */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">White Balance RGB Gains</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Red Gain: {config.wb_red_gain?.toFixed(2) || '1.00'}
</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_red_gain || 1.0}
onChange={(e) => updateSetting('wb_red_gain', parseFloat(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>0.00</span>
<span>3.99</span>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Green Gain: {config.wb_green_gain?.toFixed(2) || '1.00'}
</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_green_gain || 1.0}
onChange={(e) => updateSetting('wb_green_gain', parseFloat(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>0.00</span>
<span>3.99</span>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Blue Gain: {config.wb_blue_gain?.toFixed(2) || '1.00'}
</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_blue_gain || 1.0}
onChange={(e) => updateSetting('wb_blue_gain', parseFloat(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>0.00</span>
<span>3.99</span>
</div>
</div>
</div>
<p className="text-xs text-gray-500 mt-2">Manual white balance gains (only effective when Auto White Balance is disabled)</p>
</div>
{/* Advanced Settings */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">Advanced Settings</h4>
@@ -536,162 +612,63 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
</div>
</div>
{/* Video Recording Settings */}
{/* Video Recording Settings (Read-Only) */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">Video Recording Settings</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Video Format
</label>
<select
value={config.video_format || 'mp4'}
onChange={(e) => updateSetting('video_format', e.target.value)}
className="w-full border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500"
>
<option value="mp4">MP4 (Recommended)</option>
<option value="avi">AVI (Legacy)</option>
</select>
<p className="text-xs text-gray-500 mt-1">MP4 provides better web compatibility and smaller file sizes</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Video Codec
</label>
<select
value={config.video_codec || 'mp4v'}
onChange={(e) => updateSetting('video_codec', e.target.value)}
className="w-full border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500"
>
{getAvailableCodecs(config.video_format || 'mp4').map(codec => (
<option key={codec} value={codec}>{codec.toUpperCase()}</option>
))}
</select>
<p className="text-xs text-gray-500 mt-1">Video compression codec</p>
</div>
<div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2">
Video Quality: {config.video_quality ?? 95}%
</label>
<input
type="range"
min="50"
max="100"
step="5"
value={config.video_quality ?? 95}
onChange={(e) => updateSetting('video_quality', parseInt(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>50% (Smaller files)</span>
<span>100% (Best quality)</span>
<div className="bg-gray-50 border border-gray-200 rounded-md p-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Video Format
</label>
<div className="text-sm text-gray-900 font-medium">
{config.video_format?.toUpperCase() || 'MP4'}
</div>
<p className="text-xs text-gray-500">Current recording format</p>
</div>
<p className="text-xs text-gray-500 mt-1">Higher quality = larger file sizes</p>
</div>
</div>
{/* Video Format Warnings */}
{videoFormatWarnings.length > 0 && (
<div className="mt-4 p-3 bg-yellow-50 border border-yellow-200 rounded-md">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Video Codec
</label>
<div className="text-sm text-gray-900 font-medium">
{config.video_codec?.toUpperCase() || 'MP4V'}
</div>
<p className="text-xs text-gray-500">Compression codec</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Video Quality
</label>
<div className="text-sm text-gray-900 font-medium">
{config.video_quality || 95}%
</div>
<p className="text-xs text-gray-500">Recording quality</p>
</div>
</div>
<div className="mt-4 p-3 bg-blue-50 border border-blue-200 rounded-md">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
<svg className="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">Video Format Warnings</h3>
<div className="mt-2 text-sm text-yellow-700">
<ul className="list-disc list-inside space-y-1">
{videoFormatWarnings.map((warning, index) => (
<li key={index}>{warning}</li>
))}
</ul>
<h3 className="text-sm font-medium text-blue-800">Video Format Information</h3>
<div className="mt-2 text-sm text-blue-700">
<p>Video recording settings are configured in the system configuration file and require a service restart to modify.</p>
<p className="mt-1"><strong>Current benefits:</strong> MP4 format provides ~40% smaller file sizes and better web compatibility than AVI.</p>
</div>
</div>
</div>
</div>
)}
{/* Restart Warning */}
{needsRestart && (
<div className="mt-4 p-3 bg-red-50 border border-red-200 rounded-md">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">Restart Required</h3>
<p className="mt-2 text-sm text-red-700">
Video format changes require a camera service restart to take effect. Use "Apply & Restart" to apply these changes.
</p>
</div>
</div>
</div>
)}
</div>
{/* Auto-Recording Settings */}
<div>
<h4 className="text-md font-medium text-gray-900 mb-4">Auto-Recording Settings</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={config.auto_record_on_machine_start}
onChange={(e) => updateSetting('auto_record_on_machine_start', e.target.checked)}
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
<span className="text-sm font-medium text-gray-700">Auto Record on Machine Start</span>
</label>
<p className="text-xs text-gray-500 mt-1">Start recording when MQTT machine state changes to ON</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Max Retries: {config.auto_recording_max_retries}
</label>
<input
type="range"
min="1"
max="10"
step="1"
value={config.auto_recording_max_retries}
onChange={(e) => updateSetting('auto_recording_max_retries', parseInt(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>1</span>
<span>10</span>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Retry Delay (seconds): {config.auto_recording_retry_delay_seconds}
</label>
<input
type="range"
min="1"
max="30"
step="1"
value={config.auto_recording_retry_delay_seconds}
onChange={(e) => updateSetting('auto_recording_retry_delay_seconds', parseInt(e.target.value))}
className="w-full"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>1s</span>
<span>30s</span>
</div>
</div>
</div>
</div>
{/* Information */}
<div className="bg-blue-50 border border-blue-200 rounded-md p-4">
<div className="flex">
@@ -704,10 +681,10 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
<h3 className="text-sm font-medium text-blue-800">Configuration Notes</h3>
<div className="mt-2 text-sm text-blue-700">
<ul className="list-disc list-inside space-y-1">
<li>Real-time settings (exposure, gain, image quality) apply immediately</li>
<li>Noise reduction settings require camera restart to take effect</li>
<li>Use "Apply & Restart" to apply settings that require restart</li>
<li>HDR mode may impact performance when enabled</li>
<li><strong>Real-time settings:</strong> Exposure, gain, image quality, white balance - apply immediately</li>
<li><strong>System settings:</strong> Video format, noise reduction, auto-recording - configured in system files</li>
<li><strong>Performance:</strong> HDR mode may impact frame rate when enabled</li>
<li><strong>White balance:</strong> RGB gains only effective when auto white balance is disabled</li>
</ul>
</div>
</div>
@@ -744,13 +721,6 @@ export function CameraConfigModal({ cameraName, isOpen, onClose, onSuccess, onEr
>
{saving ? 'Saving...' : 'Save Changes'}
</button>
<button
onClick={applyConfig}
disabled={applying}
className="px-4 py-2 text-sm font-medium text-white bg-red-600 border border-transparent rounded-md hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
{applying ? 'Applying...' : 'Apply & Restart'}
</button>
<button
onClick={onClose}
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"

View File

@@ -144,61 +144,73 @@ export interface AutoRecordingStatusResponse {
// Camera Configuration Types
export interface CameraConfig {
// READ-ONLY SYSTEM FIELDS
name: string
machine_topic: string
storage_path: string
enabled: boolean
auto_record_on_machine_start: boolean
// NEW AUTO-RECORDING CONFIG FIELDS (optional for backward compatibility)
auto_start_recording_enabled?: boolean
auto_recording_max_retries?: number
auto_recording_retry_delay_seconds?: number
// READ-ONLY AUTO-RECORDING FIELDS
auto_start_recording_enabled: boolean
auto_recording_max_retries: number
auto_recording_retry_delay_seconds: number
// BASIC SETTINGS (real-time configurable)
exposure_ms: number
gain: number
target_fps: number
// NEW VIDEO RECORDING SETTINGS (MP4 format support)
video_format?: string // 'mp4' or 'avi' (optional for backward compatibility)
video_codec?: string // 'mp4v', 'XVID', 'MJPG' (optional for backward compatibility)
video_quality?: number // 0-100 (higher = better quality) (optional for backward compatibility)
// VIDEO RECORDING SETTINGS (restart required)
video_format: string // 'mp4' or 'avi'
video_codec: string // 'mp4v', 'XVID', 'MJPG'
video_quality: number // 0-100 (higher = better quality)
// IMAGE QUALITY SETTINGS (real-time configurable)
sharpness: number
contrast: number
saturation: number
gamma: number
noise_filter_enabled: boolean
denoise_3d_enabled: boolean
// COLOR SETTINGS (real-time configurable)
auto_white_balance: boolean
color_temperature_preset: number
// WHITE BALANCE RGB GAINS (real-time configurable)
wb_red_gain: number
wb_green_gain: number
wb_blue_gain: number
// ADVANCED SETTINGS
anti_flicker_enabled: boolean
light_frequency: number
// NOISE REDUCTION (restart required)
noise_filter_enabled: boolean
denoise_3d_enabled: boolean
// SYSTEM SETTINGS (restart required)
bit_depth: number
// HDR SETTINGS (real-time configurable)
hdr_enabled: boolean
hdr_gain_mode: number
}
export interface CameraConfigUpdate {
auto_record_on_machine_start?: boolean
auto_start_recording_enabled?: boolean
auto_recording_max_retries?: number
auto_recording_retry_delay_seconds?: number
// BASIC SETTINGS (real-time configurable)
exposure_ms?: number
gain?: number
target_fps?: number
// NEW VIDEO RECORDING SETTINGS (MP4 format support)
video_format?: string // 'mp4' or 'avi'
video_codec?: string // 'mp4v', 'XVID', 'MJPG'
video_quality?: number // 0-100 (higher = better quality)
// IMAGE QUALITY SETTINGS (real-time configurable)
sharpness?: number
contrast?: number
saturation?: number
gamma?: number
noise_filter_enabled?: boolean
denoise_3d_enabled?: boolean
// COLOR SETTINGS (real-time configurable)
auto_white_balance?: boolean
color_temperature_preset?: number
// WHITE BALANCE RGB GAINS (real-time configurable)
wb_red_gain?: number
wb_green_gain?: number
wb_blue_gain?: number
// ADVANCED SETTINGS (real-time configurable)
anti_flicker_enabled?: boolean
light_frequency?: number
// HDR SETTINGS (real-time configurable)
hdr_enabled?: boolean
hdr_gain_mode?: number
// NOTE: Video format settings and noise reduction settings are not included
// as they are either read-only or require restart via apply-config endpoint
}
export interface CameraConfigUpdateResponse {