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.frame_timeout = 5.0 # Timeout after 5 seconds without frames
|
||||||
self.reconnect_interval = 5.0 # Try to reconnect every 5 seconds
|
self.reconnect_interval = 5.0 # Try to reconnect every 5 seconds
|
||||||
self.last_reconnect_attempt = 0
|
self.last_reconnect_attempt = 0
|
||||||
|
self.connection_retries = 0
|
||||||
|
self.max_retries = 3
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start the camera stream"""
|
"""Start the camera stream with improved error handling"""
|
||||||
if self.running:
|
if self.running:
|
||||||
return
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.is_network_camera:
|
if self.is_network_camera:
|
||||||
@@ -315,6 +317,16 @@ class CameraStream:
|
|||||||
|
|
||||||
logger.info(f"Connecting to network camera: {url}")
|
logger.info(f"Connecting to network camera: {url}")
|
||||||
self.cap = cv2.VideoCapture(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:
|
else:
|
||||||
# Handle local camera
|
# Handle local camera
|
||||||
self.cap = cv2.VideoCapture(self.camera_id)
|
self.cap = cv2.VideoCapture(self.camera_id)
|
||||||
@@ -329,6 +341,7 @@ class CameraStream:
|
|||||||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||||
|
|
||||||
self.running = True
|
self.running = True
|
||||||
|
self.connection_retries = 0
|
||||||
self.thread = threading.Thread(target=self._capture_loop)
|
self.thread = threading.Thread(target=self._capture_loop)
|
||||||
self.thread.daemon = True
|
self.thread.daemon = True
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
@@ -338,6 +351,7 @@ class CameraStream:
|
|||||||
if self.cap:
|
if self.cap:
|
||||||
self.cap.release()
|
self.cap.release()
|
||||||
self.cap = None
|
self.cap = None
|
||||||
|
self.connection_retries += 1
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@@ -356,15 +370,23 @@ class CameraStream:
|
|||||||
break
|
break
|
||||||
|
|
||||||
def _capture_loop(self):
|
def _capture_loop(self):
|
||||||
"""Main capture loop with automatic reconnection"""
|
"""Main capture loop with improved error handling and reconnection"""
|
||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
if not self.cap or not self.cap.isOpened():
|
if not self.cap or not self.cap.isOpened():
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if current_time - self.last_reconnect_attempt >= self.reconnect_interval:
|
if current_time - self.last_reconnect_attempt >= self.reconnect_interval:
|
||||||
logger.info(f"Attempting to reconnect camera {self.camera_id}")
|
if self.connection_retries < self.max_retries:
|
||||||
self.last_reconnect_attempt = current_time
|
logger.info(f"Attempting to reconnect camera {self.camera_id}")
|
||||||
self.start()
|
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)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -511,10 +533,16 @@ def video_feed(camera_id):
|
|||||||
return Response(gen_frames(camera_id),
|
return Response(gen_frames(camera_id),
|
||||||
mimetype='multipart/x-mixed-replace; boundary=frame')
|
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')
|
@app.route('/cameras')
|
||||||
def get_cameras():
|
def get_cameras():
|
||||||
"""Get list of available cameras"""
|
"""Get list of available cameras"""
|
||||||
# Scan for local cameras silently
|
# Get local cameras
|
||||||
cameras = scan_cameras_silently()
|
cameras = scan_cameras_silently()
|
||||||
|
|
||||||
# Add network cameras
|
# Add network cameras
|
||||||
@@ -523,7 +551,9 @@ def get_cameras():
|
|||||||
cameras.append({
|
cameras.append({
|
||||||
'id': f'net:{name}',
|
'id': f'net:{name}',
|
||||||
'type': 'network',
|
'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
|
# Add status information for active cameras
|
||||||
@@ -536,7 +566,7 @@ def get_cameras():
|
|||||||
camera['active'] = False
|
camera['active'] = False
|
||||||
camera['status'] = 'disconnected'
|
camera['status'] = 'disconnected'
|
||||||
|
|
||||||
return jsonify(cameras)
|
return jsonify({'cameras': cameras})
|
||||||
|
|
||||||
@app.route('/add_camera/<path:camera_id>')
|
@app.route('/add_camera/<path:camera_id>')
|
||||||
def add_camera(camera_id):
|
def add_camera(camera_id):
|
||||||
@@ -597,6 +627,109 @@ def load_model():
|
|||||||
success = camera_manager.detector.load_yolo_model(model_dir)
|
success = camera_manager.detector.load_yolo_model(model_dir)
|
||||||
return jsonify({'success': success})
|
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
|
# Reduce camera scanning noise
|
||||||
def scan_cameras_silently():
|
def scan_cameras_silently():
|
||||||
"""Scan for cameras while suppressing OpenCV warnings"""
|
"""Scan for cameras while suppressing OpenCV warnings"""
|
||||||
|
|||||||
Reference in New Issue
Block a user