feat: Add CameraPreviewModal component for live camera streaming

feat: Implement useAuth hook for user authentication management

feat: Create useAutoRecording hook for managing automatic recording functionality

feat: Develop AutoRecordingManager to handle automatic recording based on MQTT events

test: Add test script to verify camera configuration API fix

test: Create HTML page for testing camera configuration API and auto-recording fields
This commit is contained in:
Alireza Vaezi
2025-07-29 12:30:59 -04:00
parent 104f6202fb
commit 0d20fe189d
40 changed files with 8142 additions and 127 deletions

View File

@@ -0,0 +1,175 @@
# Instructions for AI Agent: Auto-Recording Feature Integration
## 🎯 Task Overview
Update the React application to support the new auto-recording feature that has been added to the USDA Vision Camera System backend.
## 📋 What You Need to Know
### System Context
- **Camera 1** monitors the **vibratory conveyor** (conveyor/cracker cam)
- **Camera 2** monitors the **blower separator** machine
- Auto-recording automatically starts when machines turn ON and stops when they turn OFF
- The system includes retry logic for failed recording attempts
- Manual recording always takes precedence over auto-recording
### New Backend Capabilities
The backend now supports:
1. **Automatic recording** triggered by MQTT machine state changes
2. **Retry mechanism** for failed recording attempts (configurable retries and delays)
3. **Status tracking** for auto-recording state, failures, and attempts
4. **API endpoints** for enabling/disabling and monitoring auto-recording
## 🔧 Required React App Changes
### 1. Update TypeScript Interfaces
Add these new fields to existing `CameraStatusResponse`:
```typescript
interface CameraStatusResponse {
// ... existing fields
auto_recording_enabled: boolean;
auto_recording_active: boolean;
auto_recording_failure_count: number;
auto_recording_last_attempt?: string;
auto_recording_last_error?: string;
}
```
Add new response types:
```typescript
interface AutoRecordingConfigResponse {
success: boolean;
message: string;
camera_name: string;
enabled: boolean;
}
interface AutoRecordingStatusResponse {
running: boolean;
auto_recording_enabled: boolean;
retry_queue: Record<string, any>;
enabled_cameras: string[];
}
```
### 2. Add New API Endpoints
```typescript
// Enable auto-recording for a camera
POST /cameras/{camera_name}/auto-recording/enable
// Disable auto-recording for a camera
POST /cameras/{camera_name}/auto-recording/disable
// Get overall auto-recording system status
GET /auto-recording/status
```
### 3. UI Components to Add/Update
#### Camera Status Display
- Add auto-recording status badge/indicator
- Show auto-recording enabled/disabled state
- Display failure count if > 0
- Show last error message if any
- Distinguish between manual and auto-recording states
#### Auto-Recording Controls
- Toggle switch to enable/disable auto-recording per camera
- System-wide auto-recording status display
- Retry queue information
- Machine state correlation display
#### Error Handling
- Clear display of auto-recording failures
- Retry attempt information
- Last attempt timestamp
- Quick retry/reset actions
### 4. Visual Design Guidelines
**Status Priority (highest to lowest):**
1. Manual Recording (red/prominent) - user initiated
2. Auto-Recording Active (green) - machine ON, recording
3. Auto-Recording Enabled (blue) - ready but machine OFF
4. Auto-Recording Disabled (gray) - feature disabled
**Machine Correlation:**
- Show machine name next to camera (e.g., "Vibratory Conveyor", "Blower Separator")
- Display machine ON/OFF status
- Alert if machine is ON but auto-recording failed
## 🎨 Specific Implementation Tasks
### Task 1: Update Camera Cards
- Add auto-recording status indicators
- Add enable/disable toggle controls
- Show machine state correlation
- Display failure information when relevant
### Task 2: Create Auto-Recording Dashboard
- Overall system status
- List of enabled cameras
- Active retry queue display
- Recent events/errors
### Task 3: Update Recording Status Logic
- Distinguish between manual and auto-recording
- Show appropriate controls based on recording type
- Handle manual override scenarios
### Task 4: Add Error Handling
- Display auto-recording failures clearly
- Show retry attempts and timing
- Provide manual retry options
## 📱 User Experience Requirements
### Key Behaviors
1. **Non-Intrusive:** Auto-recording status shouldn't clutter the main interface
2. **Clear Hierarchy:** Manual controls should be more prominent than auto-recording
3. **Informative:** Users should understand why recording started/stopped
4. **Actionable:** Clear options to enable/disable or retry failed attempts
### Mobile Considerations
- Auto-recording controls should work well on mobile
- Status information should be readable on small screens
- Consider collapsible sections for detailed information
## 🔍 Testing Requirements
Ensure the React app correctly handles:
- [ ] Toggling auto-recording on/off per camera
- [ ] Displaying real-time status updates
- [ ] Showing error states and retry information
- [ ] Manual recording override scenarios
- [ ] Machine state changes and correlation
- [ ] Mobile interface functionality
## 📚 Reference Files
Key files to review for implementation details:
- `AUTO_RECORDING_FEATURE_GUIDE.md` - Comprehensive technical details
- `api-endpoints.http` - API endpoint documentation
- `config.json` - Configuration structure
- `usda_vision_system/api/models.py` - Response type definitions
## 🎯 Success Criteria
The React app should:
1. **Display** auto-recording status for each camera clearly
2. **Allow** users to enable/disable auto-recording per camera
3. **Show** machine state correlation and recording triggers
4. **Handle** error states and retry scenarios gracefully
5. **Maintain** existing manual recording functionality
6. **Provide** clear visual hierarchy between manual and auto-recording
## 💡 Implementation Tips
1. **Start Small:** Begin with basic status display, then add controls
2. **Use Existing Patterns:** Follow the current app's design patterns
3. **Test Incrementally:** Test each feature as you add it
4. **Consider State Management:** Update your state management to handle new data
5. **Mobile First:** Ensure mobile usability from the start
The goal is to seamlessly integrate auto-recording capabilities while maintaining the existing user experience and adding valuable automation features for the camera operators.

View File

