I’ve had a Raspberry Pi camera module (v1) since spring 2015, but I’ve rarely put it to use. With some spare time on my hands I have decided to see if I can build a camera feed on a webpage.
Before I continue I should point out that if you are interested in using the Pi and Pi camera module as a security feed then motionEye may be the solution you are looking for.
Also Apache or Nginx and a bash script to capture images from the camera at regular intervals may be a better solution, but I wanted to do this in Python and use Flask as I have used it in previous projects and like it.
Full code for this project is on my GitHub at: https://github.com/geektechdude/python_raspberry_pi_cam_site
Project Directory Layout
The project is split into:
- camera_flask.py – a Python file containing the Python that controls the camera, Flask and moves the image after it is taken.
- templates – a folder to hold the HTML template that the render engine calls
- flask_temp.html – the HTML template that the render engine calls and then fills in with relevant details
- latest.jpg – the latest photo taken by the camera
- old_images – a folder containing previous photos taken by the camera

Originally I did not use the “latest.jpg” and had Flask calling on the latest photo via it’s name however I then had issues trying to keep the photos organised.
The Code
camera_flask.py
# geektechstuff # Libraries to import from flask import Flask, render_template from picamera import PiCamera from datetime import datetime import shutil import os app = Flask(__name__,static_url_path='',static_folder='/home/pi/flask_photo/') def save_photo(): camera = PiCamera() filename = datetime.now().strftime("%H%M%Y%m%d.jpg") camera.capture(filename) camera.close() shutil.copyfile(filename,'/home/pi/flask_photo/latest.jpg') new_location = "/home/pi/flask_photo/old_images/"+filename shutil.copyfile(filename, new_location) if os.path.exists(filename): os.remove(filename) return() @app.route('/') def load_page(): save_photo() time_hour_min = datetime.now().strftime("%H:%M") time_date = datetime.now().strftime("%d-%m-%y") return render_template("flask_temp.html", time_hour_min=time_hour_min, time_date=time_date)

camera_flask.py has two functions:
- save_photo(): Uses the Pi Camera module to take a photo, then saves it using the current system time/date. It then copies that file as latest.jpg and also copies itself (with the original timestamp name) to the /old_images/ directory before deleting the file from the original location. This stops the /flask_photo/ directory from being flooded by photo (jpg) files and allows the HTML to reference the latest.jpg rather than the timestamp name.
- load_page(): Loads the page and adds a time reference onto the page. I have some ideas of other functionality I want to add at a future date.
flask_temp.html
<!DOCTYPE html> <head> <meta http-equiv="refresh" content="30" > </head> <title>GeekTechStuff Live Photo</title> <body> <p><b>GeekTechStuff</b> <br> Current view:<br> </p> <img src="latest.jpg" alt="Current View" width="400" height="300"> <p>Taken: {{time_date}} at {{time_hour_min}}</p> </body> </html>

flask_temp.html is the HTML template that Flask calls on using the render engine, passing in values for text within the curly braces {{ }}. I admit flask_temp is a little bland at the moment, but I wanted to make sure that the Python and camera were working correctly before adding details to the HTML, or adding CSS to control the styling of the page.
The web page takes a new photo each time it loads (or is fully refreshed), I have added in:
<meta http-equiv="refresh" content="30" >
to make the web page refresh every 30 seconds which updates the image.
Currently I am using the command:
FLASK_APP=camera_flask.py flask run --host=0.0.0.0
to run the webpage, with the host as 0.0.0.0 so that I can access it from other computers on my personal network.
I’m serving up the page from my Pi on port 5000, and my first attempt (which was still using the timestamp method for the image name) worked ok as it showed Sinestro on my desk.

You must be logged in to post a comment.