Skip to content

More efficient file handling #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ The Arduino ESP32-Camera test sketch only lets you use the stream on your local

This collection of scripts consists of:
- Arduino code for ESP32 camera module (AI Thinker CAM) `websocket_camera_stream.ino`
- Python code to receive the images via websockets with `receive_stream.py`
- Python code to push the most recent image to a website with `send_image_stream.py`
- Python code to receive and serve the images via websockets with `run_in_memory.py`, using `receive_stream.py`, `send_image_stream.py` and a queue system `queueu.py`


# Why is this cool?
Expand All @@ -22,17 +21,18 @@ Upload the code to you ESP32 AI Thinker Cam board. Please test the Arduino camer

2. Install the missing python requirements using pip: `pip install pillow websockets flask asyncio`

3. Run `python receive_stream.py`
You should get a constant stream of numbers (sizes of images). The image.jpg in the directory is always the latest received image.

4. Open a second terminal and run `python send_image_stream.py`
3. Run `run_in_memory.py`
You should get a response by flask with an IP and port to enter in your browser.

Now enjoy your fresh live stream! 📺



# Known Issues

### Security
While this should be fine to run on a private (trusted LAN) network, exposing it to the public internet will allow others to receive and interrupt the stream. Only do this is you have sufficient knowledge.

### Browsers don't like broken images.
This is solved using the placeholder.jpg. It just replaces the image, if the backend receives a broken frame to prevent the browser from freezing the stream.

Expand Down
3 changes: 3 additions & 0 deletions python/queueue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from multiprocessing import Queue

q = Queue(maxsize=100)
13 changes: 7 additions & 6 deletions python/receive_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

from PIL import Image, UnidentifiedImageError

from multiprocessing import Queue

from queueue import q

def is_valid_image(image_bytes):
try:
Image.open(BytesIO(image_bytes))
Expand All @@ -18,19 +22,16 @@ async def handle_connection(websocket, path):
while True:
try:
message = await websocket.recv()
print(len(message))
#print(len(message)) # This made the IP to connect to go away
if len(message) > 5000:
if is_valid_image(message):
#print(message)
with open("image.jpg", "wb") as f:
f.write(message)
q.put(message) # puts message into queue

print()
#print()
except websockets.exceptions.ConnectionClosed:
break

async def main():
server = await websockets.serve(handle_connection, '0.0.0.0', 3001)
await server.wait_closed()

asyncio.run(main())
25 changes: 25 additions & 0 deletions python/run_in_memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import asyncio
from multiprocessing import Process, Queue

import receive_stream, send_image_stream

from queueue import q

def receiver(q):
asyncio.run(receive_stream.main())

def server(q):
send_image_stream.app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)

if __name__ == '__main__':

receiver_process = Process(target=receiver, args=(q,))
server_process = Process(target=server, args=(q,))

# Start the processes
receiver_process.start()
server_process.start()

# Join the processes
receiver_process.join()
server_process.join()
7 changes: 3 additions & 4 deletions python/send_image_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from flask import Flask, Response
from base64 import b64encode

from queueue import q


app = Flask(__name__)

Expand All @@ -17,8 +19,7 @@ def index():
def get_image():
while True:
try:
with open("image.jpg", "rb") as f:
image_bytes = f.read()
image_bytes = q.get(timeout=10)
image = Image.open(BytesIO(image_bytes))
img_io = BytesIO()
image.save(img_io, 'JPEG')
Expand All @@ -41,5 +42,3 @@ def get_image():
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + img_bytes + b'\r\n')
continue

app.run(host='0.0.0.0', debug=False, threaded=True)