from flask import Flask, Response, render_template_string from picamera2 import Picamera2 import io import logging import threading import time app = Flask(__name__) # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') class Camera: def __init__(self, resolution=(640, 480), framerate=30): self.resolution = resolution self.framerate = framerate self.picam2 = None self.frame = None self.lock = threading.Lock() self.running = False self.thread = None def start(self): self.picam2 = Picamera2() config = self.picam2.create_video_configuration( main={"size": self.resolution, "format": "RGB888"}, controls={"FrameRate": self.framerate} ) self.picam2.configure(config) self.picam2.start() # Allow camera to warm up time.sleep(2) self.running = True self.thread = threading.Thread(target=self._capture, daemon=True) self.thread.start() logging.info("Camera started.") def _capture(self): while self.running: try: arr = self.picam2.capture_array() # Encode as JPEG import cv2 ret, buf = cv2.imencode('.jpg', arr) if ret: with self.lock: self.frame = buf.tobytes() time.sleep(0.001) # Brief sleep to yield except Exception as e: logging.error(f"Capture error: {e}") time.sleep(0.1) def get_frame(self): with self.lock: return self.frame def stop(self): self.running = False if self.thread: self.thread.join(timeout=2.0) if self.picam2: self.picam2.stop() self.picam2.close() logging.info("Camera stopped.") camera = None HTML_PAGE = """
{{ resolution }} @ {{ framerate }} fps