some bullshit
This commit is contained in:
Binary file not shown.
2386
logs/access.log
2386
logs/access.log
File diff suppressed because it is too large
Load Diff
1915
logs/error.log
1915
logs/error.log
File diff suppressed because it is too large
Load Diff
1337
templates/index.html
1337
templates/index.html
File diff suppressed because it is too large
Load Diff
151
web_server.py
151
web_server.py
@@ -284,11 +284,13 @@ class CameraStream:
|
||||
self.frame_timeout = 5.0 # Timeout after 5 seconds without frames
|
||||
self.reconnect_interval = 5.0 # Try to reconnect every 5 seconds
|
||||
self.last_reconnect_attempt = 0
|
||||
self.connection_retries = 0
|
||||
self.max_retries = 3
|
||||
|
||||
def start(self):
|
||||
"""Start the camera stream"""
|
||||
"""Start the camera stream with improved error handling"""
|
||||
if self.running:
|
||||
return
|
||||
return False
|
||||
|
||||
try:
|
||||
if self.is_network_camera:
|
||||
@@ -315,6 +317,16 @@ class CameraStream:
|
||||
|
||||
logger.info(f"Connecting to network camera: {url}")
|
||||
self.cap = cv2.VideoCapture(url)
|
||||
|
||||
# Wait for connection
|
||||
retry_count = 0
|
||||
while not self.cap.isOpened() and retry_count < 3:
|
||||
time.sleep(1)
|
||||
retry_count += 1
|
||||
self.cap.open(url)
|
||||
|
||||
if not self.cap.isOpened():
|
||||
raise Exception(f"Failed to connect to network camera at {url}")
|
||||
else:
|
||||
# Handle local camera
|
||||
self.cap = cv2.VideoCapture(self.camera_id)
|
||||
@@ -329,6 +341,7 @@ class CameraStream:
|
||||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
|
||||
self.running = True
|
||||
self.connection_retries = 0
|
||||
self.thread = threading.Thread(target=self._capture_loop)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
@@ -338,6 +351,7 @@ class CameraStream:
|
||||
if self.cap:
|
||||
self.cap.release()
|
||||
self.cap = None
|
||||
self.connection_retries += 1
|
||||
return False
|
||||
|
||||
def stop(self):
|
||||
@@ -356,15 +370,23 @@ class CameraStream:
|
||||
break
|
||||
|
||||
def _capture_loop(self):
|
||||
"""Main capture loop with automatic reconnection"""
|
||||
"""Main capture loop with improved error handling and reconnection"""
|
||||
while self.running:
|
||||
try:
|
||||
if not self.cap or not self.cap.isOpened():
|
||||
current_time = time.time()
|
||||
if current_time - self.last_reconnect_attempt >= self.reconnect_interval:
|
||||
logger.info(f"Attempting to reconnect camera {self.camera_id}")
|
||||
self.last_reconnect_attempt = current_time
|
||||
self.start()
|
||||
if self.connection_retries < self.max_retries:
|
||||
logger.info(f"Attempting to reconnect camera {self.camera_id}")
|
||||
self.last_reconnect_attempt = current_time
|
||||
if self.start():
|
||||
logger.info(f"Successfully reconnected camera {self.camera_id}")
|
||||
else:
|
||||
logger.warning(f"Failed to reconnect camera {self.camera_id}")
|
||||
else:
|
||||
logger.error(f"Max reconnection attempts reached for camera {self.camera_id}")
|
||||
self.running = False
|
||||
break
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
@@ -511,10 +533,16 @@ def video_feed(camera_id):
|
||||
return Response(gen_frames(camera_id),
|
||||
mimetype='multipart/x-mixed-replace; boundary=frame')
|
||||
|
||||
@app.route('/scan_cameras')
|
||||
def scan_cameras_route():
|
||||
"""Scan and return available cameras"""
|
||||
cameras = scan_cameras_silently()
|
||||
return jsonify({'cameras': cameras})
|
||||
|
||||
@app.route('/cameras')
|
||||
def get_cameras():
|
||||
"""Get list of available cameras"""
|
||||
# Scan for local cameras silently
|
||||
# Get local cameras
|
||||
cameras = scan_cameras_silently()
|
||||
|
||||
# Add network cameras
|
||||
@@ -523,7 +551,9 @@ def get_cameras():
|
||||
cameras.append({
|
||||
'id': f'net:{name}',
|
||||
'type': 'network',
|
||||
'name': f'{name} ({url})'
|
||||
'name': f'{name} ({url})',
|
||||
'width': 1280, # Default width for network cameras
|
||||
'height': 720 # Default height for network cameras
|
||||
})
|
||||
|
||||
# Add status information for active cameras
|
||||
@@ -536,7 +566,7 @@ def get_cameras():
|
||||
camera['active'] = False
|
||||
camera['status'] = 'disconnected'
|
||||
|
||||
return jsonify(cameras)
|
||||
return jsonify({'cameras': cameras})
|
||||
|
||||
@app.route('/add_camera/<path:camera_id>')
|
||||
def add_camera(camera_id):
|
||||
@@ -597,6 +627,109 @@ def load_model():
|
||||
success = camera_manager.detector.load_yolo_model(model_dir)
|
||||
return jsonify({'success': success})
|
||||
|
||||
@app.route('/check_model')
|
||||
def check_model():
|
||||
"""Check YOLO model status"""
|
||||
return jsonify({
|
||||
'model_loaded': camera_manager.detector.model_loaded,
|
||||
'model_name': camera_manager.detector.current_model,
|
||||
'cuda_available': camera_manager.detector.cuda_available
|
||||
})
|
||||
|
||||
@app.route('/model_info')
|
||||
def model_info():
|
||||
"""Get detailed model information"""
|
||||
detector = camera_manager.detector
|
||||
return jsonify({
|
||||
'model_loaded': detector.model_loaded,
|
||||
'model_name': detector.current_model,
|
||||
'cuda_available': detector.cuda_available,
|
||||
'classes': detector.classes,
|
||||
'confidence_threshold': detector.confidence_threshold
|
||||
})
|
||||
|
||||
@app.route('/update_model_settings', methods=['POST'])
|
||||
def update_model_settings():
|
||||
"""Update model settings"""
|
||||
data = request.json
|
||||
if 'confidence_threshold' in data:
|
||||
try:
|
||||
threshold = float(data['confidence_threshold'])
|
||||
if 0 <= threshold <= 1:
|
||||
camera_manager.detector.confidence_threshold = threshold
|
||||
return jsonify({'success': True})
|
||||
except ValueError:
|
||||
pass
|
||||
return jsonify({'success': False, 'error': 'Invalid settings'})
|
||||
|
||||
@app.route('/network_cameras/list')
|
||||
def list_network_cameras():
|
||||
"""List all configured network cameras"""
|
||||
cameras = []
|
||||
for name, info in camera_manager.network_cameras.items():
|
||||
if isinstance(info, dict):
|
||||
cameras.append({
|
||||
'name': name,
|
||||
'url': info['url'],
|
||||
'username': info.get('username'),
|
||||
'has_auth': bool(info.get('username') and info.get('password'))
|
||||
})
|
||||
else:
|
||||
cameras.append({
|
||||
'name': name,
|
||||
'url': info,
|
||||
'has_auth': False
|
||||
})
|
||||
return jsonify({'cameras': cameras})
|
||||
|
||||
@app.route('/network_cameras/remove/<name>', methods=['POST'])
|
||||
def remove_network_camera(name):
|
||||
"""Remove a network camera"""
|
||||
success = camera_manager.remove_network_camera(name)
|
||||
return jsonify({'success': success})
|
||||
|
||||
@app.route('/camera_settings/<path:camera_id>', methods=['GET', 'POST'])
|
||||
def camera_settings(camera_id):
|
||||
"""Get or update camera settings"""
|
||||
camera = camera_manager.get_camera(camera_id)
|
||||
if not camera:
|
||||
return jsonify({'success': False, 'error': 'Camera not found'})
|
||||
|
||||
if request.method == 'POST':
|
||||
data = request.json
|
||||
try:
|
||||
if 'width' in data and 'height' in data:
|
||||
width = int(data['width'])
|
||||
height = int(data['height'])
|
||||
if camera.cap:
|
||||
camera.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||||
camera.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||||
if 'fps' in data:
|
||||
fps = int(data['fps'])
|
||||
if camera.cap:
|
||||
camera.cap.set(cv2.CAP_PROP_FPS, fps)
|
||||
if 'reconnect' in data and data['reconnect']:
|
||||
# Force camera reconnection
|
||||
camera.stop()
|
||||
time.sleep(1) # Wait for cleanup
|
||||
camera.start()
|
||||
return jsonify({'success': True})
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating camera settings: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
else:
|
||||
if not camera.cap:
|
||||
return jsonify({'success': False, 'error': 'Camera not connected'})
|
||||
|
||||
settings = {
|
||||
'width': int(camera.cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
|
||||
'height': int(camera.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
|
||||
'fps': int(camera.cap.get(cv2.CAP_PROP_FPS)),
|
||||
'is_network': camera.is_network_camera,
|
||||
'status': 'connected' if camera.cap and camera.cap.isOpened() else 'disconnected'
|
||||
}
|
||||
return jsonify({'success': True, 'settings': settings})
|
||||
|
||||
# Reduce camera scanning noise
|
||||
def scan_cameras_silently():
|
||||
"""Scan for cameras while suppressing OpenCV warnings"""
|
||||
|
||||
Reference in New Issue
Block a user