From 318e69e626a0c4e056698eda838fa520c48456f9 Mon Sep 17 00:00:00 2001 From: Axel Rafn Date: Thu, 23 Jan 2025 18:24:57 +0100 Subject: [PATCH] Adding more structure and first files --- .gitignore | 1 + README.md | 3 +- python/pypeepr.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 python/pypeepr.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..702ebda --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.ropeproject diff --git a/README.md b/README.md index 8c6cc42..263b2c1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # peepr -A project to make a intelligent peephole with a Raspberry Pi Zero W 2 and a Raspberry camera module \ No newline at end of file +A project to make a intelligent peephole with a Raspberry Pi Zero W 2 and a Raspberry camera module. +The project is focused on two things, code to run the stuff and a 3D model to print to create the physical parts. diff --git a/python/pypeepr.py b/python/pypeepr.py new file mode 100644 index 0000000..1727a8a --- /dev/null +++ b/python/pypeepr.py @@ -0,0 +1,128 @@ +import io +import logging +import socketserver +from http import server +from threading import Condition + +from picamera2 import Picamera2 +from picamera2.encoders import JpegEncoder +from picamera2.outputs import FileOutput + +PAGE = """\ + + + + + + peepr + + + +
+
peepr
+ Webcam Stream +
+ + +""" + +class StreamingOutput(io.BufferedIOBase): + def __init__(self): + self.frame = None + self.condition = Condition() + + def write(self, buf): + with self.condition: + self.frame = buf + self.condition.notify_all() + + +class StreamingHandler(server.BaseHTTPRequestHandler): + def do_GET(self): + if self.path == '/': + self.send_response(301) + self.send_header('Location', '/index.html') + self.end_headers() + elif self.path == '/index.html': + content = PAGE.encode('utf-8') + self.send_response(200) + self.send_header('Content-Type', 'text/html') + self.send_header('Content-Length', len(content)) + self.end_headers() + self.wfile.write(content) + elif self.path == '/stream.mjpg': + self.send_response(200) + self.send_header('Age', 0) + self.send_header('Cache-Control', 'no-cache, private') + self.send_header('Pragma', 'no-cache') + self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME') + self.end_headers() + try: + while True: + with output.condition: + output.condition.wait() + frame = output.frame + self.wfile.write(b'--FRAME\r\n') + self.send_header('Content-Type', 'image/jpeg') + self.send_header('Content-Length', len(frame)) + self.end_headers() + self.wfile.write(frame) + self.wfile.write(b'\r\n') + except Exception as e: + logging.warning( + 'Removed streaming client %s: %s', + self.client_address, str(e)) + else: + self.send_error(404) + self.end_headers() + + +class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer): + allow_reuse_address = True + daemon_threads = True + + +picam2 = Picamera2() +picam2.configure(picam2.create_video_configuration(main={"size": (800, 480)})) +output = StreamingOutput() +picam2.start_recording(JpegEncoder(), FileOutput(output)) + +try: + address = ('', 7123) + server = StreamingServer(address, StreamingHandler) + server.serve_forever() +finally: + picam2.stop_recording() +