Web 界面较硬核,可自行魔改

原作者为 Marcelo Rovai · Github



  • Raspberry 3
    • 之后的版本都可以
  • 树莓派 CSI 接口的摄像头
  • 显示器
    • 可选,我这里接了官方七寸 LCD 屏


  • Raspbian Buster
  • python 3.7.7
    • flask
    • 这两个 buster 自带,应该不用手动安装



  1. 安装摄像头(详见 简易树莓派拍照远程监控,为了方便阅读复读一次)
    • 排线蓝色一面朝向以太网接口,插反不会 boom 但无法识别
    • 不能热插拔
    • 摄像头板子上有 led 灯(拍照的时候会亮),注意不要用导电的材料连通,否则灯会坏(反而更隐蔽?),我当时为了省事把摄像头卡在两根 GPIO 针中间,某天碰了一下,一个火花闪过LED再也没亮过
  2. 测试摄像头
    • 执行指令,拍张照先
      raspistill -o ~/Desktop/image.jpg


  3. 建立 flask 项目结构
    • 新建 static 目录(flask 会从该目录加载样式表和 js)
    • 在 static 目录新建样式表 style.css
          background: blue;
          color: yellow;
          text-align: center;


    • 新建与 static 目录同级的 templates 目录(flask 会从该目录加载 html 模板)
    • 在 templates 目录下新建 index.html
          <title>MJRoBot Lab Live Streaming</title>
          <link rel="stylesheet" href='../static/style.css'/>
          <h1>MJRoBot Lab Live Streaming</h1>
          <h3><img src="{{ url_for('video_feed') }}" width="50%"></h3>
          <p> @2018 Developed by MJRoBot.org</p>
  4. flask 代码
    • 源代码在参考链接中(作者不是我),这里复读一遍
      • 注意:如果选择下载作者的代码,请使用 camWebServer 目录下的代码,camWebServer2 中添加了温湿度传感器 DHT22 的代码,如果没有连接 DHT22 会报错
    • 在 static 的同级目录下新建 app.py
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      #   appCam.py
      #   based on tutorial ==> https://blog.miguelgrinberg.com/post/video-streaming-with-flask
      #   PiCam Local Web Server with Flask
      # MJRoBot.org 19Jan18
      from flask import Flask, render_template, Response
      # Raspberry Pi camera module (requires picamera package)
      from camera_pi import Camera
      app = Flask(__name__)
      def index():
          """Video streaming home page."""
          return render_template('index.html')
      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')
      def video_feed():
          """Video streaming route. Put this in the src attribute of an img tag."""
          return Response(gen(Camera()),
                          mimetype='multipart/x-mixed-replace; boundary=frame')
      if __name__ == '__main__':
          app.run(host='', port =80, debug=True, threaded=True)
    • 在 static 的同级目录下新建 camera_pi.py
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      #  camera_pi.py
      import time
      import io
      import threading
      import picamera
      class Camera(object):
          thread = None  # background thread that reads frames from camera
          frame = None  # current frame is stored here by background thread
          last_access = 0  # time of last client access to the camera
          def initialize(self):
              if Camera.thread is None:
                  # start background frame thread
                  Camera.thread = threading.Thread(target=self._thread)
                  # wait until frames start to be available
                  while self.frame is None:
          def get_frame(self):
              Camera.last_access = time.time()
              return self.frame
          def _thread(cls):
              with picamera.PiCamera() as camera:
                  # camera setup
                  camera.resolution = (320, 240)
                  camera.hflip = True
                  camera.vflip = True
                  # let camera warm up
                  stream = io.BytesIO()
                  for foo in camera.capture_continuous(stream, 'jpeg',
                      # store frame
                      cls.frame = stream.read()
                      # reset stream for next frame
                      # if there hasn't been any clients asking for frames in
                      # the last 10 seconds stop the thread
                      if time.time() - cls.last_access > 10:
              cls.thread = None
  5. 运行 flask
    • 执行指令
      sudo python3 app.py

      注意不是 root 用户需要 sudo,不然权限不够无法监听 Web 端口

Continue reading “树莓派 CSI 摄像头 + Flask 实现轻量 Web 直播串流”


  1. 打开 /etc/lighttpd/lighttpd.conf,更改server.port值。
    vim /etc/lighttpd/lighttpd.conf
    server.groupname = "www-data"
    server.port = 8080
    accesslog.filename = "/var/log/lighttpd/access.log"
  2. 重启lighttpd服务
    systemctl restart lighttpd


  1. 执行指令
    pihole -a -p
  2. 输入新密码
    • 如果以非root用户登录会首先验证系统密码

The only reason I’m doing this is that I have an extra Raspberry Pi 3B(all IO ports are removed from the board) and I want it to be used, otherwise it will lose other Raspberry Pis’ respect.

The Installation is quite simple, due to the official guide(here), the only thing we need to do is install snap then use snap to install NextCloud. (There’s an another more complicated way to install NextCloud, I tried, then I failed. It’s just not worth it to me. If you want to do it anyway, you can see this article. For me, the reason I failed is I did not change the “server_name” in the nginx config file to my Pi’s IP.)

Run command

sudo apt update
sudo apt upgrade
sudo apt install snapd

then you have snap installed.

Snap is quite like Docker, but without containers and all the virtual stuff it has virtual stuff actually(I didn’t actually look into it, ignore it if I’m wrong). You can find the information about the differences here, and the relationship between snap and linux distros community here.

Run command

sudo snap install nextcloud

to install NextCloud.

NextCloud will run at default 80 port, type in your Pi’s IP in your browser then you are on the go.