I have this Flask-Socketio app which shows the Raspberry Pi system info like temperature, RAM and Disk space. This app also has a video streaming component VideroStream.py.
I have added VideroStream.py route to index.py using Flask blueprint. When accessing the app in browser RPI freezes and in error log it shows:
> Truncated or oversized response headers received from daemon process
> 'rpiWebServer': /var/www/rpiWebServer.wsgi
Why this is happening?
Is this line correct videoStreamBp = Blueprint('video_stream', __name__) ?
Should I use videopi instead of video_stream?
When I create a standalone app without blueprint and Socketio streaming works perfectly.
UPDATE:
When I remove image src="{{url_for(videopi)}}" page loads without video as expected.
index.py
from flask import Flask, render_template, Response, request
from flask_socketio import SocketIO, emit
from threading import Lock
#for temp
import os
import datetime
import ast
import psutil
app = Flask(__name__)
#for socket
async_mode = None
socketio = SocketIO(app, async_mode=async_mode)
#thread = None
thread1 = None
thread_lock = Lock()
from findPath import findPathBp
app.register_blueprint(findPathBp)
from videoStream import videoStreamBp
app.register_blueprint(videoStreamBp)
# GET RAM info
def getSysInfo():
count = 0
while True:
#RAM
memory = psutil.virtual_memory()
ramAvailable = round(memory.available/1024.0/1024.0,1) # Divide from Bytes -> KB -> MB
ramTotal = round(memory.total/1024.0/1024.0,1)
#Temp
temp = os.popen("vcgencmd measure_temp").readline()
cpuTemp = temp.replace("temp=","")
cpuTemp = cpuTemp.replace("'C","°C")
#DISK
disk = psutil.disk_usage('/')
# Divide from Bytes -> KB -> MB -> GB
diskFree = round(disk.free/1024.0/1024.0/1024.0,1)
diskTotal = round(disk.total/1024.0/1024.0/1024.0,1)
socketio.sleep(1)
count += 1
socketio.emit('sysStat',{'available': ramAvailable, 'total': ramTotal, 'temp': cpuTemp, 'freeDisk': diskFree, 'totalDisk': diskTotal }, namespace='/getSysInfo')
#index route
#app.route("/", methods=['GET', 'POST'])
def index():
return render_template('index.html', result= timeString)
#socket IO
# Get system info
#socketio.on('connect', namespace='/getSysInfo')
def test_connect():
global thread1
with thread_lock:
if thread1 is None:
thread1 = socketio.start_background_task(getSysInfo)
if __name__ == "__main__":
socketio.run(host='192.168.225.47', port=80, debug=True, threaded=True)
videoStream.py
from flask import Blueprint, render_template, Response
videoStreamBp = Blueprint('video_stream', __name__)
# Raspberry Pi camera module (requires picamera package)
from camera_pi import Camera
def gen(camera):
# Video streaming generator function.
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#videoStreamBp.route('/videopi')
def video_stream():
return Response(gen(Camera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
index.html
<div class='fifty'>
<p class='tempConainer'>CPU temperature is: <span id='temp'>Loading..</span></p><br>
<p class='tempConainer'>RAM available: <span id='ramInfo'>Loading..</span></p>
<p class='tempConainer'>RAM total: <span id='ramInfo1'>Loading..</span></p><br>
<p class='tempConainer'>Free disk: <span id='freeDisk'>Loading..</span></p><br>
<p class='tempConainer'>Total disk: <span id='totalDisk'>Loading..</span></p><br>
</div>
<div class='fifty'>
<img src="{{url_for(videopi)}}">
</div>
Finally I found that the src attribute of image was wrong and I changed it to this:
<img src='/videopi'>
Works like a charm.
Related
I am trying to take a RTSP video input and apply analytics and show it as a live stream. I am using Open CV and PyFlask for this purpose.
I can manage to show the output successfully. However, I am having issues when I try to access the host from multiple devices.
If I access from single device, it's working like a charm but when I try to access from multiple devices at the same time, it's breaking.
RTSP = f'''rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4'''
# importing
import cv2
from flask import Flask, render_template, Response
app= Flask(__name__)
cap= cv2.VideoCapture(RTSP)
def gen_frames():
while True:
success, frame = cap.read()
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield(b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#app.route('/')
def index():
return render_template('index.html')
#app.route('/video')
def video():
return Response(gen_frames(), mimetype = 'multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(debug = False, host = '0.0.0.0', port = 8018)
Need some expert advice. Thanks in advance.
Note - index.html code is given below:
<!DOCTYPE html>
<html>
<body>
<h1>Live streaming</h1>
<div>
<img src="{{ url_for('video') }}"/>
</div>
</body>
</html>
Context:
I have a function in my views command where some varaibales is being send through a background task script after a HTTP post on form. This background script handles a lot of API calls and is converting this to JSON that is gonna be converted Because this can take a long time (because of the way the API Calls) go before the next html page is rendered I had decided to make this one a background task with threading. Eventually if possible I would like a que to be added later on.
The problem:
But the thing is even though I clearly set it to a daemon thread and everything. The code is not being executed. I the Python Console log does not even show the code being executed, so what I am doing wrong here.
Just look at Order 66 if you want the background task itself.
"""
Routes and views for the flask application.
"""
from datetime import datetime
from flask import render_template, jsonify
from FlaskWebPODTracer import app
import json
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import request, redirect, url_for, flash
# The main script that has to happen in the background.
import classified.background_script.backgroundtask as Order66
from threading import Thread
import random
import string
from celery import Celery
from flask_mail import Mail, Message
import requests
API_VERSION = "v1/"
Succes_message = "U ontvangt nog een mail wanneer de data klaar is. Bedankt om PODTracer te gebruiken."
Fail_message_1 = "Wijzig de parameters van uw aanvraag en probeer opnieuw."
Fail_message_2 = "Blijft dit voorkomen contacteer dan support."
Fail_message = Fail_message_1 + '\n' + Fail_message_2
#app.route('/handle_data/')
#app.route('/handle_data/', methods=['POST', 'GET'])
def handle_data():
#if request.method == 'GET':
# return render_template(
# "request-completed.html",
# title=
# "Aanvraag ingediend",
# objects = jsonobjects,
# year=datetime.now().year,
# message='Uw aanvraag is voltooid.'
# )
if request.method == 'POST':
email = request.form['inputEmail']
stringpart = request.form['city']
sper_year = int(request.form["Speryear"])
urlpart = request.form["api-url-input"]
url = "Classified" + API_VERSION + urlpart
print(url)
response = requests.get(url)
if response.status_code == 200:
jsonobjects = len(response.json())
task = Thread(group=None, target=None,name=Order66.main, args=(stringpart,url,sper_year,email), daemon=True)
task.start()
state = "succesvol."
message_body = Succes_message
else:
jsonobjects = 0;
state = "onsuccesvol."
message_body = Fail_message
return render_template(
"request-posted.html",
respstate = state,
body = message_body,
title=
"Aanvraag ingediend",
objects = jsonobjects,
year=datetime.now().year,
message='Uw aanvraag is ' + state
)
# TODO RUN THIS IN BACKGROUND
# app.route('/request-completed')
#app.route('/handle_data_fail')
def handle_data_fail():
jsonobjects = 0
state = "onsuccesvol."
message_body = Fail_message
return render_template(
"request-posted.html",
respstate = state,
body = message_body,
title=
"Aanvraag ingediend",
objects = jsonobjects,
year=datetime.now().year,
message='Uw aanvraag is ' + state
)
As discussed in comments, here's an oversimplified example of an event-driven system with RabbitMQ and Flask.
Dependencies you need:
(flask-rabbitmq) ➜ flask-rabbitmq pip freeze
click==8.0.3
Flask==2.0.2
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
pika==1.2.0
Werkzeug==2.0.2
Try to create a RabbitMQ docker container with the command below:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9-management
your simple flask app would look like this:
from flask import Flask
from flask import request
import json
from RabbitMQPublisher import publish
app = Flask(__name__)
#app.route('/publish', methods=['POST'])
def index():
if request.method == 'POST':
publish(json.dumps(request.json))
return 'Done'
if __name__ == '__main__':
app.run()
your RabbitMQPublisher.py would be like this:
import pika
def publish(data: str):
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='0.0.0.0', port=5672))
channel = connection.channel()
channel.exchange_declare(exchange='test', exchange_type='fanout')
channel.queue_declare(queue='', exclusive=True)
channel.basic_publish(exchange='test', routing_key='', body='{"data": %s}'%(data))
connection.close()
and finally your script.py would be like this:
import pika
import json
from time import sleep
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='0.0.0.0', port=5672))
channel = connection.channel()
channel.exchange_declare(exchange='test', exchange_type='fanout')
result = channel.queue_declare(queue='', exclusive=True)
channel.queue_bind(exchange='test', queue='')
def callback(ch, method, properties, body):
body = json.loads(body.decode().replace("'", '"'))
print(body)
channel.basic_consume(
queue='', on_message_callback=callback, auto_ack=True)
channel.start_consuming()
inside the callback function in the code above, you can specify you're logic and when your logic finishes you can again use RabbitMQ to call a pattern on flask side or event do http call with requests. that would be your choice.
I have created a simple live video stream from the raspberry camera. It looks like this
server.py
from flask import Flask
from flask import render_template
from flask import Response
import cv2
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/video_feed')
def video_feed():
return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')
def gen():
camera = cv2.VideoCapture(0)
while True:
ret, img = camera.read()
if ret:
frame = cv2.imencode('.jpg', img)[1].tobytes()
yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
else:
break
app.run(host='192.168.0.241', port=7070, debug=True)
index.html
<html>
<head>
<title>PiCamera stream</title>
</head>
<body>
<h1>Streaming</h1>
<img src="{{ url_for('video_feed') }}">
</body>
</html>
Everything works correct, I enter http://<raspberry_ip>:<port> in the browser and I can see the video.
Right now I need to create mobile app for watching this video, however I am struggling how to do it. Is there a way to capture video stream in iOS app?
Your video is streaming on
http://<raspberry_ip>:<port>/video_feed
http://<raspberry_ip>:<port>
Using Ngrok if you want to push your app to public server!
http://ngrok.com/
This question already has answers here:
I'm trying to use a simple webcam capture upload, upload isn't working?
(2 answers)
How do i take picture from client side(html) and save it to server side(Python)
(2 answers)
How can I capture an image via the user's webcam using getUserMedia?
(3 answers)
Closed 4 years ago.
First that all sorry about my not so good English skills and i appreciate the corrections.
I have tried to build a python program that can access the camera through a Flask web service, this is the code:
from flask import Flask, render_template, Response
import cv2
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def gen():
i = 1
while i < 10:
yield (b'--frame\r\n'
b'Content-Type: text/plain\r\n\r\n' + str(i) + b'\r\n')
i += 1
def get_frame():
camera_port = 0
ramp_frames = 100
camera = cv2.VideoCapture(camera_port) # this makes a web cam object
i = 1
while True:
retval, im = camera.read()
imgencode = cv2.imencode('.jpg', im)[1]
stringData = imgencode.tostring()
yield (b'--frame\r\n'
b'Content-Type: text/plain\r\n\r\n' + stringData + b'\r\n')
i += 1
del (camera)
#app.route('/calc')
def calc():
return Response(get_frame(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, threaded=True)
And the html code:
<html>
<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('calc') }}">
<!-- <h1>{{ url_for('calc') }}</h1> -->
</body>
</html>
The problem i have with this is when I run it in my laptop and Flask deploys. I access the service from a different device doesn't use the device's cam, but activates my laptop's webcam.
Is it possible to make the service use the camera of the device from which I access it(client) instead the laptop's(server) camera?
I wrote a simple Flask app that will return the most up to date image from a video source. The video source is running on a thread. The Flask appp is deployed with gevent. The client makes a GET request every 5 seconds (it's currently 5 seconds, because the image transfers are slow). The images are between 50 and 60 KB and usually take between 3 to 5 seconds to transfer. This is a local network, so I'd expect the speed to be much greater. Is there some optimization I should be aware of?
As a side note, I've also used Flask-SocketIO websockets and have the same problem with transfer speed.
The app code:
from gevent import monkey
monkey.patch_all()
from gevent.wsgi import WSGIServer
from flask import Flask, send_file, render_template
import threading
from cStringIO import StringIO
app = Flask(__name__)
img = StringIO()
def save_video():
global img
jpg_frame = some_image_source()
img.reset()
img.write(jpg_frame)
img.truncate()
#app.route("/")
def hello():
return render_template('index.html')
#app.route('/image<rand_num>')
def get_image(rand_num):
global img
new_img = StringIO(img.getvalue())
return send_file(new_img, mimetype='image/jpg')
if __name__ == "__main__":
imgthread = threading.Thread(target=save_video)
imgthread.daemon = True
imgthread.start()
http_server = WSGIServer(('0.0.0.0', 9090), app)
http_server.serve_forever()
I send requests with random numbers so that the browser doesn't fetch a cached image. The client code I have in the HTML body (head only has title):
<script>
setInterval(function() {
var myImageElement = document.getElementById('myImage');
myImageElement.src = '/image' + Math.random();
}, 5000);
</script>
<img src="/image0" id="myImage" />