Refactor camera management to conditionally import SDK and handle mock mode; update API base URL references to localhost in documentation and code.

This commit is contained in:
salirezav
2025-08-08 13:20:31 -04:00
parent fc2da16728
commit 20907509b1
17 changed files with 404 additions and 121 deletions

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ camera-management-api/usda_vision_system.log
# Docker
*.pid
camera-management-api/camera_sdk/

View File

@@ -7,14 +7,14 @@ This guide is specifically designed for AI assistants to understand and implemen
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)
- **Base URL**: `http://localhost: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)
- **Production**: `http://localhost: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
@@ -77,7 +77,7 @@ GET /cameras/{camera_name}/stream
```jsx
import React, { useState, useEffect } from 'react';
const CameraStream = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => {
const CameraStream = ({ cameraName, apiBaseUrl = 'http://localhost:8000' }) => {
const [isStreaming, setIsStreaming] = useState(false);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
@@ -227,7 +227,7 @@ export default CameraStream;
import React, { useState, useEffect } from 'react';
import CameraStream from './CameraStream';
const CameraDashboard = ({ apiBaseUrl = 'http://vision:8000' }) => {
const CameraDashboard = ({ apiBaseUrl = 'http://localhost:8000' }) => {
const [cameras, setCameras] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -315,7 +315,7 @@ export default CameraDashboard;
```jsx
import { useState, useEffect, useCallback } from 'react';
const useCameraStream = (cameraName, apiBaseUrl = 'http://vision:8000') => {
const useCameraStream = (cameraName, apiBaseUrl = 'http://localhost:8000') => {
const [isStreaming, setIsStreaming] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
@@ -451,7 +451,7 @@ const CameraStreamTailwind = ({ cameraName }) => {
### Environment Variables (.env)
```env
# Production configuration (using 'vision' hostname)
REACT_APP_CAMERA_API_URL=http://vision:8000
REACT_APP_CAMERA_API_URL=http://localhost:8000
REACT_APP_STREAM_REFRESH_INTERVAL=30000
REACT_APP_STREAM_TIMEOUT=10000
@@ -465,7 +465,7 @@ REACT_APP_STREAM_TIMEOUT=10000
### API Configuration
```javascript
const apiConfig = {
baseUrl: process.env.REACT_APP_CAMERA_API_URL || 'http://vision:8000',
baseUrl: process.env.REACT_APP_CAMERA_API_URL || 'http://localhost:8000',
timeout: parseInt(process.env.REACT_APP_STREAM_TIMEOUT) || 10000,
refreshInterval: parseInt(process.env.REACT_APP_STREAM_REFRESH_INTERVAL) || 30000,
};

View File

@@ -3,18 +3,18 @@
#
# CONFIGURATION:
# - Default Base URL: http://localhost:8000 (local development)
# - Production Base URL: http://vision:8000 (when using hostname 'vision')
# - Production Base URL: http://localhost:8000 (when using hostname 'vision')
# - Custom hostname: Update @baseUrl variable below
#
# HOSTNAME SETUP:
# To use 'vision' hostname instead of 'localhost':
# 1. Add to /etc/hosts: 127.0.0.1 vision
# 2. Or configure DNS to point 'vision' to the server IP
# 3. Update camera_preview.html: API_BASE = 'http://vision:8000'
# 3. Update camera_preview.html: API_BASE = 'http://localhost:8000'
###############################################################################
# Base URL Configuration - Change this to match your setup
@baseUrl = http://vision:8000
@baseUrl = http://localhost:8000
# Alternative configurations:
# @baseUrl = http://localhost:8000 # Local development
# @baseUrl = http://192.168.1.100:8000 # Specific IP address
@@ -30,8 +30,8 @@
# - Requires hostname resolution setup
# - Add to /etc/hosts: 127.0.0.1 vision
# - Or configure DNS: vision -> server IP address
# - Update camera_preview.html: API_BASE = 'http://vision:8000'
# - Set @baseUrl = http://vision:8000
# - Update camera_preview.html: API_BASE = 'http://localhost:8000'
# - Set @baseUrl = http://localhost:8000
# Option 2: Using localhost (development)
# - Works immediately on local machine

View File

@@ -16,7 +16,7 @@ export interface ApiConfig {
}
export const defaultApiConfig: ApiConfig = {
baseUrl: 'http://vision:8000', // Production default, change to 'http://localhost:8000' for development
baseUrl: 'http://localhost:8000', // Production default, change to 'http://localhost:8000' for development
timeout: 10000,
refreshInterval: 30000,
};

View File

@@ -1,7 +1,7 @@
### USDA Vision Camera Streaming API
###
### CONFIGURATION:
### - Production: http://vision:8000 (requires hostname setup)
### - Production: http://localhost:8000 (requires hostname setup)
### - Development: http://localhost:8000
### - Custom: Update @baseUrl below to match your setup
###
@@ -9,7 +9,7 @@
### Use with VS Code REST Client extension or similar tools.
# Base URL - Update to match your configuration
@baseUrl = http://vision:8000
@baseUrl = http://localhost:8000
# Alternative: @baseUrl = http://localhost:8000
### =============================================================================

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,43 +12,43 @@
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);
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%;
@@ -58,14 +59,14 @@
min-height: 200px;
display: block;
}
.camera-controls {
margin-top: 10px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
padding: 8px 16px;
border: none;
@@ -74,80 +75,80 @@
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;
@@ -155,18 +156,19 @@
}
</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>
@@ -178,18 +180,18 @@
</div>
<script>
const API_BASE = 'http://vision:8000';
const API_BASE = 'http://localhost: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 {
@@ -202,13 +204,13 @@
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>
@@ -222,18 +224,18 @@
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');
@@ -254,22 +256,22 @@
`;
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();
@@ -280,21 +282,21 @@
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();
@@ -305,7 +307,7 @@
updateStatus(cameraName, `Error stopping stream: ${error.message}`, 'error');
}
}
// Refresh stream for a camera
function refreshStream(cameraName) {
const streamImg = document.getElementById(`stream-${cameraName}`);
@@ -316,21 +318,22 @@
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>
</html>

View File

@@ -1,5 +1,9 @@
# This file was autogenerated by uv via the following command:
# uv export --format requirements-txt
aiofiles==24.1.0 \
--hash=sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c \
--hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5
# via usda-vision-cameras
annotated-types==0.7.0 \
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
@@ -7,11 +11,61 @@ annotated-types==0.7.0 \
anyio==4.9.0 \
--hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \
--hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c
# via starlette
# via
# httpx
# starlette
appnope==0.1.4 ; sys_platform == 'darwin' \
--hash=sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee \
--hash=sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c
# via ipykernel
asttokens==3.0.0 \
--hash=sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7 \
--hash=sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2
# via stack-data
certifi==2025.7.14 \
--hash=sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2 \
--hash=sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995
# via requests
# via
# httpcore
# httpx
# requests
cffi==1.17.1 ; implementation_name == 'pypy' \
--hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
--hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
--hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
--hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
--hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
--hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
--hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
--hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
--hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
--hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
--hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
--hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
--hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
--hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
--hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
--hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
--hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
--hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
--hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
--hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
--hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
--hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via pyzmq
charset-normalizer==3.4.2 \
--hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \
--hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \
@@ -64,7 +118,12 @@ colorama==0.4.6 ; sys_platform == 'win32' \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
# via
# click
# ipython
# tqdm
comm==0.2.3 \
--hash=sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971 \
--hash=sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417
# via ipykernel
contourpy==1.3.2 \
--hash=sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f \
--hash=sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92 \
@@ -115,6 +174,30 @@ cycler==0.12.1 \
--hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \
--hash=sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c
# via matplotlib
debugpy==1.8.15 \
--hash=sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc \
--hash=sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba \
--hash=sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00 \
--hash=sha256:62954fb904bec463e2b5a415777f6d1926c97febb08ef1694da0e5d1463c5c3b \
--hash=sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683 \
--hash=sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6 \
--hash=sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327 \
--hash=sha256:babc4fb1962dd6a37e94d611280e3d0d11a1f5e6c72ac9b3d87a08212c4b6dd3 \
--hash=sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d \
--hash=sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa \
--hash=sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf \
--hash=sha256:f778e68f2986a58479d0ac4f643e0b8c82fdd97c2e200d4d61e7c2d13838eb53 \
--hash=sha256:f9d1b5abd75cd965e2deabb1a06b0e93a1546f31f9f621d2705e78104377c702 \
--hash=sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709
# via ipykernel
decorator==5.2.1 \
--hash=sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360 \
--hash=sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a
# via ipython
executing==2.2.0 \
--hash=sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa \
--hash=sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755
# via stack-data
fastapi==0.116.1 \
--hash=sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565 \
--hash=sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143
@@ -150,17 +233,54 @@ fonttools==4.59.0 \
h11==0.16.0 \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
# via uvicorn
# via
# httpcore
# uvicorn
httpcore==1.0.9 \
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
# via httpx
httpx==0.28.1 \
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
# via usda-vision-cameras
idna==3.10 \
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via
# anyio
# httpx
# requests
imageio==2.37.0 \
--hash=sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed \
--hash=sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996
# via usda-vision-cameras
ipykernel==6.30.0 \
--hash=sha256:b7b808ddb2d261aae2df3a26ff3ff810046e6de3dfbc6f7de8c98ea0a6cb632c \
--hash=sha256:fd2936e55c4a1c2ee8b1e5fa6a372b8eecc0ab1338750dee76f48fa5cca1301e
# via usda-vision-cameras
ipython==9.4.0 \
--hash=sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066 \
--hash=sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270
# via ipykernel
ipython-pygments-lexers==1.1.1 \
--hash=sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81 \
--hash=sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c
# via ipython
jedi==0.19.2 \
--hash=sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0 \
--hash=sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9
# via ipython
jupyter-client==8.6.3 \
--hash=sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419 \
--hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
# via ipykernel
jupyter-core==5.8.1 \
--hash=sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941 \
--hash=sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0
# via
# ipykernel
# jupyter-client
kiwisolver==1.4.8 \
--hash=sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50 \
--hash=sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8 \
@@ -249,6 +369,16 @@ matplotlib==3.10.3 \
--hash=sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158 \
--hash=sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b
# via usda-vision-cameras
matplotlib-inline==0.1.7 \
--hash=sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90 \
--hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
# via
# ipykernel
# ipython
nest-asyncio==1.6.0 \
--hash=sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe \
--hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
# via ipykernel
numpy==2.3.2 \
--hash=sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5 \
--hash=sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b \
@@ -342,11 +472,21 @@ opencv-python==4.11.0.86 \
packaging==25.0 \
--hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
--hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
# via matplotlib
# via
# ipykernel
# matplotlib
paho-mqtt==2.1.0 \
--hash=sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834 \
--hash=sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee
# via usda-vision-cameras
parso==0.8.4 \
--hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 \
--hash=sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d
# via jedi
pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' \
--hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
--hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
# via ipython
pillow==11.3.0 \
--hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \
--hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \
@@ -429,6 +569,36 @@ pillow==11.3.0 \
# imageio
# matplotlib
# usda-vision-cameras
platformdirs==4.3.8 \
--hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \
--hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4
# via jupyter-core
prompt-toolkit==3.0.51 \
--hash=sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07 \
--hash=sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed
# via ipython
psutil==7.0.0 \
--hash=sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25 \
--hash=sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91 \
--hash=sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da \
--hash=sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34 \
--hash=sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553 \
--hash=sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456 \
--hash=sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993 \
--hash=sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99
# via ipykernel
ptyprocess==0.7.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' \
--hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
--hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220
# via pexpect
pure-eval==0.2.3 \
--hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 \
--hash=sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42
# via stack-data
pycparser==2.22 ; implementation_name == 'pypy' \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
pydantic==2.11.7 \
--hash=sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db \
--hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b
@@ -490,6 +660,12 @@ pydantic-core==2.33.2 \
--hash=sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6 \
--hash=sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d
# via pydantic
pygments==2.19.2 \
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
# via
# ipython
# ipython-pygments-lexers
pyparsing==3.2.3 \
--hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \
--hash=sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be
@@ -497,11 +673,66 @@ pyparsing==3.2.3 \
python-dateutil==2.9.0.post0 \
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
# via matplotlib
# via
# jupyter-client
# matplotlib
pytz==2025.2 \
--hash=sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3 \
--hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00
# via usda-vision-cameras
pywin32==311 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32' \
--hash=sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151 \
--hash=sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87 \
--hash=sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503 \
--hash=sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d \
--hash=sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31 \
--hash=sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a \
--hash=sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42 \
--hash=sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2 \
--hash=sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee \
--hash=sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067 \
--hash=sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852 \
--hash=sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d
# via jupyter-core
pyzmq==27.0.0 \
--hash=sha256:0546a720c1f407b2172cb04b6b094a78773491497e3644863cf5c96c42df8cff \
--hash=sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22 \
--hash=sha256:14fe7aaac86e4e93ea779a821967360c781d7ac5115b3f1a171ced77065a0174 \
--hash=sha256:15f39d50bd6c9091c67315ceb878a4f531957b121d2a05ebd077eb35ddc5efed \
--hash=sha256:1958947983fef513e6e98eff9cb487b60bf14f588dc0e6bf35fa13751d2c8251 \
--hash=sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef \
--hash=sha256:21457825249b2a53834fa969c69713f8b5a79583689387a5e7aed880963ac564 \
--hash=sha256:2c386339d7e3f064213aede5d03d054b237937fbca6dd2197ac8cf3b25a6b14e \
--hash=sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152 \
--hash=sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e \
--hash=sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d \
--hash=sha256:60e8cc82d968174650c1860d7b716366caab9973787a1c060cf8043130f7d0f7 \
--hash=sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38 \
--hash=sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9 \
--hash=sha256:6ad0562d4e6abb785be3e4dd68599c41be821b521da38c402bc9ab2a8e7ebc7e \
--hash=sha256:7011ade88c8e535cf140f8d1a59428676fbbce7c6e54fefce58bf117aefb6667 \
--hash=sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a \
--hash=sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4 \
--hash=sha256:9df43a2459cd3a3563404c1456b2c4c69564daa7dbaf15724c09821a3329ce46 \
--hash=sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad \
--hash=sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf \
--hash=sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44 \
--hash=sha256:c0dc628b5493f9a8cd9844b8bee9732ef587ab00002157c9329e4fc0ef4d3afa \
--hash=sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d \
--hash=sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688 \
--hash=sha256:c5817641eebb391a2268c27fecd4162448e03538387093cdbd8bf3510c316b38 \
--hash=sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371 \
--hash=sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3 \
--hash=sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52 \
--hash=sha256:cd1dc59763effd1576f8368047c9c31468fce0af89d76b5067641137506792ae \
--hash=sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f \
--hash=sha256:dc1091f59143b471d19eb64f54bae4f54bcf2a466ffb66fe45d94d8d734eb495 \
--hash=sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371 \
--hash=sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be \
--hash=sha256:f7bbe9e1ed2c8d3da736a15694d87c12493e54cc9dc9790796f0321794bbc91f
# via
# ipykernel
# jupyter-client
requests==2.32.4 \
--hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \
--hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422
@@ -514,20 +745,50 @@ sniffio==1.3.1 \
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
# via anyio
stack-data==0.6.3 \
--hash=sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9 \
--hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
# via ipython
starlette==0.47.2 \
--hash=sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8 \
--hash=sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b
# via fastapi
tornado==6.5.1 \
--hash=sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7 \
--hash=sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692 \
--hash=sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331 \
--hash=sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e \
--hash=sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a \
--hash=sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c \
--hash=sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b \
--hash=sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6 \
--hash=sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888 \
--hash=sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401 \
--hash=sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7 \
--hash=sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365
# via
# ipykernel
# jupyter-client
tqdm==4.67.1 \
--hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \
--hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2
# via usda-vision-cameras
traitlets==5.14.3 \
--hash=sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7 \
--hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
# via
# ipykernel
# ipython
# jupyter-client
# jupyter-core
# matplotlib-inline
typing-extensions==4.14.1 \
--hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \
--hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76
# via
# anyio
# fastapi
# ipython
# pydantic
# pydantic-core
# starlette
@@ -544,6 +805,10 @@ uvicorn==0.35.0 \
--hash=sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a \
--hash=sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01
# via usda-vision-cameras
wcwidth==0.2.13 \
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
# via prompt-toolkit
websockets==15.0.1 \
--hash=sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2 \
--hash=sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5 \

View File

@@ -12,9 +12,15 @@ import logging
from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime
# Add camera SDK to path
# Add camera SDK to path and import conditionally
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk"))
import mvsdk
try:
import mvsdk
CAMERA_SDK_AVAILABLE = True
except (ImportError, OSError) as e:
# Camera SDK not available - system will run in mock mode
mvsdk = None
CAMERA_SDK_AVAILABLE = False
from ..core.config import Config, CameraConfig
from ..core.state_manager import StateManager, CameraStatus
@@ -35,8 +41,11 @@ class CameraManager:
self.event_system = event_system
self.logger = logging.getLogger(__name__)
# Initialize SDK early to suppress error messages
initialize_sdk_with_suppression()
# Initialize SDK early to suppress error messages (if available)
if CAMERA_SDK_AVAILABLE:
initialize_sdk_with_suppression()
else:
self.logger.warning("Camera SDK not available - running in mock mode")
# Camera management
self.available_cameras: List[Any] = [] # mvsdk camera device info
@@ -111,6 +120,11 @@ class CameraManager:
try:
self.logger.info("Discovering GigE cameras...")
if not CAMERA_SDK_AVAILABLE:
self.logger.warning("Camera SDK not available - no cameras will be discovered")
self.available_cameras = []
return
# Enumerate cameras using mvsdk
device_list = mvsdk.CameraEnumerateDevice()
self.available_cameras = device_list

View File

@@ -1,10 +1,10 @@
# Environment Configuration for Pecan Experiments Application
# USDA Vision Camera System API Configuration
# Default: http://vision:8000 (current working setup)
# Default: http://localhost:8000 (current working setup)
# For localhost setup, use: http://localhost:8000
# For remote systems, use: http://192.168.1.100:8000 (replace with actual IP)
VITE_VISION_API_URL=http://vision:8000
VITE_VISION_API_URL=http://localhost:8000
# Supabase Configuration (if needed for production)
# VITE_SUPABASE_URL=your_supabase_url

View File

@@ -40,7 +40,7 @@ The Vision System dashboard provides real-time monitoring and control of the USD
## API Integration
The dashboard connects to the Vision System API running on `http://vision:8000` and provides:
The dashboard connects to the Vision System API running on `http://localhost:8000` and provides:
### Endpoints Used
- `GET /system/status` - System overview and status
@@ -103,7 +103,7 @@ The dashboard includes comprehensive error handling:
### Common Issues
1. **"Failed to fetch vision system data"**
- Ensure the vision system API is running on vision:8000
- Ensure the vision system API is running on localhost:8000
- Check network connectivity
- Verify the vision system service is started
@@ -121,7 +121,7 @@ The dashboard includes comprehensive error handling:
The API base URL is configured in `src/lib/visionApi.ts`:
```typescript
const VISION_API_BASE_URL = 'http://vision:8000'
const VISION_API_BASE_URL = 'http://localhost:8000'
```
To change the API endpoint, modify this constant and rebuild the application.

View File

@@ -1,6 +1,6 @@
###############################################################################
# USDA Vision Camera System - Complete API Endpoints Documentation
# Base URL: http://vision:8000
# Base URL: http://localhost:8000
###############################################################################
###############################################################################
@@ -8,7 +8,7 @@
###############################################################################
### Root endpoint - API information
GET http://vision:8000/
GET http://localhost:8000/
# Response: SuccessResponse
# {
# "success": true,
@@ -20,7 +20,7 @@ GET http://vision:8000/
###
### Health check
GET http://vision:8000/health
GET http://localhost:8000/health
# Response: Simple health status
# {
# "status": "healthy",
@@ -30,7 +30,7 @@ GET http://vision:8000/health
###
### Get system status
GET http://vision:8000/system/status
GET http://localhost:8000/system/status
# Response: SystemStatusResponse
# {
# "system_started": true,
@@ -60,7 +60,7 @@ GET http://vision:8000/system/status
###############################################################################
### Get all machines status
GET http://vision:8000/machines
GET http://localhost:8000/machines
# Response: Dict[str, MachineStatusResponse]
# {
# "vibratory_conveyor": {
@@ -84,7 +84,7 @@ GET http://vision:8000/machines
###############################################################################
### Get MQTT status and statistics
GET http://vision:8000/mqtt/status
GET http://localhost:8000/mqtt/status
# Response: MQTTStatusResponse
# {
# "connected": true,
@@ -101,7 +101,7 @@ GET http://vision:8000/mqtt/status
# }
### Get recent MQTT events history
GET http://vision:8000/mqtt/events
GET http://localhost:8000/mqtt/events
# Optional query parameter: limit (default: 5, max: 50)
# Response: MQTTEventsHistoryResponse
# {
@@ -128,14 +128,14 @@ GET http://vision:8000/mqtt/events
# }
### Get recent MQTT events with custom limit
GET http://vision:8000/mqtt/events?limit=10
GET http://localhost:8000/mqtt/events?limit=10
###############################################################################
# CAMERA ENDPOINTS
###############################################################################
### Get all cameras status
GET http://vision:8000/cameras
GET http://localhost:8000/cameras
# Response: Dict[str, CameraStatusResponse]
# {
# "camera1": {
@@ -157,9 +157,9 @@ GET http://vision:8000/cameras
###
### Get specific camera status
GET http://vision:8000/cameras/camera1/status
GET http://localhost:8000/cameras/camera1/status
### Get specific camera status
GET http://vision:8000/cameras/camera2/status
GET http://localhost:8000/cameras/camera2/status
# Response: CameraStatusResponse (same as above for single camera)
###############################################################################
@@ -167,7 +167,7 @@ GET http://vision:8000/cameras/camera2/status
###############################################################################
### Start recording (with all optional parameters)
POST http://vision:8000/cameras/camera1/start-recording
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
@@ -193,7 +193,7 @@ Content-Type: application/json
###
### Start recording (minimal - only filename)
POST http://vision:8000/cameras/camera1/start-recording
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
@@ -203,7 +203,7 @@ Content-Type: application/json
###
### Start recording (only camera settings)
POST http://vision:8000/cameras/camera1/start-recording
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{
@@ -215,7 +215,7 @@ Content-Type: application/json
###
### Start recording (empty body - all defaults)
POST http://vision:8000/cameras/camera1/start-recording
POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json
{}
@@ -223,9 +223,9 @@ Content-Type: application/json
###
### Stop recording
POST http://vision:8000/cameras/camera1/stop-recording
POST http://localhost:8000/cameras/camera1/stop-recording
### Stop recording
POST http://vision:8000/cameras/camera2/stop-recording
POST http://localhost:8000/cameras/camera2/stop-recording
# No request body required
# Response: StopRecordingResponse
# {
@@ -239,8 +239,8 @@ POST http://vision:8000/cameras/camera2/stop-recording
###############################################################################
### Test camera connection
POST http://vision:8000/cameras/camera1/test-connection
POST http://vision:8000/cameras/camera2/test-connection
POST http://localhost:8000/cameras/camera1/test-connection
POST http://localhost:8000/cameras/camera2/test-connection
# No request body required
# Response: CameraTestResponse
# {
@@ -253,8 +253,8 @@ POST http://vision:8000/cameras/camera2/test-connection
###
### Reconnect camera (soft recovery)
POST http://vision:8000/cameras/camera1/reconnect
POST http://vision:8000/cameras/camera2/reconnect
POST http://localhost:8000/cameras/camera1/reconnect
POST http://localhost:8000/cameras/camera2/reconnect
# No request body required
# Response: CameraRecoveryResponse
# {
@@ -268,33 +268,33 @@ POST http://vision:8000/cameras/camera2/reconnect
###
### Restart camera grab process
POST http://vision:8000/cameras/camera1/restart-grab
POST http://vision:8000/cameras/camera2/restart-grab
POST http://localhost:8000/cameras/camera1/restart-grab
POST http://localhost:8000/cameras/camera2/restart-grab
# Response: CameraRecoveryResponse (same structure as reconnect)
###
### Reset camera timestamp
POST http://vision:8000/cameras/camera1/reset-timestamp
POST http://vision:8000/cameras/camera2/reset-timestamp
POST http://localhost:8000/cameras/camera1/reset-timestamp
POST http://localhost:8000/cameras/camera2/reset-timestamp
# Response: CameraRecoveryResponse (same structure as reconnect)
###
### Full camera reset (hard recovery)
POST http://vision:8000/cameras/camera1/full-reset
POST http://localhost:8000/cameras/camera1/full-reset
### Full camera reset (hard recovery)
POST http://vision:8000/cameras/camera2/full-reset
POST http://localhost:8000/cameras/camera2/full-reset
# Response: CameraRecoveryResponse (same structure as reconnect)
###
### Reinitialize failed camera
POST http://vision:8000/cameras/camera1/reinitialize
POST http://localhost:8000/cameras/camera1/reinitialize
### Reinitialize failed camera
POST http://vision:8000/cameras/camera2/reinitialize
POST http://localhost:8000/cameras/camera2/reinitialize
# Response: CameraRecoveryResponse (same structure as reconnect)
###############################################################################
@@ -302,7 +302,7 @@ POST http://vision:8000/cameras/camera2/reinitialize
###############################################################################
### Get all recording sessions
GET http://vision:8000/recordings
GET http://localhost:8000/recordings
# Response: Dict[str, RecordingInfoResponse]
# {
# "rec_001": {
@@ -323,7 +323,7 @@ GET http://vision:8000/recordings
###############################################################################
### Get storage statistics
GET http://vision:8000/storage/stats
GET http://localhost:8000/storage/stats
# Response: StorageStatsResponse
# {
# "base_path": "/storage",
@@ -345,7 +345,7 @@ GET http://vision:8000/storage/stats
###
### Get recording files list (with filters)
POST http://vision:8000/storage/files
POST http://localhost:8000/storage/files
Content-Type: application/json
{
@@ -377,7 +377,7 @@ Content-Type: application/json
###
### Get all files (no camera filter)
POST http://vision:8000/storage/files
POST http://localhost:8000/storage/files
Content-Type: application/json
{
@@ -387,7 +387,7 @@ Content-Type: application/json
###
### Cleanup old storage files
POST http://vision:8000/storage/cleanup
POST http://localhost:8000/storage/cleanup
Content-Type: application/json
{

View File

@@ -46,10 +46,10 @@ Create a `.env` file with the following configuration:
```bash
# USDA Vision Camera System API Configuration
# Default: http://vision:8000 (Docker container)
# Default: http://localhost:8000 (Docker container)
# For local development without Docker: http://localhost:8000
# For remote systems: http://192.168.1.100:8000
VITE_VISION_API_URL=http://vision:8000
VITE_VISION_API_URL=http://localhost:8000
```
### API Endpoints Used

View File

@@ -16,8 +16,8 @@ import {
import { performanceMonitor } from '../utils/performanceMonitor';
// Configuration - Use environment variable or default to vision container
// The API is accessible at vision:8000 in the current setup
const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://vision:8000';
// The API is accessible at localhost:8000 in the current setup
const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000';
/**
* Custom error class for video API errors

View File

@@ -1,7 +1,7 @@
// Vision System API Client
// Base URL for the vision system API - Use environment variable or default to vision container
// The API is accessible at vision:8000 in the current setup
const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://vision:8000'
// The API is accessible at localhost:8000 in the current setup
const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000'
// Types based on the API documentation
export interface SystemStatus {

View File

@@ -3,7 +3,7 @@
class TestVisionApiClient {
constructor() {
this.baseUrl = 'http://vision:8000'
this.baseUrl = 'http://localhost:8000'
}
async request(endpoint) {

View File

@@ -81,7 +81,7 @@
<script src="test-api-fix.js"></script>
<script>
const API_BASE = 'http://vision:8000'; // Change to your vision API URL if different
const API_BASE = 'http://localhost:8000'; // Change to your vision API URL if different
async function testCameraList() {
const resultsDiv = document.getElementById('test-results');

View File

@@ -106,7 +106,7 @@
</div>
<script>
const API_BASE = 'http://vision:8000';
const API_BASE = 'http://localhost:8000';
let cameras = {};
// Load cameras on page load