@@ -0,0 +1,595 @@
# 🤖 AI Integration Guide: USDA Vision Camera Streaming for React Projects
This guide is specifically designed for AI assistants to understand and implement the USDA Vision Camera streaming functionality in React applications.
## 📋 System Overview
The USDA Vision Camera system provides live video streaming through REST API endpoints. The streaming uses MJPEG format which is natively supported by HTML `<img>` tags and can be easily integrated into React components.
### Key Characteristics:
- **Base URL**: `http://vision:8000` (production) or `http://localhost:8000` (development)
- **Stream Format**: MJPEG (Motion JPEG)
- **Content-Type**: `multipart/x-mixed-replace; boundary=frame`
- **Authentication**: None (add if needed for production)
- **CORS**: Enabled for all origins (configure for production)
### Base URL Configuration:
- **Production**: `http://vision:8000` (requires hostname setup)
- **Development**: `http://localhost:8000` (local testing)
- **Custom IP**: `http://192.168.1.100:8000` (replace with actual IP)
- **Custom hostname**: Configure DNS or /etc/hosts as needed
## 🔌 API Endpoints Reference
### 1. Get Camera List
```http
GET /cameras
```
**Response:**
```json
{
"camera1": {
"name": "camera1",
"status": "connected",
"is_recording": false,
"last_checked": "2025-01-28T10:30:00",
"device_info": {...}
},
"camera2": {...}
}
```
### 2. Start Camera Stream
```http
POST /cameras/{camera_name}/start-stream
```
**Response:**
```json
{
"success": true,
"message": "Started streaming for camera camera1"
}
```
### 3. Stop Camera Stream
```http
POST /cameras/{camera_name}/stop-stream
```
**Response:**
```json
{
"success": true,
"message": "Stopped streaming for camera camera1"
}
```
### 4. Live Video Stream
```http
GET /cameras/{camera_name}/stream
```
**Response:** MJPEG video stream
**Usage:** Set as `src` attribute of HTML `<img>` element
## ⚛️ React Integration Examples
### Basic Camera Stream Component
```jsx
import React, { useState, useEffect } from 'react';
const CameraStream = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => {
const [isStreaming, setIsStreaming] = useState(false);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const startStream = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/start-stream`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
setIsStreaming(true);
} else {
const errorData = await response.json();
setError(errorData.detail || 'Failed to start stream');
}
} catch (err) {
setError(`Network error: ${err.message}`);
} finally {
setLoading(false);
}
};
const stopStream = async () => {
setLoading(true);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/stop-stream`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
setIsStreaming(false);
} else {
const errorData = await response.json();
setError(errorData.detail || 'Failed to stop stream');
}
} catch (err) {
setError(`Network error: ${err.message}`);
} finally {
setLoading(false);
}
};
return (
<div className="camera-stream">
<h3>Camera: {cameraName}</h3>
{/* Video Stream */}
<div className="stream-container">
{isStreaming ? (
<img
src={`${apiBaseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`}
alt={`${cameraName} live stream`}
style={{
width: '100%',
maxWidth: '640px',
height: 'auto',
border: '2px solid #ddd',
borderRadius: '8px',
}}
onError={() => setError('Stream connection lost')}
/>
) : (
<div style={{
width: '100%',
maxWidth: '640px',
height: '360px',
backgroundColor: '#f0f0f0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: '2px solid #ddd',
borderRadius: '8px',
}}>
<span>No Stream Active</span>
</div>
)}
</div>
{/* Controls */}
<div className="stream-controls" style={{ marginTop: '10px' }}>
<button
onClick={startStream}
disabled={loading || isStreaming}
style={{
padding: '8px 16px',
marginRight: '8px',
backgroundColor: '#28a745',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: loading ? 'not-allowed' : 'pointer',
}}
>
{loading ? 'Loading...' : 'Start Stream'}
</button>
<button
onClick={stopStream}
disabled={loading || !isStreaming}
style={{
padding: '8px 16px',
backgroundColor: '#dc3545',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: loading ? 'not-allowed' : 'pointer',
}}
>
{loading ? 'Loading...' : 'Stop Stream'}
</button>
</div>
{/* Error Display */}
{error && (
<div style={{
marginTop: '10px',
padding: '8px',
backgroundColor: '#f8d7da',
color: '#721c24',
border: '1px solid #f5c6cb',
borderRadius: '4px',
}}>
Error: {error}
</div>
)}
</div>
);
};
export default CameraStream;
```
### Multi-Camera Dashboard Component
```jsx
import React, { useState, useEffect } from 'react';
import CameraStream from './CameraStream';
const CameraDashboard = ({ apiBaseUrl = 'http://vision:8000' }) => {
const [cameras, setCameras] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchCameras();
// Refresh camera status every 30 seconds
const interval = setInterval(fetchCameras, 30000);
return () => clearInterval(interval);
}, []);
const fetchCameras = async () => {
try {
const response = await fetch(`${apiBaseUrl}/cameras`);
if (response.ok) {
const data = await response.json();
setCameras(data);
setError(null);
} else {
setError('Failed to fetch cameras');
}
} catch (err) {
setError(`Network error: ${err.message}`);
} finally {
setLoading(false);
}
};
if (loading) {
return <div>Loading cameras...</div>;
}
if (error) {
return (
<div style={{ color: 'red', padding: '20px' }}>
Error: {error}
<button onClick={fetchCameras} style={{ marginLeft: '10px' }}>
Retry
</button>
</div>
);
}
return (
<div className="camera-dashboard">
<h1>USDA Vision Camera Dashboard</h1>
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))',
gap: '20px',
padding: '20px',
}}>
{Object.entries(cameras).map(([cameraName, cameraInfo]) => (
<div key={cameraName} style={{
border: '1px solid #ddd',
borderRadius: '8px',
padding: '15px',
backgroundColor: '#f9f9f9',
}}>
<CameraStream
cameraName={cameraName}
apiBaseUrl={apiBaseUrl}
/>
{/* Camera Status */}
<div style={{ marginTop: '10px', fontSize: '14px' }}>
<div>Status: <strong>{cameraInfo.status}</strong></div>
<div>Recording: <strong>{cameraInfo.is_recording ? 'Yes' : 'No'}</strong></div>
<div>Last Checked: {new Date(cameraInfo.last_checked).toLocaleString()}</div>
</div>
</div>
))}
</div>
</div>
);
};
export default CameraDashboard;
```
### Custom Hook for Camera Management
```jsx
import { useState, useEffect, useCallback } from 'react';
const useCameraStream = (cameraName, apiBaseUrl = 'http://vision:8000') => {
const [isStreaming, setIsStreaming] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const startStream = useCallback(async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/start-stream`, {
method: 'POST',
});
if (response.ok) {
setIsStreaming(true);
return { success: true };
} else {
const errorData = await response.json();
const errorMsg = errorData.detail || 'Failed to start stream';
setError(errorMsg);
return { success: false, error: errorMsg };
}
} catch (err) {
const errorMsg = `Network error: ${err.message}`;
setError(errorMsg);
return { success: false, error: errorMsg };
} finally {
setLoading(false);
}
}, [cameraName, apiBaseUrl]);
const stopStream = useCallback(async () => {
setLoading(true);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/stop-stream`, {
method: 'POST',
});
if (response.ok) {
setIsStreaming(false);
return { success: true };
} else {
const errorData = await response.json();
const errorMsg = errorData.detail || 'Failed to stop stream';
setError(errorMsg);
return { success: false, error: errorMsg };
}
} catch (err) {
const errorMsg = `Network error: ${err.message}`;
setError(errorMsg);
return { success: false, error: errorMsg };
} finally {
setLoading(false);
}
}, [cameraName, apiBaseUrl]);
const getStreamUrl = useCallback(() => {
return `${apiBaseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`;
}, [cameraName, apiBaseUrl]);
return {
isStreaming,
loading,
error,
startStream,
stopStream,
getStreamUrl,
};
};
export default useCameraStream;
```
## 🎨 Styling with Tailwind CSS
```jsx
const CameraStreamTailwind = ({ cameraName }) => {
const { isStreaming, loading, error, startStream, stopStream, getStreamUrl } = useCameraStream(cameraName);
return (
<div className="bg-white rounded-lg shadow-md p-6">
<h3 className="text-lg font-semibold mb-4">Camera: {cameraName}</h3>
{/* Stream Container */}
<div className="relative mb-4">
{isStreaming ? (
<img
src={getStreamUrl()}
alt={`${cameraName} live stream`}
className="w-full max-w-2xl h-auto border-2 border-gray-300 rounded-lg"
onError={() => setError('Stream connection lost')}
/>
) : (
<div className="w-full max-w-2xl h-64 bg-gray-100 border-2 border-gray-300 rounded-lg flex items-center justify-center">
<span className="text-gray-500">No Stream Active</span>
</div>
)}
</div>
{/* Controls */}
<div className="flex gap-2 mb-4">
<button
onClick={startStream}
disabled={loading || isStreaming}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Loading...' : 'Start Stream'}
</button>
<button
onClick={stopStream}
disabled={loading || !isStreaming}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Loading...' : 'Stop Stream'}
</button>
</div>
{/* Error Display */}
{error && (
<div className="p-3 bg-red-100 border border-red-400 text-red-700 rounded">
Error: {error}
</div>
)}
</div>
);
};
```
## 🔧 Configuration Options
### Environment Variables (.env)
```env
# Production configuration (using 'vision' hostname)
REACT_APP_CAMERA_API_URL=http://vision:8000
REACT_APP_STREAM_REFRESH_INTERVAL=30000
REACT_APP_STREAM_TIMEOUT=10000
# Development configuration (using localhost)
# REACT_APP_CAMERA_API_URL=http://localhost:8000
# Custom IP configuration
# REACT_APP_CAMERA_API_URL=http://192.168.1.100:8000
```
### API Configuration
```javascript
const apiConfig = {
baseUrl: process.env.REACT_APP_CAMERA_API_URL || 'http://vision:8000',
timeout: parseInt(process.env.REACT_APP_STREAM_TIMEOUT) || 10000,
refreshInterval: parseInt(process.env.REACT_APP_STREAM_REFRESH_INTERVAL) || 30000,
};
```
### Hostname Setup Guide
```bash
# Option 1: Add to /etc/hosts (Linux/Mac)
echo "127.0.0.1 vision" | sudo tee -a /etc/hosts
# Option 2: Add to hosts file (Windows)
# Add to C:\Windows\System32\drivers\etc\hosts:
# 127.0.0.1 vision
# Option 3: Configure DNS
# Point 'vision' hostname to your server's IP address
# Verify hostname resolution
ping vision
```
## 🚨 Important Implementation Notes
### 1. MJPEG Stream Handling
- Use HTML `<img>` tag with `src` pointing to stream endpoint
- Add timestamp query parameter to prevent caching: `?t=${Date.now()}`
- Handle `onError` event for connection issues
### 2. Error Handling
- Network errors (fetch failures)
- HTTP errors (4xx, 5xx responses)
- Stream connection errors (img onError)
- Timeout handling for long requests
### 3. Performance Considerations
- Streams consume bandwidth continuously
- Stop streams when components unmount
- Limit concurrent streams based on system capacity
- Consider lazy loading for multiple cameras
### 4. State Management
- Track streaming state per camera
- Handle loading states during API calls
- Manage error states with user feedback
- Refresh camera list periodically
## 📱 Mobile Considerations
```jsx
// Responsive design for mobile
const mobileStyles = {
container: {
padding: '10px',
maxWidth: '100vw',
},
stream: {
width: '100%',
maxWidth: '100vw',
height: 'auto',
},
controls: {
display: 'flex',
flexDirection: 'column',
gap: '8px',
},
};
```
## 🧪 Testing Integration
```javascript
// Test API connectivity
const testConnection = async () => {
try {
const response = await fetch(`${apiBaseUrl}/health`);
return response.ok;
} catch {
return false;
}
};
// Test camera availability
const testCamera = async (cameraName) => {
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/test-connection`, {
method: 'POST',
});
return response.ok;
} catch {
return false;
}
};
```
## 📁 Additional Files for AI Integration
### TypeScript Definitions
- `camera-api.types.ts` - Complete TypeScript definitions for all API types
- `streaming-api.http` - REST Client file with all streaming endpoints
- `STREAMING_GUIDE.md` - Comprehensive user guide for streaming functionality
### Quick Integration Checklist for AI Assistants
1. **Copy TypeScript types** from `camera-api.types.ts`
2. **Use API endpoints** from `streaming-api.http`
3. **Implement error handling** as shown in examples
4. **Add CORS configuration** if needed for production
5. **Test with multiple cameras** using provided examples
### Key Integration Points
- **Stream URL Format**: `${baseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`
- **Start Stream**: `POST /cameras/{name}/start-stream`
- **Stop Stream**: `POST /cameras/{name}/stop-stream`
- **Camera List**: `GET /cameras`
- **Error Handling**: Always wrap in try-catch blocks
- **Loading States**: Implement for better UX
### Production Considerations
- Configure CORS for specific origins
- Add authentication if required
- Implement rate limiting
- Monitor system resources with multiple streams
- Add reconnection logic for network issues
This documentation provides everything an AI assistant needs to integrate the USDA Vision Camera streaming functionality into React applications, including complete code examples, error handling, and best practices.

View File

@@ -0,0 +1,260 @@
# Auto-Recording Feature Implementation Guide
## 🎯 Overview for React App Development
This document provides a comprehensive guide for updating the React application to support the new auto-recording feature that was added to the USDA Vision Camera System.
## 📋 What Changed in the Backend
### New API Endpoints Added
1. **Enable Auto-Recording**
```http
POST /cameras/{camera_name}/auto-recording/enable
Response: AutoRecordingConfigResponse
```
2. **Disable Auto-Recording**
```http
POST /cameras/{camera_name}/auto-recording/disable
Response: AutoRecordingConfigResponse
```
3. **Get Auto-Recording Status**
```http
GET /auto-recording/status
Response: AutoRecordingStatusResponse
```
### Updated API Responses
#### CameraStatusResponse (Updated)
```typescript
interface CameraStatusResponse {
name: string;
status: string;
is_recording: boolean;
last_checked: string;
last_error?: string;
device_info?: any;
current_recording_file?: string;
recording_start_time?: string;
// NEW AUTO-RECORDING FIELDS
auto_recording_enabled: boolean;
auto_recording_active: boolean;
auto_recording_failure_count: number;
auto_recording_last_attempt?: string;
auto_recording_last_error?: string;
}
```
#### CameraConfigResponse (Updated)
```typescript
interface CameraConfigResponse {
name: string;
machine_topic: string;
storage_path: string;
enabled: boolean;
// NEW AUTO-RECORDING CONFIG FIELDS
auto_start_recording_enabled: boolean;
auto_recording_max_retries: number;
auto_recording_retry_delay_seconds: number;
// ... existing fields (exposure_ms, gain, etc.)
}
```
#### New Response Types
```typescript
interface AutoRecordingConfigResponse {
success: boolean;
message: string;
camera_name: string;
enabled: boolean;
}
interface AutoRecordingStatusResponse {
running: boolean;
auto_recording_enabled: boolean;
retry_queue: Record<string, any>;
enabled_cameras: string[];
}
```
## 🎨 React App UI Requirements
### 1. Camera Status Display Updates
**Add to Camera Cards/Components:**
- Auto-recording enabled/disabled indicator
- Auto-recording active status (when machine is ON and auto-recording)
- Failure count display (if > 0)
- Last auto-recording error (if any)
- Visual distinction between manual and auto-recording
**Example UI Elements:**
```jsx
// Auto-recording status badge
{camera.auto_recording_enabled && (
<Badge variant={camera.auto_recording_active ? "success" : "secondary"}>
Auto-Recording {camera.auto_recording_active ? "Active" : "Enabled"}
</Badge>
)}
// Failure indicator
{camera.auto_recording_failure_count > 0 && (
<Alert variant="warning">
Auto-recording failures: {camera.auto_recording_failure_count}
</Alert>
)}
```
### 2. Auto-Recording Controls
**Add Toggle Controls:**
- Enable/Disable auto-recording per camera
- Global auto-recording status display
- Retry queue monitoring
**Example Control Component:**
```jsx
const AutoRecordingToggle = ({ camera, onToggle }) => {
const handleToggle = async () => {
const endpoint = camera.auto_recording_enabled ? 'disable' : 'enable';
await fetch(`/cameras/${camera.name}/auto-recording/${endpoint}`, {
method: 'POST'
});
onToggle();
};
return (
<Switch
checked={camera.auto_recording_enabled}
onChange={handleToggle}
label="Auto-Recording"
/>
);
};
```
### 3. Machine State Integration
**Display Machine Status:**
- Show which machine each camera monitors
- Display current machine state (ON/OFF)
- Show correlation between machine state and recording status
**Camera-Machine Mapping:**
- Camera 1 → Vibratory Conveyor (conveyor/cracker cam)
- Camera 2 → Blower Separator (blower separator)
### 4. Auto-Recording Dashboard
**Create New Dashboard Section:**
- Overall auto-recording system status
- List of cameras with auto-recording enabled
- Active retry queue display
- Recent auto-recording events/logs
## 🔧 Implementation Steps for React App
### Step 1: Update TypeScript Interfaces
```typescript
// Update existing interfaces in your types file
// Add new interfaces for auto-recording responses
```
### Step 2: Update API Service Functions
```typescript
// Add new API calls
export const enableAutoRecording = (cameraName: string) =>
fetch(`/cameras/${cameraName}/auto-recording/enable`, { method: 'POST' });
export const disableAutoRecording = (cameraName: string) =>
fetch(`/cameras/${cameraName}/auto-recording/disable`, { method: 'POST' });
export const getAutoRecordingStatus = () =>
fetch('/auto-recording/status').then(res => res.json());
```
### Step 3: Update Camera Components
- Add auto-recording status indicators
- Add enable/disable controls
- Update recording status display to distinguish auto vs manual
### Step 4: Create Auto-Recording Management Panel
- System-wide auto-recording status
- Per-camera auto-recording controls
- Retry queue monitoring
- Error reporting and alerts
### Step 5: Update State Management
```typescript
// Add auto-recording state to your store/context
interface AppState {
cameras: CameraStatusResponse[];
autoRecordingStatus: AutoRecordingStatusResponse;
// ... existing state
}
```
## 🎯 Key User Experience Considerations
### Visual Indicators
1. **Recording Status Hierarchy:**
- Manual Recording (highest priority - red/prominent)
- Auto-Recording Active (green/secondary)
- Auto-Recording Enabled but Inactive (blue/subtle)
- Auto-Recording Disabled (gray/muted)
2. **Machine State Correlation:**
- Show machine ON/OFF status next to camera
- Indicate when auto-recording should be active
- Alert if machine is ON but auto-recording failed
3. **Error Handling:**
- Clear error messages for auto-recording failures
- Retry count display
- Last attempt timestamp
- Quick retry/reset options
### User Controls
1. **Quick Actions:**
- Toggle auto-recording per camera
- Force retry failed auto-recording
- Override auto-recording (manual control)
2. **Configuration:**
- Adjust retry settings
- Change machine-camera mappings
- Set recording parameters for auto-recording
## 🚨 Important Notes
### Behavior Rules
1. **Manual Override:** Manual recording always takes precedence over auto-recording
2. **Non-Blocking:** Auto-recording status checks don't interfere with camera operation
3. **Machine Correlation:** Auto-recording only activates when the associated machine turns ON
4. **Failure Handling:** Failed auto-recording attempts are retried automatically with exponential backoff
### API Polling Recommendations
- Poll camera status every 2-3 seconds for real-time updates
- Poll auto-recording status every 5-10 seconds
- Use WebSocket connections if available for real-time machine state updates
## 📱 Mobile Considerations
- Auto-recording controls should be easily accessible on mobile
- Status indicators should be clear and readable on small screens
- Consider collapsible sections for detailed auto-recording information
## 🔍 Testing Checklist
- [ ] Auto-recording toggle works for each camera
- [ ] Status updates reflect machine state changes
- [ ] Error states are clearly displayed
- [ ] Manual recording overrides auto-recording
- [ ] Retry mechanism is visible to users
- [ ] Mobile interface is functional
This guide provides everything needed to update the React app to fully support the new auto-recording feature!

View File

@@ -0,0 +1,455 @@
# 🎛️ Camera Configuration API Guide
This guide explains how to configure camera settings via API endpoints, including all the advanced settings from your config.json.
## 📋 Configuration Categories
### ✅ **Real-time Configurable (No Restart Required)**
These settings can be changed while the camera is active:
- **Basic**: `exposure_ms`, `gain`, `target_fps`
- **Image Quality**: `sharpness`, `contrast`, `saturation`, `gamma`
- **Color**: `auto_white_balance`, `color_temperature_preset`
- **Advanced**: `anti_flicker_enabled`, `light_frequency`
- **HDR**: `hdr_enabled`, `hdr_gain_mode`
### ⚠️ **Restart Required**
These settings require camera restart to take effect:
- **Noise Reduction**: `noise_filter_enabled`, `denoise_3d_enabled`
- **System**: `machine_topic`, `storage_path`, `enabled`, `bit_depth`
### 🤖 **Auto-Recording**
- **Auto-Recording**: `auto_record_on_machine_start` - When enabled, the camera automatically starts recording when MQTT messages indicate the associated machine turns on, and stops recording when it turns off
## 🔌 API Endpoints
### 1. Get Camera Configuration
```http
GET /cameras/{camera_name}/config
```
**Response:**
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1",
"enabled": true,
"auto_record_on_machine_start": false,
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 0,
"sharpness": 120,
"contrast": 110,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"denoise_3d_enabled": false,
"auto_white_balance": true,
"color_temperature_preset": 0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
```
### 2. Update Camera Configuration
```http
PUT /cameras/{camera_name}/config
Content-Type: application/json
```
**Request Body (all fields optional):**
```json
{
"auto_record_on_machine_start": true,
"exposure_ms": 2.0,
"gain": 4.0,
"target_fps": 10.0,
"sharpness": 150,
"contrast": 120,
"saturation": 110,
"gamma": 90,
"noise_filter_enabled": true,
"denoise_3d_enabled": false,
"auto_white_balance": false,
"color_temperature_preset": 1,
"anti_flicker_enabled": true,
"light_frequency": 1,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
```
**Response:**
```json
{
"success": true,
"message": "Camera camera1 configuration updated",
"updated_settings": ["exposure_ms", "gain", "sharpness"]
}
```
### 3. Apply Configuration (Restart Camera)
```http
POST /cameras/{camera_name}/apply-config
```
**Response:**
```json
{
"success": true,
"message": "Configuration applied to camera camera1"
}
```
## 📊 Setting Ranges and Descriptions
### Basic Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `exposure_ms` | 0.1 - 1000.0 | 1.0 | Exposure time in milliseconds |
| `gain` | 0.0 - 20.0 | 3.5 | Camera gain multiplier |
| `target_fps` | 0.0 - 120.0 | 0 | Target FPS (0 = maximum) |
### Image Quality Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `sharpness` | 0 - 200 | 100 | Image sharpness (100 = no sharpening) |
| `contrast` | 0 - 200 | 100 | Image contrast (100 = normal) |
| `saturation` | 0 - 200 | 100 | Color saturation (color cameras only) |
| `gamma` | 0 - 300 | 100 | Gamma correction (100 = normal) |
### Color Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `auto_white_balance` | true/false | true | Automatic white balance |
| `color_temperature_preset` | 0-10 | 0 | Color temperature preset (0=auto) |
### Advanced Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `anti_flicker_enabled` | true/false | true | Reduce artificial lighting flicker |
| `light_frequency` | 0/1 | 1 | Light frequency (0=50Hz, 1=60Hz) |
| `noise_filter_enabled` | true/false | true | Basic noise filtering |
| `denoise_3d_enabled` | true/false | false | Advanced 3D denoising |
### HDR Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `hdr_enabled` | true/false | false | High Dynamic Range |
| `hdr_gain_mode` | 0-3 | 0 | HDR processing mode |
## 🚀 Usage Examples
### Example 1: Adjust Exposure and Gain
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"exposure_ms": 1.5,
"gain": 4.0
}'
```
### Example 2: Improve Image Quality
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"sharpness": 150,
"contrast": 120,
"gamma": 90
}'
```
### Example 3: Configure for Indoor Lighting
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"anti_flicker_enabled": true,
"light_frequency": 1,
"auto_white_balance": false,
"color_temperature_preset": 2
}'
```
### Example 4: Enable HDR Mode
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"hdr_enabled": true,
"hdr_gain_mode": 1
}'
```
## ⚛️ React Integration Examples
### Camera Configuration Component
```jsx
import React, { useState, useEffect } from 'react';
const CameraConfig = ({ cameraName, apiBaseUrl = 'http://localhost:8000' }) => {
const [config, setConfig] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// Load current configuration
useEffect(() => {
fetchConfig();
}, [cameraName]);
const fetchConfig = async () => {
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/config`);
if (response.ok) {
const data = await response.json();
setConfig(data);
} else {
setError('Failed to load configuration');
}
} catch (err) {
setError(`Error: ${err.message}`);
}
};
const updateConfig = async (updates) => {
setLoading(true);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/config`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
if (response.ok) {
const result = await response.json();
console.log('Updated settings:', result.updated_settings);
await fetchConfig(); // Reload configuration
} else {
const error = await response.json();
setError(error.detail || 'Update failed');
}
} catch (err) {
setError(`Error: ${err.message}`);
} finally {
setLoading(false);
}
};
const handleSliderChange = (setting, value) => {
updateConfig({ [setting]: value });
};
if (!config) return <div>Loading configuration...</div>;
return (
<div className="camera-config">
<h3>Camera Configuration: {cameraName}</h3>
{/* Basic Settings */}
<div className="config-section">
<h4>Basic Settings</h4>
<div className="setting">
<label>Exposure (ms): {config.exposure_ms}</label>
<input
type="range"
min="0.1"
max="10"
step="0.1"
value={config.exposure_ms}
onChange={(e) => handleSliderChange('exposure_ms', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Gain: {config.gain}</label>
<input
type="range"
min="0"
max="10"
step="0.1"
value={config.gain}
onChange={(e) => handleSliderChange('gain', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Target FPS: {config.target_fps}</label>
<input
type="range"
min="0"
max="30"
step="1"
value={config.target_fps}
onChange={(e) => handleSliderChange('target_fps', parseInt(e.target.value))}
/>
</div>
</div>
{/* Image Quality Settings */}
<div className="config-section">
<h4>Image Quality</h4>
<div className="setting">
<label>Sharpness: {config.sharpness}</label>
<input
type="range"
min="0"
max="200"
value={config.sharpness}
onChange={(e) => handleSliderChange('sharpness', parseInt(e.target.value))}
/>
</div>
<div className="setting">
<label>Contrast: {config.contrast}</label>
<input
type="range"
min="0"
max="200"
value={config.contrast}
onChange={(e) => handleSliderChange('contrast', parseInt(e.target.value))}
/>
</div>
<div className="setting">
<label>Gamma: {config.gamma}</label>
<input
type="range"
min="0"
max="300"
value={config.gamma}
onChange={(e) => handleSliderChange('gamma', parseInt(e.target.value))}
/>
</div>
</div>
{/* Advanced Settings */}
<div className="config-section">
<h4>Advanced Settings</h4>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.anti_flicker_enabled}
onChange={(e) => updateConfig({ anti_flicker_enabled: e.target.checked })}
/>
Anti-flicker Enabled
</label>
</div>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.auto_white_balance}
onChange={(e) => updateConfig({ auto_white_balance: e.target.checked })}
/>
Auto White Balance
</label>
</div>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.hdr_enabled}
onChange={(e) => updateConfig({ hdr_enabled: e.target.checked })}
/>
HDR Enabled
</label>
</div>
</div>
{error && (
<div className="error" style={{ color: 'red', marginTop: '10px' }}>
{error}
</div>
)}
{loading && <div>Updating configuration...</div>}
</div>
);
};
export default CameraConfig;
```
## 🔄 Configuration Workflow
### 1. Real-time Adjustments
For settings that don't require restart:
```bash
# Update settings
curl -X PUT /cameras/camera1/config -d '{"exposure_ms": 2.0}'
# Settings take effect immediately
# Continue recording/streaming without interruption
```
### 2. Settings Requiring Restart
For noise reduction and system settings:
```bash
# Update settings
curl -X PUT /cameras/camera1/config -d '{"noise_filter_enabled": false}'
# Apply configuration (restarts camera)
curl -X POST /cameras/camera1/apply-config
# Camera reinitializes with new settings
```
## 🚨 Important Notes
### Camera State During Updates
- **Real-time settings**: Applied immediately, no interruption
- **Restart-required settings**: Saved to config, applied on next restart
- **Recording**: Continues during real-time updates
- **Streaming**: Continues during real-time updates
### Error Handling
- Invalid ranges return HTTP 422 with validation errors
- Camera not found returns HTTP 404
- SDK errors are logged and return HTTP 500
### Performance Impact
- **Image quality settings**: Minimal performance impact
- **Noise reduction**: May reduce FPS when enabled
- **HDR**: Significant processing overhead when enabled
This comprehensive API allows you to control all camera settings programmatically, making it perfect for integration with React dashboards or automated optimization systems!

View File

@@ -0,0 +1,870 @@
# USDA Vision Camera System
A comprehensive system for monitoring machines via MQTT and automatically recording video from GigE cameras when machines are active. Designed for Atlanta, Georgia operations with proper timezone synchronization.
## 🎯 Overview
This system integrates MQTT machine monitoring with automated video recording from GigE cameras. When a machine turns on (detected via MQTT), the system automatically starts recording from the associated camera. When the machine turns off, recording stops and the video is saved with an Atlanta timezone timestamp.
### Key Features
- **🔄 MQTT Integration**: Listens to multiple machine state topics
- **📹 Automatic Recording**: Starts/stops recording based on machine states
- **📷 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
- **💾 Storage Management**: Organized file storage with cleanup capabilities
- **📝 Comprehensive Logging**: Detailed logging with rotation and error tracking
- **⚙️ 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
├── camera_preview.html # Web camera preview interface
├── 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
├── tests/ # Organized test files
│ ├── api/ # API-related tests
│ ├── camera/ # Camera functionality tests
│ ├── core/ # Core system tests
│ ├── mqtt/ # MQTT integration tests
│ ├── recording/ # Recording feature tests
│ ├── storage/ # Storage management tests
│ ├── integration/ # System integration tests
│ └── legacy_tests/ # Archived development files
├── docs/ # Organized documentation
│ ├── api/ # API documentation
│ ├── features/ # Feature-specific guides
│ ├── guides/ # User and setup guides
│ └── legacy/ # Legacy documentation
├── ai_agent/ # AI agent resources
│ ├── guides/ # AI-specific instructions
│ ├── examples/ # Demo scripts and notebooks
│ └── references/ # API references and types
├── Camera/ # Camera data directory
└── storage/ # Recording storage (created at runtime)
├── camera1/ # Camera 1 recordings
└── camera2/ # Camera 2 recordings
```
## 🏗️ Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MQTT Broker │ │ GigE Camera │ │ Dashboard │
│ │ │ │ │ (React) │
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
│ │ │
│ Machine States │ Video Streams │ API Calls
│ │ │
┌─────────▼──────────────────────▼──────────────────────▼───────┐
│ USDA Vision Camera System │
├───────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MQTT Client │ │ Camera │ │ API Server │ │
│ │ │ │ Manager │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ State │ │ Storage │ │ Event │ │
│ │ Manager │ │ Manager │ │ System │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────────────┘
```
## 📋 Prerequisites
### Hardware Requirements
- GigE cameras compatible with camera SDK library
- Network connection to MQTT broker
- Sufficient storage space for video recordings
### Software Requirements
- **Python 3.11+**
- **uv package manager** (recommended) or pip
- **MQTT broker** (e.g., Mosquitto, Home Assistant)
- **Linux system** (tested on Ubuntu/Debian)
### Network Requirements
- Access to MQTT broker
- GigE cameras on network
- Internet access for time synchronization (optional but recommended)
## 🚀 Installation
### 1. Clone the Repository
```bash
git clone https://github.com/your-username/USDA-Vision-Cameras.git
cd USDA-Vision-Cameras
```
### 2. Install Dependencies
Using uv (recommended):
```bash
# Install uv if not already installed
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync
```
Using pip:
```bash
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
```
### 3. Setup GigE Camera Library
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
### 4. Configure Storage Directory
```bash
# Create storage directory (adjust path as needed)
mkdir -p ./storage
# Or for system-wide storage:
# sudo mkdir -p /storage && sudo chown $USER:$USER /storage
```
### 5. Setup Time Synchronization (Recommended)
```bash
# Run timezone setup for Atlanta, Georgia
./setup_timezone.sh
```
### 6. Configure the System
Edit `config.json` to match your setup:
```json
{
"mqtt": {
"broker_host": "192.168.1.110",
"broker_port": 1883,
"topics": {
"machine1": "vision/machine1/state",
"machine2": "vision/machine2/state"
}
},
"cameras": [
{
"name": "camera1",
"machine_topic": "machine1",
"storage_path": "./storage/camera1",
"enabled": true
}
]
}
```
## 🔧 Configuration
### MQTT Configuration
```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"
}
}
}
```
### Camera Configuration
```json
{
"cameras": [
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"storage_path": "./storage/camera1",
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 3.0,
"enabled": true
}
]
}
```
### System Configuration
```json
{
"system": {
"camera_check_interval_seconds": 2,
"log_level": "INFO",
"api_host": "0.0.0.0",
"api_port": 8000,
"enable_api": true,
"timezone": "America/New_York"
}
}
```
## 🎮 Usage
### Quick Start
```bash
# Test the system
python test_system.py
# Start the system
python main.py
# Or use the startup script
./start_system.sh
```
### Command Line Options
```bash
# Custom configuration file
python main.py --config my_config.json
# Debug mode
python main.py --log-level DEBUG
# Help
python main.py --help
```
### Verify Installation
```bash
# Run system tests
python test_system.py
# Check time synchronization
python check_time.py
# Test timezone functions
python test_timezone.py
```
## 🌐 API Usage
The system provides a comprehensive REST API for monitoring and control.
> **📚 Complete API Documentation**: See [docs/API_DOCUMENTATION.md](docs/API_DOCUMENTATION.md) for the full API reference including all endpoints, request/response models, examples, and recent enhancements.
>
> **⚡ Quick Reference**: See [docs/API_QUICK_REFERENCE.md](docs/API_QUICK_REFERENCE.md) for commonly used endpoints with curl examples.
### Starting the API Server
The API server starts automatically with the main system on port 8000:
```bash
python main.py
# API available at: http://localhost:8000
```
### 🚀 New API Features
#### Enhanced Recording Control
- **Dynamic camera settings**: Set exposure, gain, FPS per recording
- **Automatic datetime prefixes**: All filenames get timestamp prefixes
- **Auto-recording management**: Enable/disable per camera via API
#### Advanced Camera Configuration
- **Real-time settings**: Update image quality without restart
- **Live streaming**: MJPEG streams for web integration
- **Recovery operations**: Reconnect, reset, reinitialize cameras
#### Comprehensive Monitoring
- **MQTT event history**: Track machine state changes
- **Storage statistics**: Monitor disk usage and file counts
- **WebSocket updates**: Real-time system notifications
### Core Endpoints
#### System Status
```bash
# Get overall system status
curl http://localhost:8000/system/status
# Response example:
{
"system_started": true,
"mqtt_connected": true,
"machines": {
"vibratory_conveyor": {"state": "on", "last_updated": "2025-07-25T21:30:00-04:00"}
},
"cameras": {
"camera1": {"status": "available", "is_recording": true}
},
"active_recordings": 1,
"uptime_seconds": 3600
}
```
#### Machine Status
```bash
# Get all machine states
curl http://localhost:8000/machines
# Response example:
{
"vibratory_conveyor": {
"name": "vibratory_conveyor",
"state": "on",
"last_updated": "2025-07-25T21:30:00-04:00",
"mqtt_topic": "vision/vibratory_conveyor/state"
}
}
```
#### Camera Status
```bash
# Get all camera statuses
curl http://localhost:8000/cameras
# Get specific camera status
curl http://localhost:8000/cameras/camera1
# Response example:
{
"name": "camera1",
"status": "available",
"is_recording": false,
"last_checked": "2025-07-25T21:30:00-04:00",
"device_info": {
"friendly_name": "Blower-Yield-Cam",
"serial_number": "054012620023"
}
}
```
#### Manual Recording Control
```bash
# Start recording manually
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"camera_name": "camera1", "filename": "manual_test.avi"}'
# Stop recording manually
curl -X POST http://localhost:8000/cameras/camera1/stop-recording
# Response example:
{
"success": true,
"message": "Recording started for camera1",
"filename": "camera1_manual_20250725_213000.avi"
}
```
#### Storage Management
```bash
# Get storage statistics
curl http://localhost:8000/storage/stats
# Get recording files list
curl -X POST http://localhost:8000/storage/files \
-H "Content-Type: application/json" \
-d '{"camera_name": "camera1", "limit": 10}'
# Cleanup old files
curl -X POST http://localhost:8000/storage/cleanup \
-H "Content-Type: application/json" \
-d '{"max_age_days": 30}'
```
### WebSocket Real-time Updates
```javascript
// Connect to WebSocket for real-time updates
const ws = new WebSocket('ws://localhost:8000/ws');
ws.onmessage = function(event) {
const update = JSON.parse(event.data);
console.log('Real-time update:', update);
// Handle different event types
if (update.event_type === 'machine_state_changed') {
console.log(`Machine ${update.data.machine_name} is now ${update.data.state}`);
} else if (update.event_type === 'recording_started') {
console.log(`Recording started: ${update.data.filename}`);
}
};
```
### Integration Examples
#### Python Integration
```python
import requests
import json
# System status check
response = requests.get('http://localhost:8000/system/status')
status = response.json()
print(f"System running: {status['system_started']}")
# Start recording
recording_data = {"camera_name": "camera1"}
response = requests.post(
'http://localhost:8000/cameras/camera1/start-recording',
headers={'Content-Type': 'application/json'},
data=json.dumps(recording_data)
)
result = response.json()
print(f"Recording started: {result['success']}")
```
#### JavaScript/React Integration
```javascript
// React hook for system status
import { useState, useEffect } from 'react';
function useSystemStatus() {
const [status, setStatus] = useState(null);
useEffect(() => {
const fetchStatus = async () => {
try {
const response = await fetch('http://localhost:8000/system/status');
const data = await response.json();
setStatus(data);
} catch (error) {
console.error('Failed to fetch status:', error);
}
};
fetchStatus();
const interval = setInterval(fetchStatus, 5000); // Update every 5 seconds
return () => clearInterval(interval);
}, []);
return status;
}
// Usage in component
function Dashboard() {
const systemStatus = useSystemStatus();
return (
<div>
<h1>USDA Vision System</h1>
{systemStatus && (
<div>
<p>Status: {systemStatus.system_started ? 'Running' : 'Stopped'}</p>
<p>MQTT: {systemStatus.mqtt_connected ? 'Connected' : 'Disconnected'}</p>
<p>Active Recordings: {systemStatus.active_recordings}</p>
</div>
)}
</div>
);
}
```
#### Supabase Integration
```javascript
// Store recording metadata in Supabase
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
// Function to sync recording data
async function syncRecordingData() {
try {
// Get recordings from vision system
const response = await fetch('http://localhost:8000/storage/files', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ limit: 100 })
});
const { files } = await response.json();
// Store in Supabase
for (const file of files) {
await supabase.from('recordings').upsert({
filename: file.filename,
camera_name: file.camera_name,
start_time: file.start_time,
duration_seconds: file.duration_seconds,
file_size_bytes: file.file_size_bytes
});
}
} catch (error) {
console.error('Sync failed:', error);
}
}
```
## 📁 File Organization
The system organizes recordings in a structured format:
```
storage/
├── camera1/
│ ├── camera1_recording_20250725_213000.avi
│ ├── camera1_recording_20250725_214500.avi
│ └── camera1_manual_20250725_220000.avi
├── camera2/
│ ├── camera2_recording_20250725_213005.avi
│ └── camera2_recording_20250725_214505.avi
└── file_index.json
```
### Filename Convention
- **Format**: `{camera_name}_{type}_{YYYYMMDD_HHMMSS}.avi`
- **Timezone**: Atlanta local time (EST/EDT)
- **Examples**:
- `camera1_recording_20250725_213000.avi` - Automatic recording
- `camera1_manual_20250725_220000.avi` - Manual recording
## 🔍 Monitoring and Logging
### Log Files
- **Main Log**: `usda_vision_system.log` (rotated automatically)
- **Console Output**: Colored, real-time status updates
- **Component Logs**: Separate log levels for different components
### Log Levels
```bash
# Debug mode (verbose)
python main.py --log-level DEBUG
# Info mode (default)
python main.py --log-level INFO
# Warning mode (errors and warnings only)
python main.py --log-level WARNING
```
### Performance Monitoring
The system tracks:
- Startup times
- Recording session metrics
- MQTT message processing rates
- Camera status check intervals
- API response times
### Health Checks
```bash
# API health check
curl http://localhost:8000/health
# System status
curl http://localhost:8000/system/status
# Time synchronization
python check_time.py
```
## 🚨 Troubleshooting
### Common Issues and Solutions
#### 1. Camera Not Found
**Problem**: `Camera discovery failed` or `No cameras found`
**Solutions**:
```bash
# Check camera connections
ping 192.168.1.165 # Replace with your camera IP
# 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('./camera_sdk')
import mvsdk
devices = mvsdk.CameraEnumerateDevice()
print(f'Found {len(devices)} cameras')
for i, dev in enumerate(devices):
print(f'Camera {i}: {dev.GetFriendlyName()}')
"
# Check camera permissions
sudo chmod 666 /dev/video* # If using USB cameras
```
#### 2. MQTT Connection Failed
**Problem**: `MQTT connection failed` or `MQTT disconnected`
**Solutions**:
```bash
# Test MQTT broker connectivity
ping 192.168.1.110 # Replace with your broker IP
telnet 192.168.1.110 1883 # Test port connectivity
# Test MQTT manually
mosquitto_sub -h 192.168.1.110 -t "vision/+/state" -v
# Check credentials in config.json
{
"mqtt": {
"broker_host": "192.168.1.110",
"broker_port": 1883,
"username": "your_username", # Add if required
"password": "your_password" # Add if required
}
}
# Check firewall
sudo ufw status
sudo ufw allow 1883 # Allow MQTT port
```
#### 3. Recording Fails
**Problem**: `Failed to start recording` or `Camera initialization failed`
**Solutions**:
```bash
# Check storage permissions
ls -la storage/
chmod 755 storage/
chmod 755 storage/camera*/
# Check available disk space
df -h storage/
# Test camera initialization
python -c "
import sys; sys.path.append('./camera_sdk')
import mvsdk
devices = mvsdk.CameraEnumerateDevice()
if devices:
try:
hCamera = mvsdk.CameraInit(devices[0], -1, -1)
print('Camera initialized successfully')
mvsdk.CameraUnInit(hCamera)
except Exception as e:
print(f'Camera init failed: {e}')
"
# Check if camera is busy
lsof | grep video # Check what's using cameras
```
#### 4. API Server Won't Start
**Problem**: `Failed to start API server` or `Port already in use`
**Solutions**:
```bash
# Check if port 8000 is in use
netstat -tlnp | grep 8000
lsof -i :8000
# Kill process using port 8000
sudo kill -9 $(lsof -t -i:8000)
# Use different port in config.json
{
"system": {
"api_port": 8001 # Change port
}
}
# Check firewall
sudo ufw allow 8000
```
#### 5. Time Synchronization Issues
**Problem**: `Time is NOT synchronized` or time drift warnings
**Solutions**:
```bash
# Check time sync status
timedatectl status
# Force time sync
sudo systemctl restart systemd-timesyncd
sudo timedatectl set-ntp true
# Manual time sync
sudo ntpdate -s time.nist.gov
# Check timezone
timedatectl list-timezones | grep New_York
sudo timedatectl set-timezone America/New_York
# Verify with system
python check_time.py
```
#### 6. Storage Issues
**Problem**: `Permission denied` or `No space left on device`
**Solutions**:
```bash
# Check disk space
df -h
du -sh storage/
# Fix permissions
sudo chown -R $USER:$USER storage/
chmod -R 755 storage/
# Clean up old files
python -c "
from usda_vision_system.storage.manager import StorageManager
from usda_vision_system.core.config import Config
from usda_vision_system.core.state_manager import StateManager
config = Config()
state_manager = StateManager()
storage = StorageManager(config, state_manager)
result = storage.cleanup_old_files(7) # Clean files older than 7 days
print(f'Cleaned {result[\"files_removed\"]} files')
"
```
### Debug Mode
Enable debug mode for detailed troubleshooting:
```bash
# Start with debug logging
python main.py --log-level DEBUG
# Check specific component logs
tail -f usda_vision_system.log | grep "camera"
tail -f usda_vision_system.log | grep "mqtt"
tail -f usda_vision_system.log | grep "ERROR"
```
### System Health Check
Run comprehensive system diagnostics:
```bash
# Full system test
python test_system.py
# Individual component tests
python test_timezone.py
python check_time.py
# API health check
curl http://localhost:8000/health
curl http://localhost:8000/system/status
```
### Log Analysis
Common log patterns to look for:
```bash
# MQTT connection issues
grep "MQTT" usda_vision_system.log | grep -E "(ERROR|WARNING)"
# Camera problems
grep "camera" usda_vision_system.log | grep -E "(ERROR|failed)"
# Recording issues
grep "recording" usda_vision_system.log | grep -E "(ERROR|failed)"
# Time sync problems
grep -E "(time|sync)" usda_vision_system.log | grep -E "(ERROR|WARNING)"
```
### Getting Help
If you encounter issues not covered here:
1. **Check Logs**: Always start with `usda_vision_system.log`
2. **Run Tests**: Use `python test_system.py` to identify problems
3. **Check Configuration**: Verify `config.json` settings
4. **Test Components**: Use individual test scripts
5. **Check Dependencies**: Ensure all required packages are installed
### Performance Optimization
For better performance:
```bash
# Reduce camera check interval (in config.json)
{
"system": {
"camera_check_interval_seconds": 5 # Increase from 2 to 5
}
}
# Optimize recording settings
{
"cameras": [
{
"target_fps": 2.0, # Reduce FPS for smaller files
"exposure_ms": 2.0 # Adjust exposure as needed
}
]
}
# Enable log rotation
{
"system": {
"log_level": "INFO" # Reduce from DEBUG to INFO
}
}
```
## 🤝 Contributing
### Development Setup
```bash
# Clone repository
git clone https://github.com/your-username/USDA-Vision-Cameras.git
cd USDA-Vision-Cameras
# Install development dependencies
uv sync --dev
# Run tests
python test_system.py
python test_timezone.py
```
### Project Structure
```
usda_vision_system/
├── core/ # Core functionality (config, state, events, logging)
├── mqtt/ # MQTT client and message handlers
├── camera/ # Camera management, monitoring, recording
├── storage/ # File management and organization
├── api/ # FastAPI server and WebSocket support
└── main.py # Application coordinator
```
### Adding Features
1. **New Camera Types**: Extend `camera/recorder.py`
2. **New MQTT Topics**: Update `config.json` and `mqtt/handlers.py`
3. **New API Endpoints**: Add to `api/server.py`
4. **New Events**: Define in `core/events.py`
## 📄 License
This project is developed for USDA research purposes.
## 🆘 Support
For technical support:
1. Check the troubleshooting section above
2. Review logs in `usda_vision_system.log`
3. Run system diagnostics with `python test_system.py`
4. Check API health at `http://localhost:8000/health`
---
**System Status**: ✅ **READY FOR PRODUCTION**
**Time Sync**: ✅ **ATLANTA, GEORGIA (EDT/EST)**
**API Server**: ✅ **http://localhost:8000**
**Documentation**: ✅ **COMPLETE**

View File

@@ -0,0 +1,240 @@
# 🎥 USDA Vision Camera Live Streaming Guide
This guide explains how to use the new live preview streaming functionality that allows you to view camera feeds in real-time without blocking recording operations.
## 🌟 Key Features
- **Non-blocking streaming**: Live preview doesn't interfere with recording
- **Separate camera connections**: Streaming uses independent camera instances
- **MJPEG streaming**: Standard web-compatible video streaming
- **Multiple concurrent viewers**: Multiple browsers can view the same stream
- **REST API control**: Start/stop streaming via API endpoints
- **Web interface**: Ready-to-use HTML interface for live preview
## 🏗️ Architecture
The streaming system creates separate camera connections for preview that are independent from recording:
```
Camera Hardware
├── Recording Connection (CameraRecorder)
│ ├── Used for video file recording
│ ├── Triggered by MQTT machine states
│ └── High quality, full FPS
└── Streaming Connection (CameraStreamer)
├── Used for live preview
├── Controlled via API endpoints
└── Optimized for web viewing (lower FPS, JPEG compression)
```
## 🚀 Quick Start
### 1. Start the System
```bash
python main.py
```
### 2. Open the Web Interface
Open `camera_preview.html` in your browser and click "Start Stream" for any camera.
### 3. API Usage
```bash
# Start streaming for camera1
curl -X POST http://localhost:8000/cameras/camera1/start-stream
# View live stream (open in browser)
http://localhost:8000/cameras/camera1/stream
# Stop streaming
curl -X POST http://localhost:8000/cameras/camera1/stop-stream
```
## 📡 API Endpoints
### Start Streaming
```http
POST /cameras/{camera_name}/start-stream
```
**Response:**
```json
{
"success": true,
"message": "Started streaming for camera camera1"
}
```
### Stop Streaming
```http
POST /cameras/{camera_name}/stop-stream
```
**Response:**
```json
{
"success": true,
"message": "Stopped streaming for camera camera1"
}
```
### Live Stream (MJPEG)
```http
GET /cameras/{camera_name}/stream
```
**Response:** Multipart MJPEG stream
**Content-Type:** `multipart/x-mixed-replace; boundary=frame`
## 🌐 Web Interface Usage
The included `camera_preview.html` provides a complete web interface:
1. **Camera Grid**: Shows all configured cameras
2. **Stream Controls**: Start/Stop/Refresh buttons for each camera
3. **Live Preview**: Real-time video feed display
4. **Status Information**: System and camera status
5. **Responsive Design**: Works on desktop and mobile
### Features:
- ✅ Real-time camera status
- ✅ One-click stream start/stop
- ✅ Automatic stream refresh
- ✅ System health monitoring
- ✅ Error handling and status messages
## 🔧 Technical Details
### Camera Streamer Configuration
- **Preview FPS**: 10 FPS (configurable)
- **JPEG Quality**: 70% (configurable)
- **Frame Buffer**: 5 frames (prevents memory buildup)
- **Timeout**: 200ms per frame capture
### Memory Management
- Automatic frame buffer cleanup
- Queue-based frame management
- Proper camera resource cleanup on stop
### Thread Safety
- Thread-safe streaming operations
- Independent from recording threads
- Proper synchronization with locks
## 🧪 Testing
### Run the Test Script
```bash
python test_streaming.py
```
This will test:
- ✅ API endpoint functionality
- ✅ Stream start/stop operations
- ✅ Concurrent recording and streaming
- ✅ Error handling
### Manual Testing
1. Start the system: `python main.py`
2. Open `camera_preview.html` in browser
3. Start streaming for a camera
4. Trigger recording via MQTT or manual API
5. Verify both work simultaneously
## 🔄 Concurrent Operations
The system supports these concurrent operations:
| Operation | Recording | Streaming | Notes |
|-----------|-----------|-----------|-------|
| Recording Only | ✅ | ❌ | Normal operation |
| Streaming Only | ❌ | ✅ | Preview without recording |
| Both Concurrent | ✅ | ✅ | **Independent connections** |
### Example: Concurrent Usage
```bash
# Start streaming
curl -X POST http://localhost:8000/cameras/camera1/start-stream
# Start recording (while streaming continues)
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"filename": "test_recording.avi"}'
# Both operations run independently!
```
## 🛠️ Configuration
### Stream Settings (in CameraStreamer)
```python
self.preview_fps = 10.0 # Lower FPS for preview
self.preview_quality = 70 # JPEG quality (1-100)
self._frame_queue.maxsize = 5 # Frame buffer size
```
### Camera Settings
The streamer uses the same camera configuration as recording:
- Exposure time from `camera_config.exposure_ms`
- Gain from `camera_config.gain`
- Optimized trigger mode for continuous streaming
## 🚨 Important Notes
### Camera Access Patterns
- **Recording**: Blocks camera during active recording
- **Streaming**: Uses separate connection, doesn't block
- **Health Checks**: Brief, non-blocking camera tests
- **Multiple Streams**: Multiple browsers can view same stream
### Performance Considerations
- Streaming uses additional CPU/memory resources
- Lower preview FPS reduces system load
- JPEG compression reduces bandwidth usage
- Frame queue prevents memory buildup
### Error Handling
- Automatic camera resource cleanup
- Graceful handling of camera disconnections
- Stream auto-restart capabilities
- Detailed error logging
## 🔍 Troubleshooting
### Stream Not Starting
1. Check camera availability: `GET /cameras`
2. Verify camera not in error state
3. Check system logs for camera initialization errors
4. Try camera reconnection: `POST /cameras/{name}/reconnect`
### Poor Stream Quality
1. Adjust `preview_quality` setting (higher = better quality)
2. Increase `preview_fps` for smoother video
3. Check network bandwidth
4. Verify camera exposure/gain settings
### Browser Issues
1. Try different browser (Chrome/Firefox recommended)
2. Check browser console for JavaScript errors
3. Verify CORS settings in API server
4. Clear browser cache and refresh
## 📈 Future Enhancements
Potential improvements for the streaming system:
- 🔄 WebRTC support for lower latency
- 📱 Mobile app integration
- 🎛️ Real-time camera setting adjustments
- 📊 Stream analytics and monitoring
- 🔐 Authentication and access control
- 🌐 Multi-camera synchronized viewing
## 📞 Support
For issues with streaming functionality:
1. Check the system logs: `usda_vision_system.log`
2. Run the test script: `python test_streaming.py`
3. Verify API health: `http://localhost:8000/health`
4. Check camera status: `http://localhost:8000/cameras`
---
**✅ Live streaming is now ready for production use!**

View File

@@ -0,0 +1,367 @@
/**
* TypeScript definitions for USDA Vision Camera System API
*
* This file provides complete type definitions for AI assistants
* to integrate the camera streaming functionality into React/TypeScript projects.
*/
// =============================================================================
// BASE CONFIGURATION
// =============================================================================
export interface ApiConfig {
baseUrl: string;
timeout?: number;
refreshInterval?: number;
}
export const defaultApiConfig: ApiConfig = {
baseUrl: 'http://vision:8000', // Production default, change to 'http://localhost:8000' for development
timeout: 10000,
refreshInterval: 30000,
};
// =============================================================================
// CAMERA TYPES
// =============================================================================
export interface CameraDeviceInfo {
friendly_name?: string;
port_type?: string;
serial_number?: string;
device_index?: number;
error?: string;
}
export interface CameraInfo {
name: string;
status: 'connected' | 'disconnected' | 'error' | 'not_found' | 'available';
is_recording: boolean;
last_checked: string; // ISO date string
last_error?: string | null;
device_info?: CameraDeviceInfo;
current_recording_file?: string | null;
recording_start_time?: string | null; // ISO date string
}
export interface CameraListResponse {
[cameraName: string]: CameraInfo;
}
// =============================================================================
// STREAMING TYPES
// =============================================================================
export interface StreamStartRequest {
// No body required - camera name is in URL path
}
export interface StreamStartResponse {
success: boolean;
message: string;
}
export interface StreamStopRequest {
// No body required - camera name is in URL path
}
export interface StreamStopResponse {
success: boolean;
message: string;
}
export interface StreamStatus {
isStreaming: boolean;
streamUrl?: string;
error?: string;
}
// =============================================================================
// RECORDING TYPES
// =============================================================================
export interface StartRecordingRequest {
filename?: string;
exposure_ms?: number;
gain?: number;
fps?: number;
}
export interface StartRecordingResponse {
success: boolean;
message: string;
filename?: string;
}
export interface StopRecordingResponse {
success: boolean;
message: string;
}
// =============================================================================
// SYSTEM TYPES
// =============================================================================
export interface SystemStatusResponse {
status: string;
uptime: string;
api_server_running: boolean;
camera_manager_running: boolean;
mqtt_client_connected: boolean;
total_cameras: number;
active_recordings: number;
active_streams?: number;
}
export interface HealthResponse {
status: 'healthy' | 'unhealthy';
timestamp: string;
}
// =============================================================================
// ERROR TYPES
// =============================================================================
export interface ApiError {
detail: string;
status_code?: number;
}
export interface StreamError extends Error {
type: 'network' | 'api' | 'stream' | 'timeout';
cameraName: string;
originalError?: Error;
}
// =============================================================================
// HOOK TYPES
// =============================================================================
export interface UseCameraStreamResult {
isStreaming: boolean;
loading: boolean;
error: string | null;
startStream: () => Promise<{ success: boolean; error?: string }>;
stopStream: () => Promise<{ success: boolean; error?: string }>;
getStreamUrl: () => string;
refreshStream: () => void;
}
export interface UseCameraListResult {
cameras: CameraListResponse;
loading: boolean;
error: string | null;
refreshCameras: () => Promise<void>;
}
export interface UseCameraRecordingResult {
isRecording: boolean;
loading: boolean;
error: string | null;
currentFile: string | null;
startRecording: (options?: StartRecordingRequest) => Promise<{ success: boolean; error?: string }>;
stopRecording: () => Promise<{ success: boolean; error?: string }>;
}
// =============================================================================
// COMPONENT PROPS TYPES
// =============================================================================
export interface CameraStreamProps {
cameraName: string;
apiConfig?: ApiConfig;
autoStart?: boolean;
onStreamStart?: (cameraName: string) => void;
onStreamStop?: (cameraName: string) => void;
onError?: (error: StreamError) => void;
className?: string;
style?: React.CSSProperties;
}
export interface CameraDashboardProps {
apiConfig?: ApiConfig;
cameras?: string[]; // If provided, only show these cameras
showRecordingControls?: boolean;
showStreamingControls?: boolean;
refreshInterval?: number;
onCameraSelect?: (cameraName: string) => void;
className?: string;
}
export interface CameraControlsProps {
cameraName: string;
apiConfig?: ApiConfig;
showRecording?: boolean;
showStreaming?: boolean;
onAction?: (action: 'start-stream' | 'stop-stream' | 'start-recording' | 'stop-recording', cameraName: string) => void;
}
// =============================================================================
// API CLIENT TYPES
// =============================================================================
export interface CameraApiClient {
// System endpoints
getHealth(): Promise<HealthResponse>;
getSystemStatus(): Promise<SystemStatusResponse>;
// Camera endpoints
getCameras(): Promise<CameraListResponse>;
getCameraStatus(cameraName: string): Promise<CameraInfo>;
testCameraConnection(cameraName: string): Promise<{ success: boolean; message: string }>;
// Streaming endpoints
startStream(cameraName: string): Promise<StreamStartResponse>;
stopStream(cameraName: string): Promise<StreamStopResponse>;
getStreamUrl(cameraName: string): string;
// Recording endpoints
startRecording(cameraName: string, options?: StartRecordingRequest): Promise<StartRecordingResponse>;
stopRecording(cameraName: string): Promise<StopRecordingResponse>;
}
// =============================================================================
// UTILITY TYPES
// =============================================================================
export type CameraAction = 'start-stream' | 'stop-stream' | 'start-recording' | 'stop-recording' | 'test-connection';
export interface CameraActionResult {
success: boolean;
message: string;
error?: string;
}
export interface StreamingState {
[cameraName: string]: {
isStreaming: boolean;
isLoading: boolean;
error: string | null;
lastStarted?: Date;
};
}
export interface RecordingState {
[cameraName: string]: {
isRecording: boolean;
isLoading: boolean;
error: string | null;
currentFile: string | null;
startTime?: Date;
};
}
// =============================================================================
// EVENT TYPES
// =============================================================================
export interface CameraEvent {
type: 'stream-started' | 'stream-stopped' | 'stream-error' | 'recording-started' | 'recording-stopped' | 'recording-error';
cameraName: string;
timestamp: Date;
data?: any;
}
export type CameraEventHandler = (event: CameraEvent) => void;
// =============================================================================
// CONFIGURATION TYPES
// =============================================================================
export interface StreamConfig {
fps: number;
quality: number; // 1-100
timeout: number;
retryAttempts: number;
retryDelay: number;
}
export interface CameraStreamConfig extends StreamConfig {
cameraName: string;
autoReconnect: boolean;
maxReconnectAttempts: number;
}
// =============================================================================
// CONTEXT TYPES (for React Context)
// =============================================================================
export interface CameraContextValue {
cameras: CameraListResponse;
streamingState: StreamingState;
recordingState: RecordingState;
apiClient: CameraApiClient;
// Actions
startStream: (cameraName: string) => Promise<CameraActionResult>;
stopStream: (cameraName: string) => Promise<CameraActionResult>;
startRecording: (cameraName: string, options?: StartRecordingRequest) => Promise<CameraActionResult>;
stopRecording: (cameraName: string) => Promise<CameraActionResult>;
refreshCameras: () => Promise<void>;
// State
loading: boolean;
error: string | null;
}
// =============================================================================
// EXAMPLE USAGE TYPES
// =============================================================================
/**
* Example usage in React component:
*
* ```typescript
* import { CameraStreamProps, UseCameraStreamResult } from './camera-api.types';
*
* const CameraStream: React.FC<CameraStreamProps> = ({
* cameraName,
* apiConfig = defaultApiConfig,
* autoStart = false,
* onStreamStart,
* onStreamStop,
* onError
* }) => {
* const {
* isStreaming,
* loading,
* error,
* startStream,
* stopStream,
* getStreamUrl
* }: UseCameraStreamResult = useCameraStream(cameraName, apiConfig);
*
* // Component implementation...
* };
* ```
*/
/**
* Example API client usage:
*
* ```typescript
* const apiClient: CameraApiClient = new CameraApiClientImpl(defaultApiConfig);
*
* // Start streaming
* const result = await apiClient.startStream('camera1');
* if (result.success) {
* const streamUrl = apiClient.getStreamUrl('camera1');
* // Use streamUrl in img tag
* }
* ```
*/
/**
* Example hook usage:
*
* ```typescript
* const MyComponent = () => {
* const { cameras, loading, error, refreshCameras } = useCameraList();
* const { isStreaming, startStream, stopStream } = useCameraStream('camera1');
*
* // Component logic...
* };
* ```
*/
export default {};

View File

@@ -0,0 +1,336 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>USDA Vision Camera Live Preview</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.camera-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.camera-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
background-color: #fafafa;
}
.camera-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
color: #333;
}
.camera-stream {
width: 100%;
max-width: 100%;
height: auto;
border: 2px solid #ddd;
border-radius: 4px;
background-color: #000;
min-height: 200px;
display: block;
}
.camera-controls {
margin-top: 10px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #545b62;
}
.btn-success {
background-color: #28a745;
color: white;
}
.btn-success:hover {
background-color: #1e7e34;
}
.btn-danger {
background-color: #dc3545;
color: white;
}
.btn-danger:hover {
background-color: #c82333;
}
.status {
margin-top: 10px;
padding: 8px;
border-radius: 4px;
font-size: 14px;
}
.status-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status-error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status-info {
background-color: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.system-info {
margin-top: 30px;
padding: 15px;
background-color: #e9ecef;
border-radius: 4px;
}
.system-info h3 {
margin-top: 0;
color: #495057;
}
.api-info {
font-family: monospace;
font-size: 12px;
color: #6c757d;
}
</style>
</head>
<body>
<div class="container">
<h1>🎥 USDA Vision Camera Live Preview</h1>
<div class="camera-grid" id="cameraGrid">
<!-- Camera cards will be dynamically generated -->
</div>
<div class="system-info">
<h3>📡 System Information</h3>
<div id="systemStatus">Loading system status...</div>
<h3>🔗 API Endpoints</h3>
<div class="api-info">
<p><strong>Live Stream:</strong> GET /cameras/{camera_name}/stream</p>
<p><strong>Start Stream:</strong> POST /cameras/{camera_name}/start-stream</p>
<p><strong>Stop Stream:</strong> POST /cameras/{camera_name}/stop-stream</p>
<p><strong>Camera Status:</strong> GET /cameras</p>
</div>
</div>
</div>
<script>
const API_BASE = 'http://vision:8000';
let cameras = {};
// Initialize the page
async function init() {
await loadCameras();
await loadSystemStatus();
// Refresh status every 5 seconds
setInterval(loadSystemStatus, 5000);
}
// Load camera information
async function loadCameras() {
try {
const response = await fetch(`${API_BASE}/cameras`);
const data = await response.json();
cameras = data;
renderCameras();
} catch (error) {
console.error('Error loading cameras:', error);
showError('Failed to load camera information');
}
}
// Load system status
async function loadSystemStatus() {
try {
const response = await fetch(`${API_BASE}/system/status`);
const data = await response.json();
const statusDiv = document.getElementById('systemStatus');
statusDiv.innerHTML = `
<p><strong>System:</strong> ${data.status}</p>
<p><strong>Uptime:</strong> ${data.uptime}</p>
<p><strong>API Server:</strong> ${data.api_server_running ? '✅ Running' : '❌ Stopped'}</p>
<p><strong>Camera Manager:</strong> ${data.camera_manager_running ? '✅ Running' : '❌ Stopped'}</p>
<p><strong>MQTT Client:</strong> ${data.mqtt_client_connected ? '✅ Connected' : '❌ Disconnected'}</p>
`;
} catch (error) {
console.error('Error loading system status:', error);
document.getElementById('systemStatus').innerHTML = '<p style="color: red;">Failed to load system status</p>';
}
}
// Render camera cards
function renderCameras() {
const grid = document.getElementById('cameraGrid');
grid.innerHTML = '';
for (const [cameraName, cameraInfo] of Object.entries(cameras)) {
const card = createCameraCard(cameraName, cameraInfo);
grid.appendChild(card);
}
}
// Create a camera card
function createCameraCard(cameraName, cameraInfo) {
const card = document.createElement('div');
card.className = 'camera-card';
card.innerHTML = `
<div class="camera-title">${cameraName}</div>
<img class="camera-stream" id="stream-${cameraName}"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZGRkIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPk5vIFN0cmVhbTwvdGV4dD48L3N2Zz4="
alt="Camera Stream">
<div class="camera-controls">
<button class="btn btn-success" onclick="startStream('${cameraName}')">Start Stream</button>
<button class="btn btn-danger" onclick="stopStream('${cameraName}')">Stop Stream</button>
<button class="btn btn-secondary" onclick="refreshStream('${cameraName}')">Refresh</button>
</div>
<div class="status status-info" id="status-${cameraName}">
Status: ${cameraInfo.status} | Recording: ${cameraInfo.is_recording ? 'Yes' : 'No'}
</div>
`;
return card;
}
// Start streaming for a camera
async function startStream(cameraName) {
try {
updateStatus(cameraName, 'Starting stream...', 'info');
// Start the stream
const response = await fetch(`${API_BASE}/cameras/${cameraName}/start-stream`, {
method: 'POST'
});
if (response.ok) {
// Set the stream source
const streamImg = document.getElementById(`stream-${cameraName}`);
streamImg.src = `${API_BASE}/cameras/${cameraName}/stream?t=${Date.now()}`;
updateStatus(cameraName, 'Stream started successfully', 'success');
} else {
const error = await response.text();
updateStatus(cameraName, `Failed to start stream: ${error}`, 'error');
}
} catch (error) {
console.error('Error starting stream:', error);
updateStatus(cameraName, `Error starting stream: ${error.message}`, 'error');
}
}
// Stop streaming for a camera
async function stopStream(cameraName) {
try {
updateStatus(cameraName, 'Stopping stream...', 'info');
const response = await fetch(`${API_BASE}/cameras/${cameraName}/stop-stream`, {
method: 'POST'
});
if (response.ok) {
// Clear the stream source
const streamImg = document.getElementById(`stream-${cameraName}`);
streamImg.src = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZGRkIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPk5vIFN0cmVhbTwvdGV4dD48L3N2Zz4=";
updateStatus(cameraName, 'Stream stopped successfully', 'success');
} else {
const error = await response.text();
updateStatus(cameraName, `Failed to stop stream: ${error}`, 'error');
}
} catch (error) {
console.error('Error stopping stream:', error);
updateStatus(cameraName, `Error stopping stream: ${error.message}`, 'error');
}
}
// Refresh stream for a camera
function refreshStream(cameraName) {
const streamImg = document.getElementById(`stream-${cameraName}`);
if (streamImg.src.includes('/stream')) {
streamImg.src = `${API_BASE}/cameras/${cameraName}/stream?t=${Date.now()}`;
updateStatus(cameraName, 'Stream refreshed', 'info');
} else {
updateStatus(cameraName, 'No active stream to refresh', 'error');
}
}
// Update status message
function updateStatus(cameraName, message, type) {
const statusDiv = document.getElementById(`status-${cameraName}`);
statusDiv.className = `status status-${type}`;
statusDiv.textContent = message;
}
// Show error message
function showError(message) {
alert(`Error: ${message}`);
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>

View File

@@ -0,0 +1,175 @@
# API Changes Summary: Camera Settings and Filename Handling
## Overview
Enhanced the `POST /cameras/{camera_name}/start-recording` API endpoint to accept optional camera settings (shutter speed/exposure, gain, and fps) and ensure all filenames have datetime prefixes.
## Changes Made
### 1. API Models (`usda_vision_system/api/models.py`)
- **Enhanced `StartRecordingRequest`** to include optional parameters:
- `exposure_ms: Optional[float]` - Exposure time in milliseconds
- `gain: Optional[float]` - Camera gain value
- `fps: Optional[float]` - Target frames per second
### 2. Camera Recorder (`usda_vision_system/camera/recorder.py`)
- **Added `update_camera_settings()` method** to dynamically update camera settings:
- Updates exposure time using `mvsdk.CameraSetExposureTime()`
- Updates gain using `mvsdk.CameraSetAnalogGain()`
- Updates target FPS in camera configuration
- Logs all setting changes
- Returns boolean indicating success/failure
### 3. Camera Manager (`usda_vision_system/camera/manager.py`)
- **Enhanced `manual_start_recording()` method** to accept new parameters:
- Added optional `exposure_ms`, `gain`, and `fps` parameters
- Calls `update_camera_settings()` if any settings are provided
- **Automatic datetime prefix**: Always prepends timestamp to filename
- If custom filename provided: `{timestamp}_{custom_filename}`
- If no filename provided: `{camera_name}_manual_{timestamp}.avi`
### 4. API Server (`usda_vision_system/api/server.py`)
- **Updated start-recording endpoint** to:
- Pass new camera settings to camera manager
- Handle filename response with datetime prefix
- Maintain backward compatibility with existing requests
### 5. API Tests (`api-tests.http`)
- **Added comprehensive test examples**:
- Basic recording (existing functionality)
- Recording with camera settings
- Recording with settings only (no filename)
- Different parameter combinations
## Usage Examples
### Basic Recording (unchanged)
```http
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
"camera_name": "camera1",
"filename": "test.avi"
}
```
**Result**: File saved as `20241223_143022_test.avi`
### Recording with Camera Settings
```http
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
"camera_name": "camera1",
"filename": "high_quality.avi",
"exposure_ms": 2.0,
"gain": 4.0,
"fps": 5.0
}
```
**Result**:
- Camera settings updated before recording
- File saved as `20241223_143022_high_quality.avi`
### Maximum FPS Recording
```http
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
"camera_name": "camera1",
"filename": "max_speed.avi",
"exposure_ms": 0.1,
"gain": 1.0,
"fps": 0
}
```
**Result**:
- Camera captures at maximum possible speed (no delay between frames)
- Video file saved with 30 FPS metadata for proper playback
- Actual capture rate depends on camera hardware and exposure settings
### Settings Only (no filename)
```http
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
"camera_name": "camera1",
"exposure_ms": 1.5,
"gain": 3.0,
"fps": 7.0
}
```
**Result**:
- Camera settings updated
- File saved as `camera1_manual_20241223_143022.avi`
## Key Features
### 1. **Backward Compatibility**
- All existing API calls continue to work unchanged
- New parameters are optional
- Default behavior preserved when no settings provided
### 2. **Automatic Datetime Prefix**
- **ALL filenames now have datetime prefix** regardless of what's sent
- Format: `YYYYMMDD_HHMMSS_` (Atlanta timezone)
- Ensures unique filenames and chronological ordering
### 3. **Dynamic Camera Settings**
- Settings can be changed per recording without restarting system
- Based on proven implementation from `old tests/camera_video_recorder.py`
- Proper error handling and logging
### 4. **Maximum FPS Capture**
- **`fps: 0`** = Capture at maximum possible speed (no delay between frames)
- **`fps > 0`** = Capture at specified frame rate with controlled timing
- **`fps` omitted** = Uses camera config default (usually 3.0 fps)
- Video files saved with 30 FPS metadata when fps=0 for proper playback
### 5. **Parameter Validation**
- Uses Pydantic models for automatic validation
- Optional parameters with proper type checking
- Descriptive field documentation
## Testing
Run the test script to verify functionality:
```bash
# Start the system first
python main.py
# In another terminal, run tests
python test_api_changes.py
```
The test script verifies:
- Basic recording functionality
- Camera settings application
- Filename datetime prefix handling
- API response accuracy
## Implementation Notes
### Camera Settings Mapping
- **Exposure**: Converted from milliseconds to microseconds for SDK
- **Gain**: Converted to camera units (multiplied by 100)
- **FPS**: Stored in camera config, used by recording loop
### Error Handling
- Settings update failures are logged but don't prevent recording
- Invalid camera names return appropriate HTTP errors
- Camera initialization failures are handled gracefully
### Filename Generation
- Uses `format_filename_timestamp()` from timezone utilities
- Ensures Atlanta timezone consistency
- Handles both custom and auto-generated filenames
## Similar to Old Implementation
The camera settings functionality mirrors the proven approach in `old tests/camera_video_recorder.py`:
- Same parameter names and ranges
- Same SDK function calls
- Same conversion factors
- Proven to work with the camera hardware

View File

@@ -0,0 +1,627 @@
# 🚀 USDA Vision Camera System - Complete API Documentation
This document provides comprehensive documentation for all API endpoints in the USDA Vision Camera System, including recent enhancements and new features.
## 📋 Table of Contents
- [🔧 System Status & Health](#-system-status--health)
- [📷 Camera Management](#-camera-management)
- [🎥 Recording Control](#-recording-control)
- [🤖 Auto-Recording Management](#-auto-recording-management)
- [🎛️ Camera Configuration](#-camera-configuration)
- [📡 MQTT & Machine Status](#-mqtt--machine-status)
- [💾 Storage & File Management](#-storage--file-management)
- [🔄 Camera Recovery & Diagnostics](#-camera-recovery--diagnostics)
- [📺 Live Streaming](#-live-streaming)
- [🌐 WebSocket Real-time Updates](#-websocket-real-time-updates)
## 🔧 System Status & Health
### Get System Status
```http
GET /system/status
```
**Response**: `SystemStatusResponse`
```json
{
"system_started": true,
"mqtt_connected": true,
"last_mqtt_message": "2024-01-15T10:30:00Z",
"machines": {
"vibratory_conveyor": {
"name": "vibratory_conveyor",
"state": "ON",
"last_updated": "2024-01-15T10:30:00Z"
}
},
"cameras": {
"camera1": {
"name": "camera1",
"status": "ACTIVE",
"is_recording": false,
"auto_recording_enabled": true
}
},
"active_recordings": 0,
"total_recordings": 15,
"uptime_seconds": 3600.5
}
```
### Health Check
```http
GET /health
```
**Response**: Simple health status
```json
{
"status": "healthy",
"timestamp": "2024-01-15T10:30:00Z"
}
```
## 📷 Camera Management
### Get All Cameras
```http
GET /cameras
```
**Response**: `Dict[str, CameraStatusResponse]`
### Get Specific Camera Status
```http
GET /cameras/{camera_name}/status
```
**Response**: `CameraStatusResponse`
```json
{
"name": "camera1",
"status": "ACTIVE",
"is_recording": false,
"last_checked": "2024-01-15T10:30:00Z",
"last_error": null,
"device_info": {
"model": "GigE Camera",
"serial": "12345"
},
"current_recording_file": null,
"recording_start_time": null,
"auto_recording_enabled": true,
"auto_recording_active": false,
"auto_recording_failure_count": 0,
"auto_recording_last_attempt": null,
"auto_recording_last_error": null
}
```
## 🎥 Recording Control
### Start Recording
```http
POST /cameras/{camera_name}/start-recording
Content-Type: application/json
{
"filename": "test_recording.avi",
"exposure_ms": 2.0,
"gain": 4.0,
"fps": 5.0
}
```
**Request Model**: `StartRecordingRequest`
- `filename` (optional): Custom filename (datetime prefix will be added automatically)
- `exposure_ms` (optional): Exposure time in milliseconds
- `gain` (optional): Camera gain value
- `fps` (optional): Target frames per second
**Response**: `StartRecordingResponse`
```json
{
"success": true,
"message": "Recording started for camera1",
"filename": "20240115_103000_test_recording.avi"
}
```
**Key Features**:
-**Automatic datetime prefix**: All filenames get `YYYYMMDD_HHMMSS_` prefix
-**Dynamic camera settings**: Adjust exposure, gain, and FPS per recording
-**Backward compatibility**: All existing API calls work unchanged
### Stop Recording
```http
POST /cameras/{camera_name}/stop-recording
```
**Response**: `StopRecordingResponse`
```json
{
"success": true,
"message": "Recording stopped for camera1",
"duration_seconds": 45.2
}
```
## 🤖 Auto-Recording Management
### Enable Auto-Recording for Camera
```http
POST /cameras/{camera_name}/auto-recording/enable
```
**Response**: `AutoRecordingConfigResponse`
```json
{
"success": true,
"message": "Auto-recording enabled for camera1",
"camera_name": "camera1",
"enabled": true
}
```
### Disable Auto-Recording for Camera
```http
POST /cameras/{camera_name}/auto-recording/disable
```
**Response**: `AutoRecordingConfigResponse`
### Get Auto-Recording Status
```http
GET /auto-recording/status
```
**Response**: `AutoRecordingStatusResponse`
```json
{
"running": true,
"auto_recording_enabled": true,
"retry_queue": {},
"enabled_cameras": ["camera1", "camera2"]
}
```
**Auto-Recording Features**:
- 🤖 **MQTT-triggered recording**: Automatically starts/stops based on machine state
- 🔄 **Retry logic**: Failed recordings are retried with configurable delays
- 📊 **Per-camera control**: Enable/disable auto-recording individually
- 📈 **Status tracking**: Monitor failure counts and last attempts
## 🎛️ Camera Configuration
### Get Camera Configuration
```http
GET /cameras/{camera_name}/config
```
**Response**: `CameraConfigResponse`
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1",
"enabled": true,
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 3.0,
"auto_start_recording_enabled": true,
"sharpness": 120,
"contrast": 110,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"denoise_3d_enabled": false,
"auto_white_balance": true,
"color_temperature_preset": 0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
```
### Update Camera Configuration
```http
PUT /cameras/{camera_name}/config
Content-Type: application/json
{
"exposure_ms": 2.0,
"gain": 4.0,
"target_fps": 5.0,
"sharpness": 130
}
```
### Apply Configuration (Restart Required)
```http
POST /cameras/{camera_name}/apply-config
```
**Configuration Categories**:
-**Real-time**: `exposure_ms`, `gain`, `target_fps`, `sharpness`, `contrast`, etc.
- ⚠️ **Restart required**: `noise_filter_enabled`, `denoise_3d_enabled`, `bit_depth`
For detailed configuration options, see [Camera Configuration API Guide](api/CAMERA_CONFIG_API.md).
## 📡 MQTT & Machine Status
### Get All Machines
```http
GET /machines
```
**Response**: `Dict[str, MachineStatusResponse]`
### Get MQTT Status
```http
GET /mqtt/status
```
**Response**: `MQTTStatusResponse`
```json
{
"connected": true,
"broker_host": "192.168.1.110",
"broker_port": 1883,
"subscribed_topics": ["vibratory_conveyor", "blower_separator"],
"last_message_time": "2024-01-15T10:30:00Z",
"message_count": 1250,
"error_count": 2,
"uptime_seconds": 3600.5
}
```
### Get MQTT Events History
```http
GET /mqtt/events?limit=10
```
**Response**: `MQTTEventsHistoryResponse`
```json
{
"events": [
{
"machine_name": "vibratory_conveyor",
"topic": "vibratory_conveyor",
"payload": "ON",
"normalized_state": "ON",
"timestamp": "2024-01-15T10:30:00Z",
"message_number": 1250
}
],
"total_events": 1250,
"last_updated": "2024-01-15T10:30:00Z"
}
```
## 💾 Storage & File Management
### Get Storage Statistics
```http
GET /storage/stats
```
**Response**: `StorageStatsResponse`
```json
{
"base_path": "/storage",
"total_files": 150,
"total_size_bytes": 5368709120,
"cameras": {
"camera1": {
"file_count": 75,
"total_size_bytes": 2684354560
},
"camera2": {
"file_count": 75,
"total_size_bytes": 2684354560
}
},
"disk_usage": {
"total_bytes": 107374182400,
"used_bytes": 53687091200,
"free_bytes": 53687091200,
"usage_percent": 50.0
}
}
```
### Get File List
```http
POST /storage/files
Content-Type: application/json
{
"camera_name": "camera1",
"start_date": "2024-01-15",
"end_date": "2024-01-16",
"limit": 50
}
```
**Response**: `FileListResponse`
```json
{
"files": [
{
"filename": "20240115_103000_test_recording.avi",
"camera_name": "camera1",
"size_bytes": 52428800,
"created_time": "2024-01-15T10:30:00Z",
"duration_seconds": 30.5
}
],
"total_count": 1
}
```
### Cleanup Old Files
```http
POST /storage/cleanup
Content-Type: application/json
{
"max_age_days": 30
}
```
**Response**: `CleanupResponse`
```json
{
"files_removed": 25,
"bytes_freed": 1073741824,
"errors": []
}
```
## 🔄 Camera Recovery & Diagnostics
### Test Camera Connection
```http
POST /cameras/{camera_name}/test-connection
```
**Response**: `CameraTestResponse`
### Reconnect Camera
```http
POST /cameras/{camera_name}/reconnect
```
**Response**: `CameraRecoveryResponse`
### Restart Camera Grab Process
```http
POST /cameras/{camera_name}/restart-grab
```
**Response**: `CameraRecoveryResponse`
### Reset Camera Timestamp
```http
POST /cameras/{camera_name}/reset-timestamp
```
**Response**: `CameraRecoveryResponse`
### Full Camera Reset
```http
POST /cameras/{camera_name}/full-reset
```
**Response**: `CameraRecoveryResponse`
### Reinitialize Camera
```http
POST /cameras/{camera_name}/reinitialize
```
**Response**: `CameraRecoveryResponse`
**Recovery Response Example**:
```json
{
"success": true,
"message": "Camera camera1 reconnected successfully",
"camera_name": "camera1",
"operation": "reconnect",
"timestamp": "2024-01-15T10:30:00Z"
}
```
## 📺 Live Streaming
### Get Live MJPEG Stream
```http
GET /cameras/{camera_name}/stream
```
**Response**: MJPEG video stream (multipart/x-mixed-replace)
### Start Camera Stream
```http
POST /cameras/{camera_name}/start-stream
```
### Stop Camera Stream
```http
POST /cameras/{camera_name}/stop-stream
```
**Streaming Features**:
- 📺 **MJPEG format**: Compatible with web browsers and React apps
- 🔄 **Concurrent operation**: Stream while recording simultaneously
-**Low latency**: Real-time preview for monitoring
For detailed streaming integration, see [Streaming Guide](guides/STREAMING_GUIDE.md).
## 🌐 WebSocket Real-time Updates
### Connect to WebSocket
```javascript
const ws = new WebSocket('ws://localhost:8000/ws');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
console.log('Real-time update:', update);
};
```
**WebSocket Message Types**:
- `system_status`: System status changes
- `camera_status`: Camera status updates
- `recording_started`: Recording start events
- `recording_stopped`: Recording stop events
- `mqtt_message`: MQTT message received
- `auto_recording_event`: Auto-recording status changes
**Example WebSocket Message**:
```json
{
"type": "recording_started",
"data": {
"camera_name": "camera1",
"filename": "20240115_103000_auto_recording.avi",
"timestamp": "2024-01-15T10:30:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
```
## 🚀 Quick Start Examples
### Basic System Monitoring
```bash
# Check system health
curl http://localhost:8000/health
# Get overall system status
curl http://localhost:8000/system/status
# Get all camera statuses
curl http://localhost:8000/cameras
```
### Manual Recording Control
```bash
# Start recording with default settings
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"filename": "manual_test.avi"}'
# Start recording with custom camera settings
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{
"filename": "high_quality.avi",
"exposure_ms": 2.0,
"gain": 4.0,
"fps": 5.0
}'
# Stop recording
curl -X POST http://localhost:8000/cameras/camera1/stop-recording
```
### Auto-Recording Management
```bash
# Enable auto-recording for camera1
curl -X POST http://localhost:8000/cameras/camera1/auto-recording/enable
# Check auto-recording status
curl http://localhost:8000/auto-recording/status
# Disable auto-recording for camera1
curl -X POST http://localhost:8000/cameras/camera1/auto-recording/disable
```
### Camera Configuration
```bash
# Get current camera configuration
curl http://localhost:8000/cameras/camera1/config
# Update camera settings (real-time)
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"exposure_ms": 1.5,
"gain": 3.0,
"sharpness": 130,
"contrast": 120
}'
```
## 📈 Recent API Changes & Enhancements
### ✨ New in Latest Version
#### 1. Enhanced Recording API
- **Dynamic camera settings**: Set exposure, gain, and FPS per recording
- **Automatic datetime prefixes**: All filenames get timestamp prefixes
- **Backward compatibility**: Existing API calls work unchanged
#### 2. Auto-Recording Feature
- **Per-camera control**: Enable/disable auto-recording individually
- **MQTT integration**: Automatic recording based on machine states
- **Retry logic**: Failed recordings are automatically retried
- **Status tracking**: Monitor auto-recording attempts and failures
#### 3. Advanced Camera Configuration
- **Real-time settings**: Update exposure, gain, image quality without restart
- **Image enhancement**: Sharpness, contrast, saturation, gamma controls
- **Noise reduction**: Configurable noise filtering and 3D denoising
- **HDR support**: High Dynamic Range imaging capabilities
#### 4. Live Streaming
- **MJPEG streaming**: Real-time camera preview
- **Concurrent operation**: Stream while recording simultaneously
- **Web-compatible**: Direct integration with React/HTML video elements
#### 5. Enhanced Monitoring
- **MQTT event history**: Track machine state changes over time
- **Storage statistics**: Monitor disk usage and file counts
- **WebSocket updates**: Real-time system status notifications
### 🔄 Migration Notes
#### From Previous Versions
1. **Recording API**: All existing calls work, but now return filenames with datetime prefixes
2. **Configuration**: New camera settings are optional and backward compatible
3. **Auto-recording**: New feature, requires enabling in `config.json` and per camera
#### Configuration Updates
```json
{
"cameras": [
{
"name": "camera1",
"auto_start_recording_enabled": true, // NEW: Enable auto-recording
"sharpness": 120, // NEW: Image quality settings
"contrast": 110,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"hdr_enabled": false
}
],
"system": {
"auto_recording_enabled": true // NEW: Global auto-recording toggle
}
}
```
## 🔗 Related Documentation
- [📷 Camera Configuration API Guide](api/CAMERA_CONFIG_API.md) - Detailed camera settings
- [🤖 Auto-Recording Feature Guide](features/AUTO_RECORDING_FEATURE_GUIDE.md) - React integration
- [📺 Streaming Guide](guides/STREAMING_GUIDE.md) - Live video streaming
- [🔧 Camera Recovery Guide](guides/CAMERA_RECOVERY_GUIDE.md) - Troubleshooting
- [📡 MQTT Logging Guide](guides/MQTT_LOGGING_GUIDE.md) - MQTT configuration
## 📞 Support & Integration
### API Base URL
- **Development**: `http://localhost:8000`
- **Production**: Configure in `config.json` under `system.api_host` and `system.api_port`
### Error Handling
All endpoints return standard HTTP status codes:
- `200`: Success
- `404`: Resource not found (camera, file, etc.)
- `500`: Internal server error
- `503`: Service unavailable (camera manager, MQTT, etc.)
### Rate Limiting
- No rate limiting currently implemented
- WebSocket connections are limited to reasonable concurrent connections
### CORS Support
- CORS is enabled for web dashboard integration
- Configure allowed origins in the API server settings
```
```

View File

@@ -0,0 +1,195 @@
# 🚀 USDA Vision Camera System - API Quick Reference
Quick reference for the most commonly used API endpoints. For complete documentation, see [API_DOCUMENTATION.md](API_DOCUMENTATION.md).
## 🔧 System Status
```bash
# Health check
curl http://localhost:8000/health
# System overview
curl http://localhost:8000/system/status
# All cameras
curl http://localhost:8000/cameras
# All machines
curl http://localhost:8000/machines
```
## 🎥 Recording Control
### Start Recording (Basic)
```bash
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"filename": "test.avi"}'
```
### Start Recording (With Settings)
```bash
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{
"filename": "high_quality.avi",
"exposure_ms": 2.0,
"gain": 4.0,
"fps": 5.0
}'
```
### Stop Recording
```bash
curl -X POST http://localhost:8000/cameras/camera1/stop-recording
```
## 🤖 Auto-Recording
```bash
# Enable auto-recording
curl -X POST http://localhost:8000/cameras/camera1/auto-recording/enable
# Disable auto-recording
curl -X POST http://localhost:8000/cameras/camera1/auto-recording/disable
# Check auto-recording status
curl http://localhost:8000/auto-recording/status
```
## 🎛️ Camera Configuration
```bash
# Get camera config
curl http://localhost:8000/cameras/camera1/config
# Update camera settings
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"exposure_ms": 1.5,
"gain": 3.0,
"sharpness": 130
}'
```
## 📺 Live Streaming
```bash
# Start streaming
curl -X POST http://localhost:8000/cameras/camera1/start-stream
# Get MJPEG stream (use in browser/video element)
# http://localhost:8000/cameras/camera1/stream
# Stop streaming
curl -X POST http://localhost:8000/cameras/camera1/stop-stream
```
## 🔄 Camera Recovery
```bash
# Test connection
curl -X POST http://localhost:8000/cameras/camera1/test-connection
# Reconnect camera
curl -X POST http://localhost:8000/cameras/camera1/reconnect
# Full reset
curl -X POST http://localhost:8000/cameras/camera1/full-reset
```
## 💾 Storage Management
```bash
# Storage statistics
curl http://localhost:8000/storage/stats
# List files
curl -X POST http://localhost:8000/storage/files \
-H "Content-Type: application/json" \
-d '{"camera_name": "camera1", "limit": 10}'
# Cleanup old files
curl -X POST http://localhost:8000/storage/cleanup \
-H "Content-Type: application/json" \
-d '{"max_age_days": 30}'
```
## 📡 MQTT Monitoring
```bash
# MQTT status
curl http://localhost:8000/mqtt/status
# Recent MQTT events
curl http://localhost:8000/mqtt/events?limit=10
```
## 🌐 WebSocket Connection
```javascript
// Connect to real-time updates
const ws = new WebSocket('ws://localhost:8000/ws');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
console.log('Update:', update);
};
```
## 📊 Response Examples
### System Status Response
```json
{
"system_started": true,
"mqtt_connected": true,
"cameras": {
"camera1": {
"name": "camera1",
"status": "ACTIVE",
"is_recording": false,
"auto_recording_enabled": true
}
},
"active_recordings": 0,
"total_recordings": 15
}
```
### Recording Start Response
```json
{
"success": true,
"message": "Recording started for camera1",
"filename": "20240115_103000_test.avi"
}
```
### Camera Status Response
```json
{
"name": "camera1",
"status": "ACTIVE",
"is_recording": false,
"auto_recording_enabled": true,
"auto_recording_active": false,
"auto_recording_failure_count": 0
}
```
## 🔗 Related Documentation
- [📚 Complete API Documentation](API_DOCUMENTATION.md)
- [🎛️ Camera Configuration Guide](api/CAMERA_CONFIG_API.md)
- [🤖 Auto-Recording Feature Guide](features/AUTO_RECORDING_FEATURE_GUIDE.md)
- [📺 Streaming Guide](guides/STREAMING_GUIDE.md)
## 💡 Tips
- All filenames automatically get datetime prefixes: `YYYYMMDD_HHMMSS_`
- Camera settings can be updated in real-time during recording
- Auto-recording is controlled per camera and globally
- WebSocket provides real-time updates for dashboard integration
- CORS is enabled for web application integration

View File

@@ -0,0 +1,212 @@
# 🎉 USDA Vision Camera System - PROJECT COMPLETE!
## ✅ Final Status: READY FOR PRODUCTION
The USDA Vision Camera System has been successfully implemented, tested, and documented. All requirements have been met and the system is production-ready.
## 📋 Completed Requirements
### ✅ 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 camera SDK library
- **Multi-threading**: Concurrent MQTT + camera monitoring + recording
- **File Management**: Timestamp-based naming in organized directories
### ✅ Advanced Features
- **REST API**: Complete FastAPI server with all endpoints
- **WebSocket Support**: Real-time updates for dashboard integration
- **Time Synchronization**: Atlanta, Georgia timezone with NTP sync
- **Storage Management**: File indexing, cleanup, and statistics
- **Comprehensive Logging**: Rotating logs with error tracking
- **Configuration System**: JSON-based configuration management
### ✅ Documentation & Testing
- **Complete README**: Installation, usage, API docs, troubleshooting
- **Test Suite**: Comprehensive system testing (`test_system.py`)
- **Time Verification**: Timezone and sync testing (`check_time.py`)
- **Startup Scripts**: Easy deployment with `start_system.sh`
- **Clean Repository**: Organized structure with proper .gitignore
## 🏗️ Final Project Structure
```
USDA-Vision-Cameras/
├── README.md # Complete documentation
├── main.py # System entry point
├── config.json # System configuration
├── requirements.txt # Python dependencies
├── pyproject.toml # UV package configuration
├── .gitignore # Git ignore rules
├── start_system.sh # Startup script
├── setup_timezone.sh # Time sync setup
├── test_system.py # System test suite
├── check_time.py # Time verification
├── test_timezone.py # Timezone testing
├── 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
├── storage/ # Recording storage
│ ├── camera1/ # Camera 1 recordings
│ └── camera2/ # Camera 2 recordings
├── tests/ # Test files and legacy tests
├── notebooks/ # Jupyter notebooks
└── docs/ # Documentation files
```
## 🚀 How to Deploy
### 1. Clone and Setup
```bash
git clone https://github.com/your-username/USDA-Vision-Cameras.git
cd USDA-Vision-Cameras
uv sync
```
### 2. Configure System
```bash
# Edit config.json for your environment
# Set MQTT broker, camera settings, storage paths
```
### 3. Setup Time Sync
```bash
./setup_timezone.sh
```
### 4. Test System
```bash
python test_system.py
```
### 5. Start System
```bash
./start_system.sh
```
## 🌐 API Integration
### Dashboard Integration
```javascript
// React component example
const systemStatus = await fetch('http://localhost:8000/system/status');
const cameras = await fetch('http://localhost:8000/cameras');
// WebSocket for real-time updates
const ws = new WebSocket('ws://localhost:8000/ws');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
// Handle real-time system updates
};
```
### Manual Control
```bash
# Start recording manually
curl -X POST http://localhost:8000/cameras/camera1/start-recording
# Stop recording manually
curl -X POST http://localhost:8000/cameras/camera1/stop-recording
# Get system status
curl http://localhost:8000/system/status
```
## 📊 System Capabilities
### Discovered Hardware
- **2 GigE Cameras**: Blower-Yield-Cam, Cracker-Cam
- **Network Ready**: Cameras accessible at 192.168.1.165, 192.168.1.167
- **MQTT Ready**: Configured for broker at 192.168.1.110
### Recording Features
- **Automatic Start/Stop**: Based on MQTT machine states
- **Timezone Aware**: Atlanta time timestamps (EST/EDT)
- **Organized Storage**: Separate directories per camera
- **File Naming**: `camera1_recording_20250725_213000.avi`
- **Manual Control**: API endpoints for manual recording
### Monitoring Features
- **Real-time Status**: Camera and machine state monitoring
- **Health Checks**: Automatic system health verification
- **Performance Tracking**: Recording metrics and system stats
- **Error Handling**: Comprehensive error tracking and recovery
## 🔧 Maintenance
### Regular Tasks
- **Log Monitoring**: Check `usda_vision_system.log`
- **Storage Cleanup**: Automatic cleanup of old recordings
- **Time Sync**: Automatic NTP synchronization
- **Health Checks**: Built-in system monitoring
### Troubleshooting
- **Test Suite**: `python test_system.py`
- **Time Check**: `python check_time.py`
- **API Health**: `curl http://localhost:8000/health`
- **Debug Mode**: `python main.py --log-level DEBUG`
## 🎯 Production Readiness
### ✅ All Tests Passing
- System initialization: ✅
- Camera discovery: ✅ (2 cameras found)
- MQTT configuration: ✅
- Storage setup: ✅
- Time synchronization: ✅
- API endpoints: ✅
### ✅ Documentation Complete
- Installation guide: ✅
- Configuration reference: ✅
- API documentation: ✅
- Troubleshooting guide: ✅
- Integration examples: ✅
### ✅ Production Features
- Error handling: ✅
- Logging system: ✅
- Time synchronization: ✅
- Storage management: ✅
- API security: ✅
- Performance monitoring: ✅
## 🚀 Next Steps
The system is now ready for:
1. **Production Deployment**: Deploy on target hardware
2. **Dashboard Integration**: Connect to React + Supabase dashboard
3. **MQTT Configuration**: Connect to production MQTT broker
4. **Camera Calibration**: Fine-tune camera settings for production
5. **Monitoring Setup**: Configure production monitoring and alerts
## 📞 Support
For ongoing support:
- **Documentation**: Complete README.md with troubleshooting
- **Test Suite**: Comprehensive diagnostic tools
- **Logging**: Detailed system logs for debugging
- **API Health**: Built-in health check endpoints
---
**🎊 PROJECT STATUS: COMPLETE AND PRODUCTION-READY! 🎊**
The USDA Vision Camera System is fully implemented, tested, and documented. All original requirements have been met, and the system is ready for production deployment with your React dashboard integration.
**Key Achievements:**
- ✅ Dual MQTT topic monitoring
- ✅ Automatic camera recording
- ✅ Atlanta timezone synchronization
- ✅ Complete REST API
- ✅ Comprehensive documentation
- ✅ Production-ready deployment

View File

@@ -0,0 +1,65 @@
# USDA Vision Camera System - Documentation
This directory contains detailed documentation for the USDA Vision Camera System.
## Documentation Files
### 🚀 [API_DOCUMENTATION.md](API_DOCUMENTATION.md) **⭐ NEW**
**Complete API reference documentation** covering all endpoints, features, and recent enhancements:
- System status and health monitoring
- Camera management and configuration
- Recording control with dynamic settings
- Auto-recording management
- MQTT and machine status
- Storage and file management
- Camera recovery and diagnostics
- Live streaming capabilities
- WebSocket real-time updates
- Quick start examples and migration notes
### ⚡ [API_QUICK_REFERENCE.md](API_QUICK_REFERENCE.md) **⭐ NEW**
**Quick reference card** for the most commonly used API endpoints with curl examples and response formats.
### 📋 [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.

View File

@@ -0,0 +1,425 @@
# 🎛️ Camera Configuration API Guide
This guide explains how to configure camera settings via API endpoints, including all the advanced settings from your config.json.
> **Note**: This document is part of the comprehensive [USDA Vision Camera System API Documentation](../API_DOCUMENTATION.md). For complete API reference, see the main documentation.
## 📋 Configuration Categories
### ✅ **Real-time Configurable (No Restart Required)**
These settings can be changed while the camera is active:
- **Basic**: `exposure_ms`, `gain`, `target_fps`
- **Image Quality**: `sharpness`, `contrast`, `saturation`, `gamma`
- **Color**: `auto_white_balance`, `color_temperature_preset`
- **Advanced**: `anti_flicker_enabled`, `light_frequency`
- **HDR**: `hdr_enabled`, `hdr_gain_mode`
### ⚠️ **Restart Required**
These settings require camera restart to take effect:
- **Noise Reduction**: `noise_filter_enabled`, `denoise_3d_enabled`
- **System**: `machine_topic`, `storage_path`, `enabled`, `bit_depth`
## 🔌 API Endpoints
### 1. Get Camera Configuration
```http
GET /cameras/{camera_name}/config
```
**Response:**
```json
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1",
"enabled": true,
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 0,
"sharpness": 120,
"contrast": 110,
"saturation": 100,
"gamma": 100,
"noise_filter_enabled": true,
"denoise_3d_enabled": false,
"auto_white_balance": true,
"color_temperature_preset": 0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"bit_depth": 8,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
```
### 2. Update Camera Configuration
```http
PUT /cameras/{camera_name}/config
Content-Type: application/json
```
**Request Body (all fields optional):**
```json
{
"exposure_ms": 2.0,
"gain": 4.0,
"target_fps": 10.0,
"sharpness": 150,
"contrast": 120,
"saturation": 110,
"gamma": 90,
"noise_filter_enabled": true,
"denoise_3d_enabled": false,
"auto_white_balance": false,
"color_temperature_preset": 1,
"anti_flicker_enabled": true,
"light_frequency": 1,
"hdr_enabled": false,
"hdr_gain_mode": 0
}
```
**Response:**
```json
{
"success": true,
"message": "Camera camera1 configuration updated",
"updated_settings": ["exposure_ms", "gain", "sharpness"]
}
```
### 3. Apply Configuration (Restart Camera)
```http
POST /cameras/{camera_name}/apply-config
```
**Response:**
```json
{
"success": true,
"message": "Configuration applied to camera camera1"
}
```
## 📊 Setting Ranges and Descriptions
### Basic Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `exposure_ms` | 0.1 - 1000.0 | 1.0 | Exposure time in milliseconds |
| `gain` | 0.0 - 20.0 | 3.5 | Camera gain multiplier |
| `target_fps` | 0.0 - 120.0 | 0 | Target FPS (0 = maximum) |
### Image Quality Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `sharpness` | 0 - 200 | 100 | Image sharpness (100 = no sharpening) |
| `contrast` | 0 - 200 | 100 | Image contrast (100 = normal) |
| `saturation` | 0 - 200 | 100 | Color saturation (color cameras only) |
| `gamma` | 0 - 300 | 100 | Gamma correction (100 = normal) |
### Color Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `auto_white_balance` | true/false | true | Automatic white balance |
| `color_temperature_preset` | 0-10 | 0 | Color temperature preset (0=auto) |
### Advanced Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `anti_flicker_enabled` | true/false | true | Reduce artificial lighting flicker |
| `light_frequency` | 0/1 | 1 | Light frequency (0=50Hz, 1=60Hz) |
| `noise_filter_enabled` | true/false | true | Basic noise filtering |
| `denoise_3d_enabled` | true/false | false | Advanced 3D denoising |
### HDR Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `hdr_enabled` | true/false | false | High Dynamic Range |
| `hdr_gain_mode` | 0-3 | 0 | HDR processing mode |
## 🚀 Usage Examples
### Example 1: Adjust Exposure and Gain
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"exposure_ms": 1.5,
"gain": 4.0
}'
```
### Example 2: Improve Image Quality
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"sharpness": 150,
"contrast": 120,
"gamma": 90
}'
```
### Example 3: Configure for Indoor Lighting
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"anti_flicker_enabled": true,
"light_frequency": 1,
"auto_white_balance": false,
"color_temperature_preset": 2
}'
```
### Example 4: Enable HDR Mode
```bash
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"hdr_enabled": true,
"hdr_gain_mode": 1
}'
```
## ⚛️ React Integration Examples
### Camera Configuration Component
```jsx
import React, { useState, useEffect } from 'react';
const CameraConfig = ({ cameraName, apiBaseUrl = 'http://localhost:8000' }) => {
const [config, setConfig] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// Load current configuration
useEffect(() => {
fetchConfig();
}, [cameraName]);
const fetchConfig = async () => {
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/config`);
if (response.ok) {
const data = await response.json();
setConfig(data);
} else {
setError('Failed to load configuration');
}
} catch (err) {
setError(`Error: ${err.message}`);
}
};
const updateConfig = async (updates) => {
setLoading(true);
try {
const response = await fetch(`${apiBaseUrl}/cameras/${cameraName}/config`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
if (response.ok) {
const result = await response.json();
console.log('Updated settings:', result.updated_settings);
await fetchConfig(); // Reload configuration
} else {
const error = await response.json();
setError(error.detail || 'Update failed');
}
} catch (err) {
setError(`Error: ${err.message}`);
} finally {
setLoading(false);
}
};
const handleSliderChange = (setting, value) => {
updateConfig({ [setting]: value });
};
if (!config) return <div>Loading configuration...</div>;
return (
<div className="camera-config">
<h3>Camera Configuration: {cameraName}</h3>
{/* Basic Settings */}
<div className="config-section">
<h4>Basic Settings</h4>
<div className="setting">
<label>Exposure (ms): {config.exposure_ms}</label>
<input
type="range"
min="0.1"
max="10"
step="0.1"
value={config.exposure_ms}
onChange={(e) => handleSliderChange('exposure_ms', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Gain: {config.gain}</label>
<input
type="range"
min="0"
max="10"
step="0.1"
value={config.gain}
onChange={(e) => handleSliderChange('gain', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Target FPS: {config.target_fps}</label>
<input
type="range"
min="0"
max="30"
step="1"
value={config.target_fps}
onChange={(e) => handleSliderChange('target_fps', parseInt(e.target.value))}
/>
</div>
</div>
{/* Image Quality Settings */}
<div className="config-section">
<h4>Image Quality</h4>
<div className="setting">
<label>Sharpness: {config.sharpness}</label>
<input
type="range"
min="0"
max="200"
value={config.sharpness}
onChange={(e) => handleSliderChange('sharpness', parseInt(e.target.value))}
/>
</div>
<div className="setting">
<label>Contrast: {config.contrast}</label>
<input
type="range"
min="0"
max="200"
value={config.contrast}
onChange={(e) => handleSliderChange('contrast', parseInt(e.target.value))}
/>
</div>
<div className="setting">
<label>Gamma: {config.gamma}</label>
<input
type="range"
min="0"
max="300"
value={config.gamma}
onChange={(e) => handleSliderChange('gamma', parseInt(e.target.value))}
/>
</div>
</div>
{/* Advanced Settings */}
<div className="config-section">
<h4>Advanced Settings</h4>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.anti_flicker_enabled}
onChange={(e) => updateConfig({ anti_flicker_enabled: e.target.checked })}
/>
Anti-flicker Enabled
</label>
</div>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.auto_white_balance}
onChange={(e) => updateConfig({ auto_white_balance: e.target.checked })}
/>
Auto White Balance
</label>
</div>
<div className="setting">
<label>
<input
type="checkbox"
checked={config.hdr_enabled}
onChange={(e) => updateConfig({ hdr_enabled: e.target.checked })}
/>
HDR Enabled
</label>
</div>
</div>
{error && (
<div className="error" style={{ color: 'red', marginTop: '10px' }}>
{error}
</div>
)}
{loading && <div>Updating configuration...</div>}
</div>
);
};
export default CameraConfig;
```
## 🔄 Configuration Workflow
### 1. Real-time Adjustments
For settings that don't require restart:
```bash
# Update settings
curl -X PUT /cameras/camera1/config -d '{"exposure_ms": 2.0}'
# Settings take effect immediately
# Continue recording/streaming without interruption
```
### 2. Settings Requiring Restart
For noise reduction and system settings:
```bash
# Update settings
curl -X PUT /cameras/camera1/config -d '{"noise_filter_enabled": false}'
# Apply configuration (restarts camera)
curl -X POST /cameras/camera1/apply-config
# Camera reinitializes with new settings
```
## 🚨 Important Notes
### Camera State During Updates
- **Real-time settings**: Applied immediately, no interruption
- **Restart-required settings**: Saved to config, applied on next restart
- **Recording**: Continues during real-time updates
- **Streaming**: Continues during real-time updates
### Error Handling
- Invalid ranges return HTTP 422 with validation errors
- Camera not found returns HTTP 404
- SDK errors are logged and return HTTP 500
### Performance Impact
- **Image quality settings**: Minimal performance impact
- **Noise reduction**: May reduce FPS when enabled
- **HDR**: Significant processing overhead when enabled
This comprehensive API allows you to control all camera settings programmatically, making it perfect for integration with React dashboards or automated optimization systems!

View File

@@ -0,0 +1,262 @@
# Auto-Recording Feature Implementation Guide
## 🎯 Overview for React App Development
This document provides a comprehensive guide for updating the React application to support the new auto-recording feature that was added to the USDA Vision Camera System.
> **📚 For complete API reference**: See the [USDA Vision Camera System API Documentation](../API_DOCUMENTATION.md) for detailed endpoint specifications and examples.
## 📋 What Changed in the Backend
### New API Endpoints Added
1. **Enable Auto-Recording**
```http
POST /cameras/{camera_name}/auto-recording/enable
Response: AutoRecordingConfigResponse
```
2. **Disable Auto-Recording**
```http
POST /cameras/{camera_name}/auto-recording/disable
Response: AutoRecordingConfigResponse
```
3. **Get Auto-Recording Status**
```http
GET /auto-recording/status
Response: AutoRecordingStatusResponse
```
### Updated API Responses
#### CameraStatusResponse (Updated)
```typescript
interface CameraStatusResponse {
name: string;
status: string;
is_recording: boolean;
last_checked: string;
last_error?: string;
device_info?: any;
current_recording_file?: string;
recording_start_time?: string;
// NEW AUTO-RECORDING FIELDS
auto_recording_enabled: boolean;
auto_recording_active: boolean;
auto_recording_failure_count: number;
auto_recording_last_attempt?: string;
auto_recording_last_error?: string;
}
```
#### CameraConfigResponse (Updated)
```typescript
interface CameraConfigResponse {
name: string;
machine_topic: string;
storage_path: string;
enabled: boolean;
// NEW AUTO-RECORDING CONFIG FIELDS
auto_start_recording_enabled: boolean;
auto_recording_max_retries: number;
auto_recording_retry_delay_seconds: number;
// ... existing fields (exposure_ms, gain, etc.)
}
```
#### New Response Types
```typescript
interface AutoRecordingConfigResponse {
success: boolean;
message: string;
camera_name: string;
enabled: boolean;
}
interface AutoRecordingStatusResponse {
running: boolean;
auto_recording_enabled: boolean;
retry_queue: Record<string, any>;
enabled_cameras: string[];
}
```
## 🎨 React App UI Requirements
### 1. Camera Status Display Updates
**Add to Camera Cards/Components:**
- Auto-recording enabled/disabled indicator
- Auto-recording active status (when machine is ON and auto-recording)
- Failure count display (if > 0)
- Last auto-recording error (if any)
- Visual distinction between manual and auto-recording
**Example UI Elements:**
```jsx
// Auto-recording status badge
{camera.auto_recording_enabled && (
<Badge variant={camera.auto_recording_active ? "success" : "secondary"}>
Auto-Recording {camera.auto_recording_active ? "Active" : "Enabled"}
</Badge>
)}
// Failure indicator
{camera.auto_recording_failure_count > 0 && (
<Alert variant="warning">
Auto-recording failures: {camera.auto_recording_failure_count}
</Alert>
)}
```
### 2. Auto-Recording Controls
**Add Toggle Controls:**
- Enable/Disable auto-recording per camera
- Global auto-recording status display
- Retry queue monitoring
**Example Control Component:**
```jsx
const AutoRecordingToggle = ({ camera, onToggle }) => {
const handleToggle = async () => {
const endpoint = camera.auto_recording_enabled ? 'disable' : 'enable';
await fetch(`/cameras/${camera.name}/auto-recording/${endpoint}`, {
method: 'POST'
});
onToggle();
};
return (
<Switch
checked={camera.auto_recording_enabled}
onChange={handleToggle}
label="Auto-Recording"
/>
);
};
```
### 3. Machine State Integration
**Display Machine Status:**
- Show which machine each camera monitors
- Display current machine state (ON/OFF)
- Show correlation between machine state and recording status
**Camera-Machine Mapping:**
- Camera 1 → Vibratory Conveyor (conveyor/cracker cam)
- Camera 2 → Blower Separator (blower separator)
### 4. Auto-Recording Dashboard
**Create New Dashboard Section:**
- Overall auto-recording system status
- List of cameras with auto-recording enabled
- Active retry queue display
- Recent auto-recording events/logs
## 🔧 Implementation Steps for React App
### Step 1: Update TypeScript Interfaces
```typescript
// Update existing interfaces in your types file
// Add new interfaces for auto-recording responses
```
### Step 2: Update API Service Functions
```typescript
// Add new API calls
export const enableAutoRecording = (cameraName: string) =>
fetch(`/cameras/${cameraName}/auto-recording/enable`, { method: 'POST' });
export const disableAutoRecording = (cameraName: string) =>
fetch(`/cameras/${cameraName}/auto-recording/disable`, { method: 'POST' });
export const getAutoRecordingStatus = () =>
fetch('/auto-recording/status').then(res => res.json());
```
### Step 3: Update Camera Components
- Add auto-recording status indicators
- Add enable/disable controls
- Update recording status display to distinguish auto vs manual
### Step 4: Create Auto-Recording Management Panel
- System-wide auto-recording status
- Per-camera auto-recording controls
- Retry queue monitoring
- Error reporting and alerts
### Step 5: Update State Management
```typescript
// Add auto-recording state to your store/context
interface AppState {
cameras: CameraStatusResponse[];
autoRecordingStatus: AutoRecordingStatusResponse;
// ... existing state
}
```
## 🎯 Key User Experience Considerations
### Visual Indicators
1. **Recording Status Hierarchy:**
- Manual Recording (highest priority - red/prominent)
- Auto-Recording Active (green/secondary)
- Auto-Recording Enabled but Inactive (blue/subtle)
- Auto-Recording Disabled (gray/muted)
2. **Machine State Correlation:**
- Show machine ON/OFF status next to camera
- Indicate when auto-recording should be active
- Alert if machine is ON but auto-recording failed
3. **Error Handling:**
- Clear error messages for auto-recording failures
- Retry count display
- Last attempt timestamp
- Quick retry/reset options
### User Controls
1. **Quick Actions:**
- Toggle auto-recording per camera
- Force retry failed auto-recording
- Override auto-recording (manual control)
2. **Configuration:**
- Adjust retry settings
- Change machine-camera mappings
- Set recording parameters for auto-recording
## 🚨 Important Notes
### Behavior Rules
1. **Manual Override:** Manual recording always takes precedence over auto-recording
2. **Non-Blocking:** Auto-recording status checks don't interfere with camera operation
3. **Machine Correlation:** Auto-recording only activates when the associated machine turns ON
4. **Failure Handling:** Failed auto-recording attempts are retried automatically with exponential backoff
### API Polling Recommendations
- Poll camera status every 2-3 seconds for real-time updates
- Poll auto-recording status every 5-10 seconds
- Use WebSocket connections if available for real-time machine state updates
## 📱 Mobile Considerations
- Auto-recording controls should be easily accessible on mobile
- Status indicators should be clear and readable on small screens
- Consider collapsible sections for detailed auto-recording information
## 🔍 Testing Checklist
- [ ] Auto-recording toggle works for each camera
- [ ] Status updates reflect machine state changes
- [ ] Error states are clearly displayed
- [ ] Manual recording overrides auto-recording
- [ ] Retry mechanism is visible to users
- [ ] Mobile interface is functional
This guide provides everything needed to update the React app to fully support the new auto-recording feature!

View File

@@ -0,0 +1,158 @@
# Camera Recovery and Diagnostics Guide
This guide explains the new camera recovery functionality implemented in the USDA Vision Camera System API.
## Overview
The system now includes comprehensive camera recovery capabilities to handle connection issues, initialization failures, and other camera-related problems. These features use the underlying mvsdk (python demo) library functions to perform various recovery operations.
## Available Recovery Operations
### 1. Connection Test (`/cameras/{camera_name}/test-connection`)
- **Purpose**: Test if the camera connection is working
- **SDK Function**: `CameraConnectTest()`
- **Use Case**: Diagnose connection issues
- **HTTP Method**: POST
- **Response**: `CameraTestResponse`
### 2. Reconnect (`/cameras/{camera_name}/reconnect`)
- **Purpose**: Soft reconnection to the camera
- **SDK Function**: `CameraReConnect()`
- **Use Case**: Most common fix for connection issues
- **HTTP Method**: POST
- **Response**: `CameraRecoveryResponse`
### 3. Restart Grab (`/cameras/{camera_name}/restart-grab`)
- **Purpose**: Restart the camera grab process
- **SDK Function**: `CameraRestartGrab()`
- **Use Case**: Fix issues with image capture
- **HTTP Method**: POST
- **Response**: `CameraRecoveryResponse`
### 4. Reset Timestamp (`/cameras/{camera_name}/reset-timestamp`)
- **Purpose**: Reset camera timestamp
- **SDK Function**: `CameraRstTimeStamp()`
- **Use Case**: Fix timing-related issues
- **HTTP Method**: POST
- **Response**: `CameraRecoveryResponse`
### 5. Full Reset (`/cameras/{camera_name}/full-reset`)
- **Purpose**: Complete camera reset (uninitialize and reinitialize)
- **SDK Functions**: `CameraUnInit()` + `CameraInit()`
- **Use Case**: Hard reset for persistent issues
- **HTTP Method**: POST
- **Response**: `CameraRecoveryResponse`
### 6. Reinitialize (`/cameras/{camera_name}/reinitialize`)
- **Purpose**: Reinitialize cameras that failed initial setup
- **SDK Functions**: Complete recorder recreation
- **Use Case**: Cameras that never initialized properly
- **HTTP Method**: POST
- **Response**: `CameraRecoveryResponse`
## Recommended Troubleshooting Workflow
When a camera has issues, follow this order:
1. **Test Connection** - Diagnose the problem
```http
POST http://localhost:8000/cameras/camera1/test-connection
```
2. **Try Reconnect** - Most common fix
```http
POST http://localhost:8000/cameras/camera1/reconnect
```
3. **Restart Grab** - If reconnect doesn't work
```http
POST http://localhost:8000/cameras/camera1/restart-grab
```
4. **Full Reset** - For persistent issues
```http
POST http://localhost:8000/cameras/camera1/full-reset
```
5. **Reinitialize** - For cameras that never worked
```http
POST http://localhost:8000/cameras/camera1/reinitialize
```
## Response Format
All recovery operations return structured responses:
### CameraTestResponse
```json
{
"success": true,
"message": "Camera camera1 connection test passed",
"camera_name": "camera1",
"timestamp": "2024-01-01T12:00:00"
}
```
### CameraRecoveryResponse
```json
{
"success": true,
"message": "Camera camera1 reconnected successfully",
"camera_name": "camera1",
"operation": "reconnect",
"timestamp": "2024-01-01T12:00:00"
}
```
## Implementation Details
### CameraRecorder Methods
- `test_connection()`: Tests camera connection
- `reconnect()`: Performs soft reconnection
- `restart_grab()`: Restarts grab process
- `reset_timestamp()`: Resets timestamp
- `full_reset()`: Complete reset with cleanup and reinitialization
### CameraManager Methods
- `test_camera_connection(camera_name)`: Test specific camera
- `reconnect_camera(camera_name)`: Reconnect specific camera
- `restart_camera_grab(camera_name)`: Restart grab for specific camera
- `reset_camera_timestamp(camera_name)`: Reset timestamp for specific camera
- `full_reset_camera(camera_name)`: Full reset for specific camera
- `reinitialize_failed_camera(camera_name)`: Reinitialize failed camera
### State Management
All recovery operations automatically update the camera status in the state manager:
- Success: Status set to "connected"
- Failure: Status set to appropriate error state with error message
## Error Handling
The system includes comprehensive error handling:
- SDK exceptions are caught and logged
- State manager is updated with error information
- Proper HTTP status codes are returned
- Detailed error messages are provided
## Testing
Use the provided test files:
- `api-tests.http`: Manual API testing with VS Code REST Client
- `test_camera_recovery_api.py`: Automated testing script
## Safety Features
- Recording is automatically stopped before recovery operations
- Camera resources are properly cleaned up
- Thread-safe operations with proper locking
- Graceful error handling prevents system crashes
## Common Use Cases
1. **Camera Lost Connection**: Use reconnect
2. **Camera Won't Capture**: Use restart-grab
3. **Camera Initialization Failed**: Use reinitialize
4. **Persistent Issues**: Use full-reset
5. **Timing Problems**: Use reset-timestamp
This recovery system provides robust tools to handle most camera-related issues without requiring system restart or manual intervention.

View File

@@ -0,0 +1,187 @@
# MQTT Console Logging & API Guide
## 🎯 Overview
Your USDA Vision Camera System now has **enhanced MQTT console logging** and **comprehensive API endpoints** for monitoring machine status via MQTT.
## ✨ What's New
### 1. **Enhanced Console Logging**
- **Colorful emoji-based console output** for all MQTT events
- **Real-time visibility** of MQTT connections, subscriptions, and messages
- **Clear status indicators** for debugging and monitoring
### 2. **New MQTT Status API Endpoint**
- **GET /mqtt/status** - Detailed MQTT client statistics
- **Message counts, error tracking, uptime monitoring**
- **Real-time connection status and broker information**
### 3. **Existing Machine Status APIs** (already available)
- **GET /machines** - All machine states from MQTT
- **GET /system/status** - Overall system status including MQTT
## 🖥️ Console Logging Examples
When you run the system, you'll see:
```bash
🔗 MQTT CONNECTED: 192.168.1.110:1883
📋 MQTT SUBSCRIBED: vibratory_conveyor → vision/vibratory_conveyor/state
📋 MQTT SUBSCRIBED: blower_separator → vision/blower_separator/state
📡 MQTT MESSAGE: vibratory_conveyor → on
📡 MQTT MESSAGE: blower_separator → off
⚠️ MQTT DISCONNECTED: Unexpected disconnection (code: 1)
🔗 MQTT CONNECTED: 192.168.1.110:1883
```
## 🌐 API Endpoints
### MQTT Status
```http
GET http://localhost:8000/mqtt/status
```
**Response:**
```json
{
"connected": true,
"broker_host": "192.168.1.110",
"broker_port": 1883,
"subscribed_topics": [
"vision/vibratory_conveyor/state",
"vision/blower_separator/state"
],
"last_message_time": "2025-07-28T12:00:00",
"message_count": 42,
"error_count": 0,
"uptime_seconds": 3600.5
}
```
### Machine Status
```http
GET http://localhost:8000/machines
```
**Response:**
```json
{
"vibratory_conveyor": {
"name": "vibratory_conveyor",
"state": "on",
"last_updated": "2025-07-28T12:00:00",
"last_message": "on",
"mqtt_topic": "vision/vibratory_conveyor/state"
},
"blower_separator": {
"name": "blower_separator",
"state": "off",
"last_updated": "2025-07-28T12:00:00",
"last_message": "off",
"mqtt_topic": "vision/blower_separator/state"
}
}
```
### System Status
```http
GET http://localhost:8000/system/status
```
**Response:**
```json
{
"system_started": true,
"mqtt_connected": true,
"last_mqtt_message": "2025-07-28T12:00:00",
"machines": { ... },
"cameras": { ... },
"active_recordings": 0,
"total_recordings": 5,
"uptime_seconds": 3600.5
}
```
## 🚀 How to Use
### 1. **Start the Full System**
```bash
python main.py
```
You'll see enhanced console logging for all MQTT events.
### 2. **Test MQTT Demo (MQTT only)**
```bash
python demo_mqtt_console.py
```
Shows just the MQTT client with enhanced logging.
### 3. **Test API Endpoints**
```bash
python test_mqtt_logging.py
```
Tests all the API endpoints and shows expected responses.
### 4. **Query APIs Directly**
```bash
# Check MQTT status
curl http://localhost:8000/mqtt/status
# Check machine states
curl http://localhost:8000/machines
# Check overall system status
curl http://localhost:8000/system/status
```
## 🔧 Configuration
The MQTT settings are in `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"
}
}
}
```
## 🎨 Console Output Features
- **🔗 Connection Events**: Green for successful connections
- **📋 Subscriptions**: Blue for topic subscriptions
- **📡 Messages**: Real-time message display with machine name and payload
- **⚠️ Warnings**: Yellow for unexpected disconnections
- **❌ Errors**: Red for connection failures and errors
- **❓ Unknown Topics**: Purple for unrecognized MQTT topics
## 📊 Monitoring & Debugging
### Real-time Monitoring
- **Console**: Watch live MQTT events as they happen
- **API**: Query `/mqtt/status` for statistics and health
- **Logs**: Check `usda_vision_system.log` for detailed logs
### Troubleshooting
1. **No MQTT messages?** Check broker connectivity and topic configuration
2. **Connection issues?** Verify broker host/port in config.json
3. **API not responding?** Ensure the system is running with `python main.py`
## 🎯 Use Cases
1. **Development**: See MQTT messages in real-time while developing
2. **Debugging**: Identify connection issues and message patterns
3. **Monitoring**: Use APIs to build dashboards or monitoring tools
4. **Integration**: Query machine states from external applications
5. **Maintenance**: Track MQTT statistics and error rates
---
**🎉 Your MQTT monitoring is now fully enhanced with both console logging and comprehensive APIs!**

View File

@@ -0,0 +1,240 @@
# 🎥 USDA Vision Camera Live Streaming Guide
This guide explains how to use the new live preview streaming functionality that allows you to view camera feeds in real-time without blocking recording operations.
## 🌟 Key Features
- **Non-blocking streaming**: Live preview doesn't interfere with recording
- **Separate camera connections**: Streaming uses independent camera instances
- **MJPEG streaming**: Standard web-compatible video streaming
- **Multiple concurrent viewers**: Multiple browsers can view the same stream
- **REST API control**: Start/stop streaming via API endpoints
- **Web interface**: Ready-to-use HTML interface for live preview
## 🏗️ Architecture
The streaming system creates separate camera connections for preview that are independent from recording:
```
Camera Hardware
├── Recording Connection (CameraRecorder)
│ ├── Used for video file recording
│ ├── Triggered by MQTT machine states
│ └── High quality, full FPS
└── Streaming Connection (CameraStreamer)
├── Used for live preview
├── Controlled via API endpoints
└── Optimized for web viewing (lower FPS, JPEG compression)
```
## 🚀 Quick Start
### 1. Start the System
```bash
python main.py
```
### 2. Open the Web Interface
Open `camera_preview.html` in your browser and click "Start Stream" for any camera.
### 3. API Usage
```bash
# Start streaming for camera1
curl -X POST http://localhost:8000/cameras/camera1/start-stream
# View live stream (open in browser)
http://localhost:8000/cameras/camera1/stream
# Stop streaming
curl -X POST http://localhost:8000/cameras/camera1/stop-stream
```
## 📡 API Endpoints
### Start Streaming
```http
POST /cameras/{camera_name}/start-stream
```
**Response:**
```json
{
"success": true,
"message": "Started streaming for camera camera1"
}
```
### Stop Streaming
```http
POST /cameras/{camera_name}/stop-stream
```
**Response:**
```json
{
"success": true,
"message": "Stopped streaming for camera camera1"
}
```
### Live Stream (MJPEG)
```http
GET /cameras/{camera_name}/stream
```
**Response:** Multipart MJPEG stream
**Content-Type:** `multipart/x-mixed-replace; boundary=frame`
## 🌐 Web Interface Usage
The included `camera_preview.html` provides a complete web interface:
1. **Camera Grid**: Shows all configured cameras
2. **Stream Controls**: Start/Stop/Refresh buttons for each camera
3. **Live Preview**: Real-time video feed display
4. **Status Information**: System and camera status
5. **Responsive Design**: Works on desktop and mobile
### Features:
- ✅ Real-time camera status
- ✅ One-click stream start/stop
- ✅ Automatic stream refresh
- ✅ System health monitoring
- ✅ Error handling and status messages
## 🔧 Technical Details
### Camera Streamer Configuration
- **Preview FPS**: 10 FPS (configurable)
- **JPEG Quality**: 70% (configurable)
- **Frame Buffer**: 5 frames (prevents memory buildup)
- **Timeout**: 200ms per frame capture
### Memory Management
- Automatic frame buffer cleanup
- Queue-based frame management
- Proper camera resource cleanup on stop
### Thread Safety
- Thread-safe streaming operations
- Independent from recording threads
- Proper synchronization with locks
## 🧪 Testing
### Run the Test Script
```bash
python test_streaming.py
```
This will test:
- ✅ API endpoint functionality
- ✅ Stream start/stop operations
- ✅ Concurrent recording and streaming
- ✅ Error handling
### Manual Testing
1. Start the system: `python main.py`
2. Open `camera_preview.html` in browser
3. Start streaming for a camera
4. Trigger recording via MQTT or manual API
5. Verify both work simultaneously
## 🔄 Concurrent Operations
The system supports these concurrent operations:
| Operation | Recording | Streaming | Notes |
|-----------|-----------|-----------|-------|
| Recording Only | ✅ | ❌ | Normal operation |
| Streaming Only | ❌ | ✅ | Preview without recording |
| Both Concurrent | ✅ | ✅ | **Independent connections** |
### Example: Concurrent Usage
```bash
# Start streaming
curl -X POST http://localhost:8000/cameras/camera1/start-stream
# Start recording (while streaming continues)
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"filename": "test_recording.avi"}'
# Both operations run independently!
```
## 🛠️ Configuration
### Stream Settings (in CameraStreamer)
```python
self.preview_fps = 10.0 # Lower FPS for preview
self.preview_quality = 70 # JPEG quality (1-100)
self._frame_queue.maxsize = 5 # Frame buffer size
```
### Camera Settings
The streamer uses the same camera configuration as recording:
- Exposure time from `camera_config.exposure_ms`
- Gain from `camera_config.gain`
- Optimized trigger mode for continuous streaming
## 🚨 Important Notes
### Camera Access Patterns
- **Recording**: Blocks camera during active recording
- **Streaming**: Uses separate connection, doesn't block
- **Health Checks**: Brief, non-blocking camera tests
- **Multiple Streams**: Multiple browsers can view same stream
### Performance Considerations
- Streaming uses additional CPU/memory resources
- Lower preview FPS reduces system load
- JPEG compression reduces bandwidth usage
- Frame queue prevents memory buildup
### Error Handling
- Automatic camera resource cleanup
- Graceful handling of camera disconnections
- Stream auto-restart capabilities
- Detailed error logging
## 🔍 Troubleshooting
### Stream Not Starting
1. Check camera availability: `GET /cameras`
2. Verify camera not in error state
3. Check system logs for camera initialization errors
4. Try camera reconnection: `POST /cameras/{name}/reconnect`
### Poor Stream Quality
1. Adjust `preview_quality` setting (higher = better quality)
2. Increase `preview_fps` for smoother video
3. Check network bandwidth
4. Verify camera exposure/gain settings
### Browser Issues
1. Try different browser (Chrome/Firefox recommended)
2. Check browser console for JavaScript errors
3. Verify CORS settings in API server
4. Clear browser cache and refresh
## 📈 Future Enhancements
Potential improvements for the streaming system:
- 🔄 WebRTC support for lower latency
- 📱 Mobile app integration
- 🎛️ Real-time camera setting adjustments
- 📊 Stream analytics and monitoring
- 🔐 Authentication and access control
- 🌐 Multi-camera synchronized viewing
## 📞 Support
For issues with streaming functionality:
1. Check the system logs: `usda_vision_system.log`
2. Run the test script: `python test_streaming.py`
3. Verify API health: `http://localhost:8000/health`
4. Check camera status: `http://localhost:8000/cameras`
---
**✅ Live streaming is now ready for production use!**

View File

@@ -0,0 +1,146 @@
# GigE Camera Image Capture
This project provides simple Python scripts to connect to a GigE camera and capture images using the provided SDK.
## Files Overview
### Demo Files (provided with camera)
- `python demo/mvsdk.py` - Main SDK wrapper library
- `python demo/grab.py` - Basic image capture example
- `python demo/cv_grab.py` - OpenCV-based continuous capture
- `python demo/cv_grab_callback.py` - Callback-based capture
- `python demo/readme.txt` - Original demo documentation
### Custom Scripts
- `camera_capture.py` - Standalone script to capture 10 images with 200ms intervals
- `test.ipynb` - Jupyter notebook with the same functionality
- `images/` - Directory where captured images are saved
## Features
- **Automatic camera detection** - Finds and connects to available GigE cameras
- **Configurable capture** - Currently set to capture 10 images with 200ms intervals
- **Both mono and color support** - Automatically detects camera type
- **Timestamped filenames** - Images saved with date/time stamps
- **Error handling** - Robust error handling for camera operations
- **Cross-platform** - Works on Windows and Linux (with appropriate image flipping)
## Requirements
- Python 3.x
- OpenCV (`cv2`)
- NumPy
- Matplotlib (for Jupyter notebook display)
- GigE camera SDK (MVSDK) - included in `python demo/` directory
## Usage
### Option 1: Standalone Script
Run the standalone Python script:
```bash
python camera_capture.py
```
This will:
1. Initialize the camera SDK
2. Detect available cameras
3. Connect to the first camera found
4. Configure camera settings (manual exposure, continuous mode)
5. Capture 10 images with 200ms intervals
6. Save images to the `images/` directory
7. Clean up and close the camera
### Option 2: Jupyter Notebook
Open and run the `test.ipynb` notebook:
```bash
jupyter notebook test.ipynb
```
The notebook provides the same functionality but with:
- Step-by-step execution
- Detailed explanations
- Visual display of the last captured image
- Better error reporting
## Camera Configuration
The scripts are configured with the following default settings:
- **Trigger Mode**: Continuous capture (mode 0)
- **Exposure**: Manual, 30ms
- **Output Format**:
- Monochrome cameras: MONO8
- Color cameras: BGR8
- **Image Processing**: Automatic ISP processing from RAW to RGB/MONO
## Output
Images are saved in the `images/` directory with the following naming convention:
```
image_XX_YYYYMMDD_HHMMSS_mmm.jpg
```
Where:
- `XX` = Image number (01-10)
- `YYYYMMDD_HHMMSS_mmm` = Timestamp with milliseconds
Example: `image_01_20250722_140530_123.jpg`
## Troubleshooting
### Common Issues
1. **"No camera was found!"**
- Check camera connection (Ethernet cable)
- Verify camera power
- Check network settings (camera and PC should be on same subnet)
- Ensure camera drivers are installed
2. **"CameraInit Failed"**
- Camera might be in use by another application
- Check camera permissions
- Try restarting the camera or PC
3. **"Failed to capture image"**
- Check camera settings
- Verify sufficient lighting
- Check exposure settings
4. **Images appear upside down**
- This is handled automatically on Windows
- Linux users may need to adjust the flip settings
### Network Configuration
For GigE cameras, ensure:
- Camera and PC are on the same network segment
- PC network adapter supports Jumbo frames (recommended)
- Firewall allows camera communication
- Sufficient network bandwidth
## Customization
You can modify the scripts to:
- **Change capture count**: Modify the range in the capture loop
- **Adjust timing**: Change the `time.sleep(0.2)` value
- **Modify exposure**: Change the exposure time parameter
- **Change output format**: Modify file format and quality settings
- **Add image processing**: Insert processing steps before saving
## SDK Reference
The camera SDK (`mvsdk.py`) provides extensive functionality:
- Camera enumeration and initialization
- Image capture and processing
- Parameter configuration (exposure, gain, etc.)
- Trigger modes and timing
- Image format conversion
- Error handling
Refer to the original SDK documentation for advanced features.

View File

@@ -0,0 +1,184 @@
# USDA Vision Camera System - Implementation Summary
## 🎉 Project Completed Successfully!
The USDA Vision Camera System has been fully implemented and tested. All components are working correctly and the system is ready for deployment.
## ✅ What Was Built
### Core Architecture
- **Modular Design**: Clean separation of concerns across multiple modules
- **Multi-threading**: Concurrent MQTT listening, camera monitoring, and recording
- **Event-driven**: Thread-safe communication between components
- **Configuration-driven**: JSON-based configuration system
### Key Components
1. **MQTT Integration** (`usda_vision_system/mqtt/`)
- Listens to two machine topics: `vision/vibratory_conveyor/state` and `vision/blower_separator/state`
- Thread-safe message handling with automatic reconnection
- State normalization (on/off/error)
2. **Camera Management** (`usda_vision_system/camera/`)
- Automatic GigE camera discovery using python demo library
- Periodic status monitoring (every 2 seconds)
- Camera initialization and configuration management
- **Discovered Cameras**:
- Blower-Yield-Cam (192.168.1.165)
- Cracker-Cam (192.168.1.167)
3. **Video Recording** (`usda_vision_system/camera/recorder.py`)
- Automatic recording start/stop based on machine states
- Timestamp-based file naming: `camera1_recording_20250726_143022.avi`
- Configurable FPS, exposure, and gain settings
- Thread-safe recording with proper cleanup
4. **Storage Management** (`usda_vision_system/storage/`)
- Organized file storage under `./storage/camera1/` and `./storage/camera2/`
- File indexing and metadata tracking
- Automatic cleanup of old files
- Storage statistics and integrity checking
5. **REST API Server** (`usda_vision_system/api/`)
- FastAPI server on port 8000
- Real-time WebSocket updates
- Manual recording control endpoints
- System status and monitoring endpoints
6. **Comprehensive Logging** (`usda_vision_system/core/logging_config.py`)
- Colored console output
- Rotating log files
- Component-specific log levels
- Performance monitoring and error tracking
## 🚀 How to Use
### Quick Start
```bash
# Run system tests
python test_system.py
# Start the system
python main.py
# Or use the startup script
./start_system.sh
```
### Configuration
Edit `config.json` to customize:
- MQTT broker settings
- Camera configurations
- Storage paths
- System parameters
### API Access
- System status: `http://localhost:8000/system/status`
- Camera status: `http://localhost:8000/cameras`
- Manual recording: `POST http://localhost:8000/cameras/camera1/start-recording`
- Real-time updates: WebSocket at `ws://localhost:8000/ws`
## 📊 Test Results
All system tests passed successfully:
- ✅ Module imports
- ✅ Configuration loading
- ✅ Camera discovery (found 2 cameras)
- ✅ Storage setup
- ✅ MQTT configuration
- ✅ System initialization
- ✅ API endpoints
## 🔧 System Behavior
### Automatic Recording Flow
1. **Machine turns ON** → MQTT message received → Recording starts automatically
2. **Machine turns OFF** → MQTT message received → Recording stops and saves file
3. **Files saved** with timestamp: `camera1_recording_YYYYMMDD_HHMMSS.avi`
### Manual Control
- Start/stop recording via API calls
- Monitor system status in real-time
- Check camera availability on demand
### Dashboard Integration
The system is designed to integrate with your React + Vite + Tailwind + Supabase dashboard:
- REST API for status queries
- WebSocket for real-time updates
- JSON responses for easy frontend consumption
## 📁 Project Structure
```
usda_vision_system/
├── core/ # Configuration, state management, events, logging
├── mqtt/ # MQTT client and message handlers
├── camera/ # Camera management, monitoring, recording
├── storage/ # File organization and management
├── api/ # FastAPI server and WebSocket support
└── main.py # Application coordinator
Supporting Files:
├── main.py # Entry point script
├── config.json # System configuration
├── test_system.py # Test suite
├── start_system.sh # Startup script
└── README_SYSTEM.md # Comprehensive documentation
```
## 🎯 Key Features Delivered
-**Dual MQTT topic listening** for two machines
-**Automatic camera recording** triggered by machine states
-**GigE camera support** using python demo library
-**Thread-safe multi-tasking** (MQTT + camera monitoring + recording)
-**Timestamp-based file naming** in organized directories
-**2-second camera status monitoring** with on-demand checks
-**REST API and WebSocket** for dashboard integration
-**Comprehensive logging** with error tracking
-**Configuration management** via JSON
-**Storage management** with cleanup capabilities
-**Graceful startup/shutdown** with signal handling
## 🔮 Ready for Dashboard Integration
The system provides everything needed for your React dashboard:
```javascript
// Example API usage
const systemStatus = await fetch('http://localhost:8000/system/status');
const cameras = await fetch('http://localhost:8000/cameras');
// WebSocket for real-time updates
const ws = new WebSocket('ws://localhost:8000/ws');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
// Handle real-time system updates
};
// Manual recording control
await fetch('http://localhost:8000/cameras/camera1/start-recording', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ camera_name: 'camera1' })
});
```
## 🎊 Next Steps
The system is production-ready! You can now:
1. **Deploy** the system on your target hardware
2. **Integrate** with your existing React dashboard
3. **Configure** MQTT topics and camera settings as needed
4. **Monitor** system performance through logs and API endpoints
5. **Extend** functionality as requirements evolve
The modular architecture makes it easy to add new features, cameras, or MQTT topics in the future.
---
**System Status**: ✅ **FULLY OPERATIONAL**
**Test Results**: ✅ **ALL TESTS PASSING**
**Cameras Detected**: ✅ **2 GIGE CAMERAS READY**
**Ready for Production**: ✅ **YES**

View File

@@ -0,0 +1 @@
# USDA-Vision-Cameras

View File

@@ -0,0 +1,249 @@
# USDA Vision Camera System
A comprehensive system for monitoring machines via MQTT and automatically recording video from GigE cameras when machines are active.
## Overview
This system integrates MQTT machine monitoring with automated video recording from GigE cameras. When a machine turns on (detected via MQTT), the system automatically starts recording from the associated camera. When the machine turns off, recording stops and the video is saved with a timestamp.
## Features
- **MQTT Integration**: Listens to multiple machine state topics
- **Automatic Recording**: Starts/stops recording based on machine states
- **GigE Camera Support**: Uses the python demo 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
- **Storage Management**: Organized file storage with cleanup capabilities
- **Comprehensive Logging**: Detailed logging with rotation and error tracking
- **Configuration Management**: JSON-based configuration system
## Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MQTT Broker │ │ GigE Camera │ │ Dashboard │
│ │ │ │ │ (React) │
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
│ │ │
│ Machine States │ Video Streams │ API Calls
│ │ │
┌─────────▼──────────────────────▼──────────────────────▼───────┐
│ USDA Vision Camera System │
├───────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MQTT Client │ │ Camera │ │ API Server │ │
│ │ │ │ Manager │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ State │ │ Storage │ │ Event │ │
│ │ Manager │ │ Manager │ │ System │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────────────┘
```
## Installation
1. **Prerequisites**:
- Python 3.11+
- GigE cameras with python demo library
- MQTT broker (e.g., Mosquitto)
- uv package manager (recommended)
2. **Install Dependencies**:
```bash
uv sync
```
3. **Setup Storage Directory**:
```bash
sudo mkdir -p /storage
sudo chown $USER:$USER /storage
```
## Configuration
Edit `config.json` to configure your system:
```json
{
"mqtt": {
"broker_host": "192.168.1.110",
"broker_port": 1883,
"topics": {
"vibratory_conveyor": "vision/vibratory_conveyor/state",
"blower_separator": "vision/blower_separator/state"
}
},
"cameras": [
{
"name": "camera1",
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1",
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 3.0,
"enabled": true
}
]
}
```
## Usage
### Basic Usage
1. **Start the System**:
```bash
python main.py
```
2. **With Custom Config**:
```bash
python main.py --config my_config.json
```
3. **Debug Mode**:
```bash
python main.py --log-level DEBUG
```
### API Endpoints
The system provides a REST API on port 8000:
- `GET /system/status` - Overall system status
- `GET /cameras` - All camera statuses
- `GET /machines` - All machine states
- `POST /cameras/{name}/start-recording` - Manual recording start
- `POST /cameras/{name}/stop-recording` - Manual recording stop
- `GET /storage/stats` - Storage statistics
- `WebSocket /ws` - Real-time updates
### Dashboard Integration
The system is designed to integrate with your existing React + Vite + Tailwind + Supabase dashboard:
1. **API Integration**: Use the REST endpoints to display system status
2. **WebSocket**: Connect to `/ws` for real-time updates
3. **Supabase Storage**: Store recording metadata and system logs
## File Organization
```
/storage/
├── camera1/
│ ├── camera1_recording_20250726_143022.avi
│ └── camera1_recording_20250726_143155.avi
├── camera2/
│ ├── camera2_recording_20250726_143025.avi
│ └── camera2_recording_20250726_143158.avi
└── file_index.json
```
## Monitoring and Logging
### Log Files
- `usda_vision_system.log` - Main system log (rotated)
- Console output with colored formatting
- Component-specific log levels
### Performance Monitoring
The system includes built-in performance monitoring:
- Startup times
- Recording session metrics
- MQTT message processing rates
- Camera status check intervals
### Error Tracking
Comprehensive error tracking with:
- Error counts per component
- Detailed error context
- Automatic recovery attempts
## Troubleshooting
### Common Issues
1. **Camera Not Found**:
- Check camera connections
- Verify python demo library installation
- Run camera discovery: Check logs for enumeration results
2. **MQTT Connection Failed**:
- Verify broker IP and port
- Check network connectivity
- Verify credentials if authentication is enabled
3. **Recording Fails**:
- Check storage permissions
- Verify available disk space
- Check camera initialization logs
4. **API Server Won't Start**:
- Check if port 8000 is available
- Verify FastAPI dependencies
- Check firewall settings
### Debug Commands
```bash
# Check system status
curl http://localhost:8000/system/status
# Check camera status
curl http://localhost:8000/cameras
# Manual recording start
curl -X POST http://localhost:8000/cameras/camera1/start-recording \
-H "Content-Type: application/json" \
-d '{"camera_name": "camera1"}'
```
## Development
### Project Structure
```
usda_vision_system/
├── core/ # Core functionality
├── mqtt/ # MQTT client and handlers
├── camera/ # Camera management and recording
├── storage/ # File management
├── api/ # FastAPI server
└── main.py # Application coordinator
```
### Adding New Features
1. **New Camera Type**: Extend `camera/recorder.py`
2. **New MQTT Topics**: Update `config.json` and `mqtt/handlers.py`
3. **New API Endpoints**: Add to `api/server.py`
4. **New Events**: Define in `core/events.py`
### Testing
```bash
# Run basic system test
python -c "from usda_vision_system import USDAVisionSystem; s = USDAVisionSystem(); print('OK')"
# Test MQTT connection
python -c "from usda_vision_system.mqtt.client import MQTTClient; # ... test code"
# Test camera discovery
python -c "import sys; sys.path.append('python demo'); import mvsdk; print(len(mvsdk.CameraEnumerateDevice()))"
```
## License
This project is developed for USDA research purposes.
## Support
For issues and questions:
1. Check the logs in `usda_vision_system.log`
2. Review the troubleshooting section
3. Check API status at `http://localhost:8000/health`

View File

@@ -0,0 +1,190 @@
# Time Synchronization Setup - Atlanta, Georgia
## ✅ Time Synchronization Complete!
The USDA Vision Camera System has been configured for proper time synchronization with Atlanta, Georgia (Eastern Time Zone).
## 🕐 What Was Implemented
### System-Level Time Configuration
- **Timezone**: Set to `America/New_York` (Eastern Time)
- **Current Status**: Eastern Daylight Time (EDT, UTC-4)
- **NTP Sync**: Configured with multiple reliable time servers
- **Hardware Clock**: Synchronized with system time
### Application-Level Timezone Support
- **Timezone-Aware Timestamps**: All recordings use Atlanta time
- **Automatic DST Handling**: Switches between EST/EDT automatically
- **Time Sync Monitoring**: Built-in time synchronization checking
- **Consistent Formatting**: Standardized timestamp formats throughout
## 🔧 Key Features
### 1. Automatic Time Synchronization
```bash
# NTP servers configured:
- time.nist.gov (NIST atomic clock)
- pool.ntp.org (NTP pool)
- time.google.com (Google time)
- time.cloudflare.com (Cloudflare time)
```
### 2. Timezone-Aware Recording Filenames
```
Example: camera1_recording_20250725_213241.avi
Format: {camera}_{type}_{YYYYMMDD_HHMMSS}.avi
Time: Atlanta local time (EDT/EST)
```
### 3. Time Verification Tools
- **Startup Check**: Automatic time sync verification on system start
- **Manual Check**: `python check_time.py` for on-demand verification
- **API Integration**: Time sync status available via REST API
### 4. Comprehensive Logging
```
=== TIME SYNCHRONIZATION STATUS ===
System time: 2025-07-25 21:32:41 EDT
Timezone: EDT (-0400)
Daylight Saving: Yes
Sync status: synchronized
Time difference: 0.10 seconds
=====================================
```
## 🚀 Usage
### Automatic Operation
The system automatically:
- Uses Atlanta time for all timestamps
- Handles daylight saving time transitions
- Monitors time synchronization status
- Logs time-related events
### Manual Verification
```bash
# Check time synchronization
python check_time.py
# Test timezone functions
python test_timezone.py
# View system time status
timedatectl status
```
### API Endpoints
```bash
# System status includes time info
curl http://localhost:8000/system/status
# Example response includes:
{
"system_started": true,
"uptime_seconds": 3600,
"timestamp": "2025-07-25T21:32:41-04:00"
}
```
## 📊 Current Status
### Time Synchronization
-**System Timezone**: America/New_York (EDT)
-**NTP Sync**: Active and synchronized
-**Time Accuracy**: Within 0.1 seconds of atomic time
-**DST Support**: Automatic EST/EDT switching
### Application Integration
-**Recording Timestamps**: Atlanta time zone
-**Log Timestamps**: Timezone-aware logging
-**API Responses**: ISO format with timezone
-**File Naming**: Consistent Atlanta time format
### Monitoring
-**Startup Verification**: Time sync checked on boot
-**Continuous Monitoring**: Built-in sync status tracking
-**Error Detection**: Alerts for time drift issues
-**Manual Tools**: On-demand verification scripts
## 🔍 Technical Details
### Timezone Configuration
```json
{
"system": {
"timezone": "America/New_York"
}
}
```
### Time Sources
1. **Primary**: NIST atomic clock (time.nist.gov)
2. **Secondary**: NTP pool servers (pool.ntp.org)
3. **Backup**: Google/Cloudflare time servers
4. **Fallback**: Local system clock
### File Naming Convention
```
Pattern: {camera_name}_recording_{YYYYMMDD_HHMMSS}.avi
Example: camera1_recording_20250725_213241.avi
Timezone: Always Atlanta local time (EST/EDT)
```
## 🎯 Benefits
### For Operations
- **Consistent Timestamps**: All recordings use Atlanta time
- **Easy Correlation**: Timestamps match local business hours
- **Automatic DST**: No manual timezone adjustments needed
- **Reliable Sync**: Multiple time sources ensure accuracy
### For Analysis
- **Local Time Context**: Recordings timestamped in business timezone
- **Accurate Sequencing**: Precise timing for event correlation
- **Standard Format**: Consistent naming across all recordings
- **Audit Trail**: Complete time synchronization logging
### For Integration
- **Dashboard Ready**: Timezone-aware API responses
- **Database Compatible**: ISO format timestamps with timezone
- **Log Analysis**: Structured time information in logs
- **Monitoring**: Built-in time sync health checks
## 🔧 Maintenance
### Regular Checks
The system automatically:
- Verifies time sync on startup
- Logs time synchronization status
- Monitors for time drift
- Alerts on sync failures
### Manual Maintenance
```bash
# Force time sync
sudo systemctl restart systemd-timesyncd
# Check NTP status
timedatectl show-timesync --all
# Verify timezone
timedatectl status
```
## 📈 Next Steps
The time synchronization is now fully operational. The system will:
1. **Automatically maintain** accurate Atlanta time
2. **Generate timestamped recordings** with local time
3. **Monitor sync status** and alert on issues
4. **Provide timezone-aware** API responses for dashboard integration
All recording files will now have accurate Atlanta timestamps, making it easy to correlate with local business operations and machine schedules.
---
**Time Sync Status**: ✅ **SYNCHRONIZED**
**Timezone**: ✅ **America/New_York (EDT)**
**Accuracy**: ✅ **±0.1 seconds**
**Ready for Production**: ✅ **YES**

View File

@@ -0,0 +1,191 @@
# Camera Video Recorder
A Python script for recording videos from GigE cameras using the provided SDK with custom exposure and gain settings.
## Features
- **List all available cameras** - Automatically detects and displays all connected cameras
- **Custom camera settings** - Set exposure time to 1ms and gain to 3.5x (or custom values)
- **Video recording** - Record videos in AVI format with timestamp filenames
- **Live preview** - Test camera functionality with live preview mode
- **Interactive menu** - User-friendly menu system for all operations
- **Automatic cleanup** - Proper resource management and cleanup
## Requirements
- Python 3.x
- OpenCV (`cv2`)
- NumPy
- Camera SDK (mvsdk) - included in `python demo` directory
- GigE camera connected to the system
## Installation
1. Ensure your GigE camera is connected and properly configured
2. Make sure the `python demo` directory with `mvsdk.py` is present
3. Install required Python packages:
```bash
pip install opencv-python numpy
```
## Usage
### Basic Usage
Run the script:
```bash
python camera_video_recorder.py
```
The script will:
1. Display a welcome message and feature overview
2. List all available cameras
3. Let you select a camera (if multiple are available)
4. Allow you to set custom exposure and gain values
5. Present an interactive menu with options
### Menu Options
1. **Start Recording** - Begin video recording with timestamp filename
2. **List Camera Info** - Display detailed camera information
3. **Test Camera (Live Preview)** - View live camera feed without recording
4. **Exit** - Clean up and exit the program
### Default Settings
- **Exposure Time**: 1.0ms (1000 microseconds)
- **Gain**: 3.5x
- **Video Format**: AVI with XVID codec
- **Frame Rate**: 30 FPS
- **Output Directory**: `videos/` (created automatically)
### Recording Controls
- **Start Recording**: Select option 1 from the menu
- **Stop Recording**: Press 'q' in the preview window
- **Video Files**: Saved as `videos/camera_recording_YYYYMMDD_HHMMSS.avi`
## File Structure
```
camera_video_recorder.py # Main script
python demo/
mvsdk.py # Camera SDK wrapper
(other demo files)
videos/ # Output directory (created automatically)
camera_recording_*.avi # Recorded video files
```
## Script Features
### CameraVideoRecorder Class
- `list_cameras()` - Enumerate and display available cameras
- `initialize_camera()` - Set up camera with custom exposure and gain
- `start_recording()` - Initialize video writer and begin recording
- `stop_recording()` - Stop recording and save video file
- `record_loop()` - Main recording loop with live preview
- `cleanup()` - Proper resource cleanup
### Key Functions
- **Camera Detection**: Automatically finds all connected GigE cameras
- **Settings Validation**: Checks and clamps exposure/gain values to camera limits
- **Frame Processing**: Handles both monochrome and color cameras
- **Windows Compatibility**: Handles frame flipping for Windows systems
- **Error Handling**: Comprehensive error handling and user feedback
## Example Output
```
Camera Video Recorder
====================
This script allows you to:
- List all available cameras
- Record videos with custom exposure (1ms) and gain (3.5x) settings
- Save videos with timestamps
- Stop recording anytime with 'q' key
Found 1 camera(s):
0: GigE Camera Model (GigE) - SN: 12345678
Using camera: GigE Camera Model
Camera Settings:
Enter exposure time in ms (default 1.0): 1.0
Enter gain value (default 3.5): 3.5
Initializing camera with:
- Exposure: 1.0ms
- Gain: 3.5x
Camera type: Color
Set exposure time: 1000.0μs
Set analog gain: 3.50x (range: 1.00 - 16.00)
Camera started successfully
==================================================
Camera Video Recorder Menu
==================================================
1. Start Recording
2. List Camera Info
3. Test Camera (Live Preview)
4. Exit
Select option (1-4): 1
Started recording to: videos/camera_recording_20241223_143022.avi
Frame size: (1920, 1080), FPS: 30.0
Press 'q' to stop recording...
Recording... Press 'q' in the preview window to stop
Recording stopped!
Saved: videos/camera_recording_20241223_143022.avi
Frames recorded: 450
Duration: 15.2 seconds
Average FPS: 29.6
```
## Troubleshooting
### Common Issues
1. **"No cameras found!"**
- Check camera connection
- Verify camera power
- Ensure network configuration for GigE cameras
2. **"SDK initialization failed"**
- Verify `python demo/mvsdk.py` exists
- Check camera drivers are installed
3. **"Camera initialization failed"**
- Camera may be in use by another application
- Try disconnecting and reconnecting the camera
4. **Recording issues**
- Ensure sufficient disk space
- Check write permissions in the output directory
### Performance Tips
- Close other applications using the camera
- Ensure adequate system resources (CPU, RAM)
- Use SSD storage for better write performance
- Adjust frame rate if experiencing dropped frames
## Customization
You can modify the script to:
- Change video codec (currently XVID)
- Adjust target frame rate
- Modify output filename format
- Add additional camera settings
- Change preview window size
## Notes
- Videos are saved in the `videos/` directory with timestamp filenames
- The script handles both monochrome and color cameras automatically
- Frame flipping is handled automatically for Windows systems
- All resources are properly cleaned up on exit

View File

@@ -0,0 +1,524 @@
### USDA Vision Camera Streaming API
###
### CONFIGURATION:
### - Production: http://vision:8000 (requires hostname setup)
### - Development: http://localhost:8000
### - Custom: Update @baseUrl below to match your setup
###
### This file contains streaming-specific API endpoints for live camera preview
### Use with VS Code REST Client extension or similar tools.
# Base URL - Update to match your configuration
@baseUrl = http://vision:8000
# Alternative: @baseUrl = http://localhost:8000
### =============================================================================
### STREAMING ENDPOINTS (NEW FUNCTIONALITY)
### =============================================================================
### Start camera streaming for live preview
### This creates a separate camera connection that doesn't interfere with recording
POST {{baseUrl}}/cameras/camera1/start-stream
Content-Type: application/json
### Expected Response:
# {
# "success": true,
# "message": "Started streaming for camera camera1"
# }
###
### Stop camera streaming
POST {{baseUrl}}/cameras/camera1/stop-stream
Content-Type: application/json
### Expected Response:
# {
# "success": true,
# "message": "Stopped streaming for camera camera1"
# }
###
### Get live MJPEG stream (open in browser or use as img src)
### This endpoint returns a continuous MJPEG stream
### Content-Type: multipart/x-mixed-replace; boundary=frame
GET {{baseUrl}}/cameras/camera1/stream
### Usage in HTML:
# <img src="http://localhost:8000/cameras/camera1/stream" alt="Live Stream" />
### Usage in React:
# <img src={`${apiBaseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`} />
###
### Start streaming for camera2
POST {{baseUrl}}/cameras/camera2/start-stream
Content-Type: application/json
###
### Get live stream for camera2
GET {{baseUrl}}/cameras/camera2/stream
###
### Stop streaming for camera2
POST {{baseUrl}}/cameras/camera2/stop-stream
Content-Type: application/json
### =============================================================================
### CONCURRENT OPERATIONS TESTING
### =============================================================================
### Test Scenario: Streaming + Recording Simultaneously
### This demonstrates that streaming doesn't block recording
### Step 1: Start streaming first
POST {{baseUrl}}/cameras/camera1/start-stream
Content-Type: application/json
###
### Step 2: Start recording (while streaming continues)
POST {{baseUrl}}/cameras/camera1/start-recording
Content-Type: application/json
{
"filename": "concurrent_test.avi"
}
###
### Step 3: Check both are running
GET {{baseUrl}}/cameras/camera1
### Expected Response shows both recording and streaming active:
# {
# "camera1": {
# "name": "camera1",
# "status": "connected",
# "is_recording": true,
# "current_recording_file": "concurrent_test.avi",
# "recording_start_time": "2025-01-28T10:30:00.000Z"
# }
# }
###
### Step 4: Stop recording (streaming continues)
POST {{baseUrl}}/cameras/camera1/stop-recording
Content-Type: application/json
###
### Step 5: Verify streaming still works
GET {{baseUrl}}/cameras/camera1/stream
###
### Step 6: Stop streaming
POST {{baseUrl}}/cameras/camera1/stop-stream
Content-Type: application/json
### =============================================================================
### MULTIPLE CAMERA STREAMING
### =============================================================================
### Start streaming on multiple cameras simultaneously
POST {{baseUrl}}/cameras/camera1/start-stream
Content-Type: application/json
###
POST {{baseUrl}}/cameras/camera2/start-stream
Content-Type: application/json
###
### Check status of all cameras
GET {{baseUrl}}/cameras
###
### Access multiple streams (open in separate browser tabs)
GET {{baseUrl}}/cameras/camera1/stream
###
GET {{baseUrl}}/cameras/camera2/stream
###
### Stop all streaming
POST {{baseUrl}}/cameras/camera1/stop-stream
Content-Type: application/json
###
POST {{baseUrl}}/cameras/camera2/stop-stream
Content-Type: application/json
### =============================================================================
### ERROR TESTING
### =============================================================================
### Test with invalid camera name
POST {{baseUrl}}/cameras/invalid_camera/start-stream
Content-Type: application/json
### Expected Response:
# {
# "detail": "Camera streamer not found: invalid_camera"
# }
###
### Test stream endpoint without starting stream first
GET {{baseUrl}}/cameras/camera1/stream
### Expected: May return error or empty stream depending on camera state
###
### Test starting stream when camera is in error state
POST {{baseUrl}}/cameras/camera1/start-stream
Content-Type: application/json
### If camera has issues, expected response:
# {
# "success": false,
# "message": "Failed to start streaming for camera camera1"
# }
### =============================================================================
### INTEGRATION EXAMPLES FOR AI ASSISTANTS
### =============================================================================
### React Component Integration:
# const CameraStream = ({ cameraName }) => {
# const [isStreaming, setIsStreaming] = useState(false);
#
# const startStream = async () => {
# const response = await fetch(`${baseUrl}/cameras/${cameraName}/start-stream`, {
# method: 'POST'
# });
# if (response.ok) {
# setIsStreaming(true);
# }
# };
#
# return (
# <div>
# <button onClick={startStream}>Start Stream</button>
# {isStreaming && (
# <img src={`${baseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`} />
# )}
# </div>
# );
# };
### JavaScript Fetch Example:
# const streamAPI = {
# async startStream(cameraName) {
# const response = await fetch(`${baseUrl}/cameras/${cameraName}/start-stream`, {
# method: 'POST',
# headers: { 'Content-Type': 'application/json' }
# });
# return response.json();
# },
#
# async stopStream(cameraName) {
# const response = await fetch(`${baseUrl}/cameras/${cameraName}/stop-stream`, {
# method: 'POST',
# headers: { 'Content-Type': 'application/json' }
# });
# return response.json();
# },
#
# getStreamUrl(cameraName) {
# return `${baseUrl}/cameras/${cameraName}/stream?t=${Date.now()}`;
# }
# };
### Vue.js Integration:
# <template>
# <div>
# <button @click="startStream">Start Stream</button>
# <img v-if="isStreaming" :src="streamUrl" />
# </div>
# </template>
#
# <script>
# export default {
# data() {
# return {
# isStreaming: false,
# cameraName: 'camera1'
# };
# },
# computed: {
# streamUrl() {
# return `${this.baseUrl}/cameras/${this.cameraName}/stream?t=${Date.now()}`;
# }
# },
# methods: {
# async startStream() {
# const response = await fetch(`${this.baseUrl}/cameras/${this.cameraName}/start-stream`, {
# method: 'POST'
# });
# if (response.ok) {
# this.isStreaming = true;
# }
# }
# }
# };
# </script>
### =============================================================================
### TROUBLESHOOTING
### =============================================================================
### If streams don't start:
# 1. Check camera status: GET /cameras
# 2. Verify system health: GET /health
# 3. Test camera connection: POST /cameras/{name}/test-connection
# 4. Check if camera is already recording (shouldn't matter, but good to know)
### If stream image doesn't load:
# 1. Verify stream was started: POST /cameras/{name}/start-stream
# 2. Check browser console for CORS errors
# 3. Try accessing stream URL directly in browser
# 4. Add timestamp to prevent caching: ?t=${Date.now()}
### If concurrent operations fail:
# 1. This should work - streaming and recording use separate connections
# 2. Check system logs for resource conflicts
# 3. Verify sufficient system resources (CPU/Memory)
# 4. Test with one camera first, then multiple
### Performance Notes:
# - Streaming uses ~10 FPS by default (configurable)
# - JPEG quality set to 70% (configurable)
# - Each stream uses additional CPU/memory
# - Multiple concurrent streams may impact performance
### =============================================================================
### CAMERA CONFIGURATION ENDPOINTS (NEW)
### =============================================================================
### Get camera configuration
GET {{baseUrl}}/cameras/camera1/config
### Expected Response:
# {
# "name": "camera1",
# "machine_topic": "vibratory_conveyor",
# "storage_path": "/storage/camera1",
# "enabled": true,
# "exposure_ms": 1.0,
# "gain": 3.5,
# "target_fps": 0,
# "sharpness": 120,
# "contrast": 110,
# "saturation": 100,
# "gamma": 100,
# "noise_filter_enabled": true,
# "denoise_3d_enabled": false,
# "auto_white_balance": true,
# "color_temperature_preset": 0,
# "anti_flicker_enabled": true,
# "light_frequency": 1,
# "bit_depth": 8,
# "hdr_enabled": false,
# "hdr_gain_mode": 0
# }
###
### Update basic camera settings (real-time, no restart required)
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"exposure_ms": 2.0,
"gain": 4.0,
"target_fps": 10.0
}
###
### Update image quality settings
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"sharpness": 150,
"contrast": 120,
"saturation": 110,
"gamma": 90
}
###
### Update advanced settings
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"anti_flicker_enabled": true,
"light_frequency": 1,
"auto_white_balance": false,
"color_temperature_preset": 2
}
###
### Enable HDR mode
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"hdr_enabled": true,
"hdr_gain_mode": 1
}
###
### Update noise reduction settings (requires restart)
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"noise_filter_enabled": false,
"denoise_3d_enabled": true
}
###
### Apply configuration (restart camera with new settings)
POST {{baseUrl}}/cameras/camera1/apply-config
### Expected Response:
# {
# "success": true,
# "message": "Configuration applied to camera camera1"
# }
###
### Get camera2 configuration
GET {{baseUrl}}/cameras/camera2/config
###
### Update camera2 for outdoor lighting
PUT {{baseUrl}}/cameras/camera2/config
Content-Type: application/json
{
"exposure_ms": 0.5,
"gain": 2.0,
"sharpness": 130,
"contrast": 115,
"anti_flicker_enabled": true,
"light_frequency": 1
}
### =============================================================================
### CONFIGURATION TESTING SCENARIOS
### =============================================================================
### Scenario 1: Low light optimization
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"exposure_ms": 5.0,
"gain": 8.0,
"noise_filter_enabled": true,
"denoise_3d_enabled": true
}
###
### Scenario 2: High speed capture
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"exposure_ms": 0.2,
"gain": 1.0,
"target_fps": 30.0,
"sharpness": 180
}
###
### Scenario 3: Color accuracy for food inspection
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"auto_white_balance": false,
"color_temperature_preset": 1,
"saturation": 120,
"contrast": 105,
"gamma": 95
}
###
### Scenario 4: HDR for high contrast scenes
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"hdr_enabled": true,
"hdr_gain_mode": 2,
"exposure_ms": 1.0,
"gain": 3.0
}
### =============================================================================
### ERROR TESTING FOR CONFIGURATION
### =============================================================================
### Test invalid camera name
GET {{baseUrl}}/cameras/invalid_camera/config
###
### Test invalid exposure range
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"exposure_ms": 2000.0
}
### Expected: HTTP 422 validation error
###
### Test invalid gain range
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{
"gain": 50.0
}
### Expected: HTTP 422 validation error
###
### Test empty configuration update
PUT {{baseUrl}}/cameras/camera1/config
Content-Type: application/json
{}
### Expected: HTTP 400 "No configuration updates provided"

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""
Test script to verify the frame conversion fix works correctly.
"""
import sys
import os
import numpy as np
# Add the current directory to Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# Add camera SDK to path
sys.path.append(os.path.join(os.path.dirname(__file__), "camera_sdk"))
try:
import mvsdk
print("✅ mvsdk imported successfully")
except ImportError as e:
print(f"❌ Failed to import mvsdk: {e}")
sys.exit(1)
def test_frame_conversion():
"""Test the frame conversion logic"""
print("🧪 Testing frame conversion logic...")
# Simulate frame data
width, height = 640, 480
frame_size = width * height * 3 # RGB
# Create mock frame data
mock_frame_data = np.random.randint(0, 255, frame_size, dtype=np.uint8)
# Create a mock frame buffer (simulate memory address)
frame_buffer = mock_frame_data.ctypes.data
# Create mock FrameHead
class MockFrameHead:
def __init__(self):
self.iWidth = width
self.iHeight = height
self.uBytes = frame_size
frame_head = MockFrameHead()
try:
# Test the conversion logic (similar to what's in streamer.py)
frame_data_buffer = (mvsdk.c_ubyte * frame_head.uBytes).from_address(frame_buffer)
frame_data = np.frombuffer(frame_data_buffer, dtype=np.uint8)
frame = frame_data.reshape((frame_head.iHeight, frame_head.iWidth, 3))
print(f"✅ Frame conversion successful!")
print(f" Frame shape: {frame.shape}")
print(f" Frame dtype: {frame.dtype}")
print(f" Frame size: {frame.size} bytes")
return True
except Exception as e:
print(f"❌ Frame conversion failed: {e}")
return False
def main():
print("🔧 Frame Conversion Test")
print("=" * 40)
success = test_frame_conversion()
if success:
print("\n✅ Frame conversion fix is working correctly!")
print("📋 The streaming issue should be resolved after system restart.")
else:
print("\n❌ Frame conversion fix needs more work.")
print("\n💡 To apply the fix:")
print("1. Restart the USDA vision system")
print("2. Test streaming again")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
"""
Test script for camera streaming functionality.
This script tests the new streaming capabilities without interfering with recording.
"""
import sys
import os
import time
import requests
import threading
from datetime import datetime
# Add the current directory to Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def test_api_endpoints():
"""Test the streaming API endpoints"""
base_url = "http://localhost:8000"
print("🧪 Testing Camera Streaming API Endpoints")
print("=" * 50)
# Test system status
try:
response = requests.get(f"{base_url}/system/status", timeout=5)
if response.status_code == 200:
print("✅ System status endpoint working")
data = response.json()
print(f" System: {data.get('status', 'Unknown')}")
print(f" Camera Manager: {'Running' if data.get('camera_manager_running') else 'Stopped'}")
else:
print(f"❌ System status endpoint failed: {response.status_code}")
except Exception as e:
print(f"❌ System status endpoint error: {e}")
# Test camera list
try:
response = requests.get(f"{base_url}/cameras", timeout=5)
if response.status_code == 200:
print("✅ Camera list endpoint working")
cameras = response.json()
print(f" Found {len(cameras)} cameras: {list(cameras.keys())}")
# Test streaming for each camera
for camera_name in cameras.keys():
test_camera_streaming(base_url, camera_name)
else:
print(f"❌ Camera list endpoint failed: {response.status_code}")
except Exception as e:
print(f"❌ Camera list endpoint error: {e}")
def test_camera_streaming(base_url, camera_name):
"""Test streaming for a specific camera"""
print(f"\n🎥 Testing streaming for {camera_name}")
print("-" * 30)
# Test start streaming
try:
response = requests.post(f"{base_url}/cameras/{camera_name}/start-stream", timeout=10)
if response.status_code == 200:
print(f"✅ Start stream endpoint working for {camera_name}")
data = response.json()
print(f" Response: {data.get('message', 'No message')}")
else:
print(f"❌ Start stream failed for {camera_name}: {response.status_code}")
print(f" Error: {response.text}")
return
except Exception as e:
print(f"❌ Start stream error for {camera_name}: {e}")
return
# Wait a moment for stream to initialize
time.sleep(2)
# Test stream endpoint (just check if it responds)
try:
response = requests.get(f"{base_url}/cameras/{camera_name}/stream", timeout=5, stream=True)
if response.status_code == 200:
print(f"✅ Stream endpoint responding for {camera_name}")
print(f" Content-Type: {response.headers.get('content-type', 'Unknown')}")
# Read a small amount of data to verify it's working
chunk_count = 0
for chunk in response.iter_content(chunk_size=1024):
chunk_count += 1
if chunk_count >= 3: # Read a few chunks then stop
break
print(f" Received {chunk_count} data chunks")
else:
print(f"❌ Stream endpoint failed for {camera_name}: {response.status_code}")
except Exception as e:
print(f"❌ Stream endpoint error for {camera_name}: {e}")
# Test stop streaming
try:
response = requests.post(f"{base_url}/cameras/{camera_name}/stop-stream", timeout=5)
if response.status_code == 200:
print(f"✅ Stop stream endpoint working for {camera_name}")
data = response.json()
print(f" Response: {data.get('message', 'No message')}")
else:
print(f"❌ Stop stream failed for {camera_name}: {response.status_code}")
except Exception as e:
print(f"❌ Stop stream error for {camera_name}: {e}")
def test_concurrent_recording_and_streaming():
"""Test that streaming doesn't interfere with recording"""
base_url = "http://localhost:8000"
print("\n🔄 Testing Concurrent Recording and Streaming")
print("=" * 50)
try:
# Get available cameras
response = requests.get(f"{base_url}/cameras", timeout=5)
if response.status_code != 200:
print("❌ Cannot get camera list for concurrent test")
return
cameras = response.json()
if not cameras:
print("❌ No cameras available for concurrent test")
return
camera_name = list(cameras.keys())[0] # Use first camera
print(f"Using camera: {camera_name}")
# Start streaming
print("1. Starting streaming...")
response = requests.post(f"{base_url}/cameras/{camera_name}/start-stream", timeout=10)
if response.status_code != 200:
print(f"❌ Failed to start streaming: {response.text}")
return
time.sleep(2)
# Start recording
print("2. Starting recording...")
response = requests.post(f"{base_url}/cameras/{camera_name}/start-recording",
json={"filename": "test_concurrent_recording.avi"}, timeout=10)
if response.status_code == 200:
print("✅ Recording started successfully while streaming")
else:
print(f"❌ Failed to start recording while streaming: {response.text}")
# Let both run for a few seconds
print("3. Running both streaming and recording for 5 seconds...")
time.sleep(5)
# Stop recording
print("4. Stopping recording...")
response = requests.post(f"{base_url}/cameras/{camera_name}/stop-recording", timeout=5)
if response.status_code == 200:
print("✅ Recording stopped successfully")
else:
print(f"❌ Failed to stop recording: {response.text}")
# Stop streaming
print("5. Stopping streaming...")
response = requests.post(f"{base_url}/cameras/{camera_name}/stop-stream", timeout=5)
if response.status_code == 200:
print("✅ Streaming stopped successfully")
else:
print(f"❌ Failed to stop streaming: {response.text}")
print("✅ Concurrent test completed successfully!")
except Exception as e:
print(f"❌ Concurrent test error: {e}")
def main():
"""Main test function"""
print("🚀 USDA Vision Camera Streaming Test")
print("=" * 50)
print(f"Test started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
# Wait for system to be ready
print("⏳ Waiting for system to be ready...")
time.sleep(3)
# Run tests
test_api_endpoints()
test_concurrent_recording_and_streaming()
print("\n" + "=" * 50)
print("🏁 Test completed!")
print("\n📋 Next Steps:")
print("1. Open camera_preview.html in your browser")
print("2. Click 'Start Stream' for any camera")
print("3. Verify live preview works without blocking recording")
print("4. Test concurrent recording and streaming")
if __name__ == "__main__":
main()