add services

This commit is contained in:
2026-06-02 22:54:55 +02:00
parent f83e01380c
commit 28bcb6232f
9 changed files with 160 additions and 37 deletions
+18 -21
View File
@@ -9,23 +9,26 @@ import os
import threading
import time
from datetime import datetime
from flask import Flask, Response, jsonify, render_template, send_from_directory
from flask import Flask, Response, jsonify, render_template, send_from_directory
from libcamera import Transform
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput
from PIL import Image
# ─── Configuration ────────────────────────────────────────────────────────────
RESOLUTION = (1280, 720) # Résolution du stream (largeur, hauteur)
FRAMERATE = 30 # Images par seconde
QUALITY = 85 # Qualité JPEG (1-100)
HOST = "0.0.0.0" # Ecoute sur toutes les interfaces réseau
PORT = 5000
RESOLUTION = (1280, 720) # Résolution du stream (largeur, hauteur)
FRAMERATE = 30 # Images par seconde
QUALITY = 85 # Qualité JPEG (1-100)
HOST = "0.0.0.0" # Ecoute sur toutes les interfaces réseau
PORT = 5000
PHOTOS_DIR = os.path.join(os.path.dirname(__file__), "photos")
# ─── Buffer de frames thread-safe ─────────────────────────────────────────────
class StreamOutput(io.BufferedIOBase):
def __init__(self):
self.frame = None
@@ -43,7 +46,8 @@ picam2 = Picamera2()
video_config = picam2.create_video_configuration(
main={"size": RESOLUTION, "format": "RGB888"},
controls={"FrameRate": FRAMERATE}
transform=Transform(rotation=90),
controls={"FrameRate": FRAMERATE},
)
picam2.configure(video_config)
@@ -58,16 +62,14 @@ os.makedirs(PHOTOS_DIR, exist_ok=True)
# ─── Générateur MJPEG ─────────────────────────────────────────────────────────
def generate_frames():
"""Génère un flux MJPEG frame par frame."""
while True:
with output.condition:
output.condition.wait()
frame = output.frame
yield (
b"--frame\r\n"
b"Content-Type: image/jpeg\r\n\r\n" + frame + b"\r\n"
)
yield (b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + frame + b"\r\n")
# ─── Application Flask ────────────────────────────────────────────────────────
@@ -78,10 +80,7 @@ app = Flask(__name__)
@app.route("/")
def index():
return render_template(
"index.html",
width=RESOLUTION[0],
height=RESOLUTION[1],
quality=QUALITY
"index.html", width=RESOLUTION[0], height=RESOLUTION[1], quality=QUALITY
)
@@ -94,8 +93,8 @@ def capture():
filename = datetime.now().strftime("%Y%m%d_%H%M%S.jpg")
filepath = os.path.join(PHOTOS_DIR, filename)
with open(filepath, "wb") as f:
f.write(frame)
image = Image.open(io.BytesIO(frame)).rotate(-90, expand=True)
image.save(filepath, "JPEG", quality=QUALITY)
return jsonify({"status": "ok", "file": filename})
@@ -103,8 +102,7 @@ def capture():
@app.route("/photos")
def photos():
files = sorted(
[f for f in os.listdir(PHOTOS_DIR) if f.endswith(".jpg")],
reverse=True
[f for f in os.listdir(PHOTOS_DIR) if f.endswith(".jpg")], reverse=True
)[:5]
return jsonify(files)
@@ -118,8 +116,7 @@ def photo(filename):
def video_feed():
"""Endpoint du flux MJPEG."""
return Response(
generate_frames(),
mimetype="multipart/x-mixed-replace; boundary=frame"
generate_frames(), mimetype="multipart/x-mixed-replace; boundary=frame"
)