第17章 Raspberry Pi Flask Web Server:用瀏覽器遠端控制 GPIO

發布日期: |更新日期:
文章主圖:第17章 Raspberry Pi Flask Web Server:用瀏覽器遠端控制 GPIO

前面的 Raspberry Pi 實作大多是在 Raspberry Pi 本機執行 Python 程式,例如控制 LED、讀取感測器、操作 LCD1602,或在第 16 章使用 Camera 拍攝照片。

但是實際的 IoT 專案通常不會要求使用者一直坐在 Raspberry Pi 前面操作。

更實用的方式是:

讓 Raspberry Pi 成為一台 Web Server。

如此一來,只要手機、平板或電腦與 Raspberry Pi 位於同一個區域網路,就可以直接開啟瀏覽器:

http://192.168.1.100:5000

然後在網頁上按下:

LED ON
LED OFF

遠端控制 Raspberry Pi GPIO。

本章將使用 Python 非常常見的 Web Framework:

Flask

建立第一個 Raspberry Pi Web Server,並將:

HTML
Flask
Python
GPIO

整合成完整的遠端硬體控制系統。

本章最後將完成:

實作:手機瀏覽器控制 Raspberry Pi LED

一、本章學習目標

完成本章後,你將了解:

  • Client 與 Server
  • Web Server 基本概念
  • HTTP 通訊
  • IP Address
  • Port
  • Flask
  • Flask Route
  • HTML 基礎
  • GET / POST 基本觀念
  • Raspberry Pi LAN 網路
  • GPIO Zero
  • Flask 與 GPIO 整合
  • 手機控制 Raspberry Pi GPIO
  • Raspberry Pi Web Server 的安全注意事項

並完成:

Raspberry Pi Flask Web GPIO Control System

二、什麼是 Client / Server?

網頁系統最基本的架構就是:

Client
   │
   │ Request
   ▼
Server
   │
   │ Response
   ▼
Client

其中:

Client

Client 就是發出要求的裝置。

例如:

  • 手機
  • 平板
  • Windows 電腦
  • Mac
  • 另一台 Raspberry Pi
  • Web Browser

本章中的 Client 就是:

手機瀏覽器。

Server

Server 負責接收 Client 的 Request,處理後再回傳 Response。

本章中的 Server 就是:

Raspberry Pi。

架構為:

手機 Browser
     │
     │ HTTP
     ▼
Raspberry Pi
Flask Web Server
     │
     ▼
Python
     │
     ▼
GPIO
     │
     ▼
LED

所以手機本身不需要直接連接 LED。

手機只需要把:

開燈

這個要求傳送給 Raspberry Pi。

真正控制 GPIO 的仍然是 Raspberry Pi。

三、什麼是 HTTP?

HTTP 是:

HyperText Transfer Protocol

也就是:

超文字傳輸協定

瀏覽器與 Web Server 之間通常利用 HTTP 或 HTTPS 進行通訊。

例如手機輸入:

http://192.168.1.100:5000/

瀏覽器會向 Raspberry Pi 發出 Request。

Raspberry Pi 的 Flask Server 收到 Request 後,回傳 HTML。

架構:

Browser
   │
   │ HTTP Request
   ▼
Flask
   │
   │ HTML Response
   ▼
Browser

四、什麼是 IP Address?

網路中的每一台裝置都需要能被識別。

其中最重要的資訊之一就是:

IP Address

例如:

192.168.1.10
192.168.1.20
192.168.1.100

假設:

Raspberry Pi
192.168.1.100

手機:

192.168.1.50

而且都連接同一台 Wi-Fi Router:

Wi-Fi Router
                    │
          ┌─────────┴─────────┐
          │                   │
        手機              Raspberry Pi
  192.168.1.50          192.168.1.100

手機就可以透過 LAN 存取 Raspberry Pi。

五、如何查 Raspberry Pi IP?

在 Raspberry Pi Terminal 輸入:

hostname -I

可能得到:

192.168.1.100

如果出現多個 IP,例如:

192.168.1.100 172.17.0.1

通常需要找出 Raspberry Pi 實際連接區域網路的 IP。

也可以輸入:

ip addr

查看各 Network Interface。

常見介面:

eth0
wlan0

其中:

eth0

通常代表 Ethernet。

wlan0

通常代表 Wi-Fi。

六、什麼是 Port?

一台 Raspberry Pi 可能同時提供很多網路服務。

例如:

SSH
Web Server
Database
MQTT

所以只有 IP 還不夠。

還需要:

Port Number

概念可以想像成:

IP Address = 大樓地址
Port       = 房間號碼

例如:

192.168.1.100:5000

其中:

192.168.1.100

是 Raspberry Pi IP。

而:

5000

是 Port。

七、Flask 預設開發 Port

Flask 開發伺服器常使用:

5000

因此稍後我們的網址會類似:

http://192.168.1.100:5000

Flask 官方 Quickstart 使用 route() 將 URL 與 Python Function 建立對應,這也是本章整個 Web GPIO 控制系統最重要的核心概念。

八、什麼是 Flask?

Flask 是 Python 的 Web Framework。

它可以讓我們使用 Python 建立:

  • Web Server
  • Web Page
  • REST API
  • IoT Dashboard
  • GPIO 控制頁面
  • Sensor Dashboard
  • Camera Control
  • Database Web Interface

最基本的 Flask 程式甚至只需要幾行 Python。

例如:

from flask import Flask

app = Flask(__name__)


@app.route("/")
def home():
    return "Hello Raspberry Pi"


if __name__ == "__main__":
    app.run()

其中:

@app.route("/")

就是告訴 Flask:

當 Browser 存取:

/

時,要執行哪一個 Python Function。

Flask 官方文件也是利用 @app.route() 建立 URL 與 Python Function 的對應。

九、建立 Raspberry Pi Flask 環境

先更新套件資訊:

sudo apt update

在 Raspberry Pi OS 中,可以直接安裝:

sudo apt install -y python3-flask

另外本章 GPIO 控制使用:

GPIO Zero

可以安裝:

sudo apt install -y python3-gpiozero

Raspberry Pi 官方文件將 GPIO Zero 作為 Raspberry Pi Python GPIO 控制方式之一,而且 Raspberry Pi OS 通常已包含 GPIO Zero。

十、為什麼本章使用 GPIO Zero?

很多舊 Raspberry Pi 教學會使用:

import RPi.GPIO as GPIO

但是本系列希望 Raspberry Pi 4 與 Raspberry Pi 5 都能較容易使用,所以本章主要採用:

from gpiozero import LED

GPIO Zero 將 GPIO 裝置封裝成比較容易理解的 Python Object。

例如:

led = LED(17)

開燈:

led.on()

關燈:

led.off()

程式非常直覺。

Raspberry Pi 官方也指出 GPIO Zero 可以簡化利用 Python 控制 GPIO 裝置的工作。

十一、準備材料

本章需要:

第 17 章實作材料
材料 數量
Raspberry Pi 1
microSD Card 1
Raspberry Pi OS 1
LED 1
220Ω~330Ω 電阻 1
Breadboard 1
Dupont Jumper Wire 數條
Wi-Fi / Ethernet 網路 1

Raspberry Pi 3、4、5 都可以進行本章實驗。

十二、LED 接線

本章使用:

GPIO17

控制 LED。

我們採用 BCM GPIO 編號。

接線:

Raspberry Pi GPIO17
        │
        │
        ▼
      電阻
   220Ω~330Ω
        │
        ▼
    LED 長腳 (+)
        │
      LED
        │
    LED 短腳 (-)
        │
        ▼
       GND

也就是:

GPIO17 LED 接線對照表
Raspberry Pi 元件
GPIO17 220Ω~330Ω 電阻
電阻另一端 LED Anode 長腳
LED Cathode 短腳 GND

十三、GPIO17 在哪裡?

GPIO Zero:

LED(17)

這裡的:

17

指的是:

BCM GPIO17

不是實體 Pin 17。

GPIO17 對應 40-pin Header 的:

Physical Pin 11

因此:

GPIO17 = BCM 17 = Physical Pin 11

兩種編號不要混淆。

Raspberry Pi 可以直接在 Terminal 使用:

pinout

查看目前 Raspberry Pi 的 GPIO Pinout;官方文件指出這個工具由 GPIO Zero 提供。

十四、為什麼 LED 一定要串接電阻?

LED 不應直接連接 GPIO。

應使用:

GPIO
 │
 ▼
Resistor
 │
 ▼
LED
 │
 ▼
GND

例如:

220Ω

或:

330Ω

電阻用來限制 LED 電流。

Raspberry Pi 官方文件也明確提醒 LED 應使用限流電阻。

十五、先測試 GPIO LED

在開始 Flask 前,先確認 LED 接線正確。

建立:

nano led_test.py

輸入:

from gpiozero import LED
from time import sleep


led = LED(17)


while True:

    led.on()
    sleep(1)

    led.off()
    sleep(1)

執行:

python3 led_test.py

LED 應該:

亮 1 秒
↓
滅 1 秒
↓
亮 1 秒
↓
滅 1 秒

循環執行。

按:

Ctrl + C

停止。

如果這一步成功,表示 GPIO 與 LED 接線正常。

十六、建立第一個 Flask Web Server

建立專案資料夾:

mkdir -p ~/flask_gpio

進入:

cd ~/flask_gpio

建立:

nano app.py

輸入:

from flask import Flask


app = Flask(__name__)


@app.route("/")
def home():

    return """
    <h1>Raspberry Pi Web Server</h1>
    <p>Hello Raspberry Pi!</p>
    """


if __name__ == "__main__":

    app.run(
        host="0.0.0.0",
        port=5000,
        debug=False
    )

十七、啟動 Flask

執行:

python3 app.py

正常情況會看到類似:

Running on http://127.0.0.1:5000
Running on http://192.168.1.100:5000

實際顯示方式會依 Flask 版本與網路環境略有不同。

十八、host=“0.0.0.0” 是什麼?

如果只讓 Web Server 接受 Localhost Request,其他裝置可能無法連入。

因此本章設定:

app.run(
    host="0.0.0.0",
    port=5000
)

這表示 Flask Development Server 在可用的網路介面上接受連線。

注意:

0.0.0.0

是 Server 的 Bind Address。

手機瀏覽器不要輸入:

http://0.0.0.0:5000

而應輸入 Raspberry Pi 的實際 LAN IP:

http://192.168.1.100:5000

十九、從 Raspberry Pi 本機測試

如果 Raspberry Pi 有 Desktop,可以打開 Browser:

http://127.0.0.1:5000

或:

http://localhost:5000

看到:

Raspberry Pi Web Server

Hello Raspberry Pi!

代表 Flask 已正常運作。

二十、使用手機連線 Raspberry Pi

首先在 Raspberry Pi 查 IP:

hostname -I

假設得到:

192.168.1.100

手機與 Raspberry Pi 必須位於可以互相通訊的 LAN。

然後手機 Browser 輸入:

http://192.168.1.100:5000

如果成功看到:

Raspberry Pi Web Server

就代表:

手機
 ↓
Wi-Fi
 ↓
Router
 ↓
Raspberry Pi
 ↓
Flask

已經全部連線成功。

二十一、什麼是 Web Route?

現在來理解 Flask 最重要的:

@app.route(...)

例如:

@app.route("/")
def home():
    return "HOME"

代表:

http://192.168.1.100:5000/

再增加:

@app.route("/hello")
def hello():
    return "Hello"

代表:

http://192.168.1.100:5000/hello

Flask 官方文件稱 Route 是用來指定哪個 URL 應觸發哪個 View Function。

二十二、將 Route 與 GPIO 結合

接下來建立:

/led/on

以及:

/led/off

概念如下:

Browser
  │
  │ /led/on
  ▼
Flask
  │
  ▼
led.on()
  │
  ▼
GPIO17 HIGH
  │
  ▼
LED ON

關燈:

Browser
  │
  │ /led/off
  ▼
Flask
  │
  ▼
led.off()
  │
  ▼
GPIO17 LOW
  │
  ▼
LED OFF

這就是:

Web Route → Python → GPIO

的核心。

二十三、第一版 Flask GPIO 程式

建立:

nano gpio_web.py

輸入:

from flask import Flask
from gpiozero import LED


app = Flask(__name__)

led = LED(17)


@app.route("/")
def home():

    return """
    <h1>Raspberry Pi GPIO Control</h1>

    <p>
        <a href="/led/on">
            LED ON
        </a>
    </p>

    <p>
        <a href="/led/off">
            LED OFF
        </a>
    </p>
    """


@app.route("/led/on")
def led_on():

    led.on()

    return """
    <h1>LED ON</h1>
    <a href="/">Back</a>
    """


@app.route("/led/off")
def led_off():

    led.off()

    return """
    <h1>LED OFF</h1>
    <a href="/">Back</a>
    """


if __name__ == "__main__":

    app.run(
        host="0.0.0.0",
        port=5000,
        debug=False
    )

執行:

python3 gpio_web.py

手機打開:

http://Raspberry-Pi-IP:5000

例如:

http://192.168.1.100:5000

按:

LED ON

LED 就會亮。

按:

LED OFF

LED 就會熄滅。

到這裡,我們已經完成最基本的:

Raspberry Pi 網頁控制 GPIO。

二十四、為什麼還要改良?

剛才的程式可以工作,但還不是很好的 Web 控制設計。

因為我們使用:

GET /led/on
GET /led/off

來改變硬體狀態。

更適合的方式是:

POST

負責執行狀態改變。

所以接下來正式專題版本會使用:

GET /

讀取頁面。

以及:

POST /led/on
POST /led/off

控制 GPIO。

二十五、GET 與 POST 基本觀念

最簡單可以理解成:

GET

通常用來:

取得資料
讀取頁面
查詢狀態

例如:

GET /

取得首頁。

POST

通常用來:

提交資料
改變狀態
執行操作

例如:

POST /led/on

執行 LED ON。

因此:

查看狀態 → GET

控制設備 → POST

是一個更好的設計方式。

二十六、HTML Button

HTML 可以建立按鈕:

<button>LED ON</button>

但是按鈕如果要向 Flask 發送命令,可以使用 Form:

<form action="/led/on" method="post">

    <button type="submit">
        LED ON
    </button>

</form>

代表:

按下按鈕後:

POST /led/on

二十七、實作:手機瀏覽器控制 Raspberry Pi LED

現在開始建立本章正式專題。

系統架構:

Smartphone
                 │
                 │ Wi-Fi
                 ▼
              Router
                 │
                 │ LAN
                 ▼
          Raspberry Pi
                 │
             Flask
                 │
       ┌─────────┴─────────┐
       │                   │
   Web Page            Web Route
                           │
                           ▼
                         Python
                           │
                           ▼
                       GPIO Zero
                           │
                           ▼
                        GPIO17
                           │
                           ▼
                          LED

二十八、建立專題目錄

執行:

mkdir -p ~/raspberrypi_web_gpio

進入:

cd ~/raspberrypi_web_gpio

建立:

nano app.py

二十九、完整 Raspberry Pi Flask GPIO 程式

輸入:

from flask import Flask, redirect, url_for
from gpiozero import LED


# -----------------------------
# Flask
# -----------------------------

app = Flask(__name__)


# -----------------------------
# GPIO
# BCM GPIO17
# Physical Pin 11
# -----------------------------

led = LED(17)


# -----------------------------
# 建立 HTML
# -----------------------------

def build_page():

    if led.is_lit:

        led_status = "ON"

    else:

        led_status = "OFF"


    html = f"""
    <!DOCTYPE html>

    <html lang="zh-TW">

    <head>

        <meta charset="UTF-8">

        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0"
        >

        <title>
            Raspberry Pi GPIO Control
        </title>


        <style>

            body {{
                font-family:
                    Arial,
                    "Microsoft JhengHei",
                    sans-serif;

                background: #f2f4f7;

                text-align: center;

                margin: 0;

                padding: 30px;
            }}


            .container {{
                max-width: 500px;

                margin: auto;

                background: white;

                padding: 30px;

                border-radius: 15px;

                box-shadow:
                    0 4px 15px
                    rgba(0, 0, 0, 0.15);
            }}


            h1 {{
                color: #333;
            }}


            .status {{
                font-size: 28px;

                font-weight: bold;

                margin: 30px 0;
            }}


            button {{
                width: 200px;

                padding: 18px;

                margin: 10px;

                border: none;

                border-radius: 10px;

                font-size: 20px;

                cursor: pointer;
            }}


            .on {{
                background: #28a745;

                color: white;
            }}


            .off {{
                background: #dc3545;

                color: white;
            }}


            .info {{
                margin-top: 30px;

                color: #666;
            }}

        </style>

    </head>


    <body>

        <div class="container">


            <h1>
                Raspberry Pi
                GPIO Control
            </h1>


            <p>
                GPIO17 LED Status
            </p>


            <div class="status">

                {led_status}

            </div>


            <form
                action="/led/on"
                method="post"
            >

                <button
                    class="on"
                    type="submit"
                >
                    LED ON
                </button>

            </form>


            <form
                action="/led/off"
                method="post"
            >

                <button
                    class="off"
                    type="submit"
                >
                    LED OFF
                </button>

            </form>


            <div class="info">

                Raspberry Pi Flask
                Web GPIO Controller

            </div>


        </div>

    </body>

    </html>
    """

    return html


# -----------------------------
# Home
# -----------------------------

@app.route("/")
def home():

    return build_page()


# -----------------------------
# LED ON
# -----------------------------

@app.route(
    "/led/on",
    methods=["POST"]
)
def led_on():

    led.on()

    return redirect(
        url_for("home")
    )


# -----------------------------
# LED OFF
# -----------------------------

@app.route(
    "/led/off",
    methods=["POST"]
)
def led_off():

    led.off()

    return redirect(
        url_for("home")
    )


# -----------------------------
# Main
# -----------------------------

if __name__ == "__main__":

    print(
        "Raspberry Pi Flask GPIO Server"
    )

    print(
        "Port: 5000"
    )

    app.run(
        host="0.0.0.0",
        port=5000,
        debug=False
    )

三十、執行專題程式

執行:

cd ~/raspberrypi_web_gpio

然後:

python3 app.py

Server 開始執行。

三十一、查 Raspberry Pi IP

另外開啟 Terminal:

hostname -I

假設為:

192.168.1.100

三十二、手機操作

手機必須連接與 Raspberry Pi 可以互通的網路。

在手機 Chrome、Safari 或其他 Browser 輸入:

http://192.168.1.100:5000

就會看到控制頁面:

Raspberry Pi GPIO Control

GPIO17 LED Status

        OFF

    [ LED ON ]

    [ LED OFF ]

按:

LED ON

傳送:

POST /led/on

Flask 執行:

led.on()

GPIO17 輸出 High。

LED:

ON

按:

LED OFF

則:

POST /led/off

執行:

led.off()

LED:

OFF

三十三、完整控制流程

現在可以把整個系統完整畫出來。

當使用者按:

LED ON

執行流程為:

手機
 │
 │ HTTP POST
 │
 │ /led/on
 ▼
Wi-Fi Router
 │
 ▼
Raspberry Pi
 │
 ▼
Flask
 │
 ▼
@app.route("/led/on")
 │
 ▼
led_on()
 │
 ▼
led.on()
 │
 ▼
GPIO Zero
 │
 ▼
GPIO17 HIGH
 │
 ▼
LED ON

這就是完整的:

Raspberry Pi Web GPIO Control

三十四、LED Status 如何取得?

程式使用:

led.is_lit

例如:

if led.is_lit:

    led_status = "ON"

else:

    led_status = "OFF"

因此網頁可以知道目前 GPIO 裝置狀態。

架構變成:

GPIO
 ↓
GPIO Zero
 ↓
Python
 ↓
Flask
 ↓
HTML
 ↓
Browser

不只是 Browser 控制 Raspberry Pi。

Raspberry Pi 也可以:

把硬體狀態顯示回 Browser。

三十五、Flask 與 HTML 的關係

目前我們直接:

return """
<html>
...
</html>
"""

把 HTML 放在 Python 裡。

這種方式很適合教學。

但是大型專案通常會拆成:

raspberrypi_web_gpio/
│
├── app.py
│
├── templates/
│   └── index.html
│
└── static/
    ├── css/
    ├── js/
    └── images/

Flask 本身支援 Template 架構,而且 Flask 使用 Jinja Template Engine 來產生動態 HTML。

例如:

from flask import render_template

然後:

return render_template(
    "index.html"
)

第 20 章完整智慧環境監控中心就很適合採用這種方式。

三十六、如果手機無法連線

如果 Raspberry Pi 本機正常:

http://127.0.0.1:5000

但是手機無法:

http://192.168.1.100:5000

可以依序檢查。

1. Flask 是否仍在執行?

Terminal 必須仍然執行:

python3 app.py

如果已按:

Ctrl + C

Server 就停止了。

2. IP 是否正確?

重新執行:

hostname -I

確認目前 Raspberry Pi IP。

DHCP 環境下,IP 可能在重新連線或重新開機後發生變化。

3. 手機與 Raspberry Pi 網路是否互通?

確認兩者是否連接可彼此通訊的 LAN。

有些:

Guest Wi-Fi

會開啟 Client Isolation。

即使手機與 Raspberry Pi 看起來連接同一個基地台,也可能禁止裝置彼此存取。

4. Flask 是否使用 0.0.0.0?

確認:

app.run(
    host="0.0.0.0",
    port=5000
)

而不是只綁定:

127.0.0.1

5. Port 是否正確?

如果 Server 使用:

5000

網址就必須有:

:5000

完整:

http://192.168.1.100:5000

三十七、查看 Flask Request

執行 Flask 時,每次 Browser 發出 Request,Terminal 通常都會顯示存取資訊。

例如:

GET / HTTP/1.1

按 LED ON:

POST /led/on HTTP/1.1

接著 Browser 回首頁:

GET / HTTP/1.1

因此 Flask Console 本身就可以協助 Debug Web Control。

三十八、為什麼按下按鈕後要 Redirect?

我們使用:

return redirect(
    url_for("home")
)

意思是:

POST /led/on
     ↓
LED ON
     ↓
Redirect
     ↓
GET /
     ↓
重新顯示首頁

因此使用者按完按鈕後會回到:

/

並看到最新:

LED Status = ON

三十九、不要直接把 Flask Development Server 開放到 Internet

本章建立的是:

LAN 教學用 Flask Server。

Flask 官方文件明確表示內建 Development Server 主要用於開發,不應直接作為正式 Production Server。正式部署應使用適合 Production 的 WSGI Server,並視架構搭配 nginx 等 Web Server / Reverse Proxy。

因此本章架構建議限定在:

家中 LAN
實驗室 LAN
公司測試 LAN

不要直接在 Router 設定:

Port Forward 5000

然後毫無身份驗證地暴露到 Internet。

因為目前:

/led/on
/led/off

沒有登入驗證。

只要能連到 Server 的人,就可能控制設備。

四十、正式 IoT Web Control 需要什麼?

真正對 Internet 開放時,應進一步考慮:

HTTPS
Authentication
Authorization
Firewall
Reverse Proxy
Session Security
CSRF Protection
Logging
Rate Limiting

架構可能變成:

Internet
   │
   ▼
HTTPS
   │
   ▼
Reverse Proxy
   │
   ▼
Production WSGI Server
   │
   ▼
Flask
   │
   ▼
Authentication
   │
   ▼
GPIO Control

但這已經屬於更進階的 Web / IoT Security 主題。

本章先以:

LAN 遠端控制

為主要目標。

四十一、延伸成繼電器控制

我們目前使用:

from gpiozero import LED

實際上同樣概念也可以延伸到繼電器。

例如:

Browser
 ↓
Flask
 ↓
GPIO
 ↓
Relay Module
 ↓
Fan

未來就可以設計:

[ FAN ON ]

[ FAN OFF ]

所以本章表面上是在控制 LED,真正學的是:

Web 遠端 GPIO 控制架構

四十二、延伸成多組 GPIO

例如:

GPIO17 → LED
GPIO18 → Relay
GPIO22 → Buzzer

Web Page 可以改成:

Raspberry Pi Control Center

LED
[ ON ] [ OFF ]

FAN
[ ON ] [ OFF ]

BUZZER
[ ON ] [ OFF ]

架構:

Flask
                    │
        ┌───────────┼───────────┐
        │           │           │
     GPIO17       GPIO18      GPIO22
        │           │           │
       LED        Relay       Buzzer
                    │
                   Fan

這就是第 20 章智慧監控中心的基礎。

四十三、Flask + Sensor

Flask 不只是控制 GPIO Output。

同樣可以讀取 Sensor。

例如:

DHT22
 │
 ▼
Python
 │
 ▼
Flask
 │
 ▼
HTML
 │
 ▼
手機

Web Page 可以顯示:

智慧環境監控

Temperature
28.5 °C

Humidity
68 %

Fan
ON

LED Warning
OFF

因此 Browser 會變成 Raspberry Pi 的:

HMI 人機介面。

四十四、Flask + Raspberry Pi Camera

上一章學過:

Picamera2

所以之後也可以加入:

[ CAMERA PHOTO ]

架構:

手機
 │
 │ POST /camera/photo
 ▼
Flask
 │
 ▼
Picamera2
 │
 ▼
Camera Module
 │
 ▼
photo.jpg

第 16 章:

Camera

加上第 17 章:

Flask

就已經可以開始設計:

Raspberry Pi Web Camera。

四十五、Flask + SQLite

第 19 章還會加入:

SQLite

架構將變成:

Sensor
  │
  ▼
Python
  │
  ├──────────────► SQLite
  │                  │
  │                  ▼
  │              History Data
  │
  ▼
Flask
  │
  ▼
Web Browser

使用者就可以在手機查看:

目前溫度
目前濕度
設備狀態
歷史資料

四十六、Flask + MQTT

下一章會介紹:

MQTT

到時架構會變成:

Raspberry Pi
                      │
          ┌───────────┼───────────┐
          │           │           │
        Flask       MQTT        GPIO
          │           │           │
        HTTP        Broker       LED
          │
        Browser

Flask 適合:

Web 操作
Dashboard
Browser Control

MQTT 適合:

IoT Message
Sensor Publish
Device Subscribe
Machine-to-Machine

兩者可以同時存在。

四十七、HTTP 與 MQTT 有什麼不同?

簡單比較:

HTTP / Flask 與 MQTT 比較
項目 HTTP / Flask MQTT
架構 Client / Server Publisher / Broker / Subscriber
Web Browser 非常適合 通常需要額外 Client
Dashboard 適合 可配合其他系統
IoT Sensor 可以 非常適合
即時裝置訊息 可以 很適合
Topic 無 有
Broker 不需要 需要
本章 Flask 下一章

因此:

手機操作介面

Flask 很方便。

而:

大量 IoT 裝置交換 Sensor Data

MQTT 通常更適合。

四十八、本章系統與前面章節整合

到目前為止,我們已經逐步建立:

Raspberry Pi OS
      │
      ▼
Linux
      │
      ▼
Python
      │
      ├──────── GPIO
      │           │
      │           ├── LED
      │           ├── Buzzer
      │           └── Relay
      │
      ├──────── Sensor
      │
      ├──────── I²C LCD
      │
      ├──────── Camera
      │
      └──────── Flask
                   │
                   ▼
               Web Browser

Raspberry Pi 已經開始從:

單機嵌入式控制器

進化成:

網路化控制平台。

四十九、本章完整系統資料流

顯示網頁

手機 Browser
     │
     │ GET /
     ▼
Flask
     │
     ▼
build_page()
     │
     ▼
讀取 led.is_lit
     │
     ▼
產生 HTML
     │
     ▼
手機 Browser

開啟 LED

手機
 │
 │ POST /led/on
 ▼
Flask
 │
 ▼
led_on()
 │
 ▼
led.on()
 │
 ▼
GPIO17
 │
 ▼
LED ON

關閉 LED

手機
 │
 │ POST /led/off
 ▼
Flask
 │
 ▼
led_off()
 │
 ▼
led.off()
 │
 ▼
GPIO17
 │
 ▼
LED OFF

這三個流程就是本章最重要的觀念。

五十、本章常用指令整理

更新套件:

sudo apt update

安裝 Flask:

sudo apt install -y python3-flask

安裝 GPIO Zero:

sudo apt install -y python3-gpiozero

查看 GPIO Pin:

pinout

查看 IP:

hostname -I

建立專案:

mkdir -p ~/raspberrypi_web_gpio

進入:

cd ~/raspberrypi_web_gpio

編輯:

nano app.py

執行:

python3 app.py

瀏覽器:

http://Raspberry-Pi-IP:5000

例如:

http://192.168.1.100:5000

停止 Flask:

Ctrl + C

五十一、本章常見錯誤

問題 1:ModuleNotFoundError: No module named ‘flask’

安裝:

sudo apt update
sudo apt install -y python3-flask

問題 2:No module named gpiozero

安裝:

sudo apt install -y python3-gpiozero

問題 3:網頁正常但 LED 不亮

先不要檢查 Flask。

先執行:

python3 led_test.py

確認:

GPIO
電阻
LED 極性
GND

正確。

如果單純 GPIO 測試都無法控制 LED,問題通常不在 Flask。

問題 4:LED 一直亮

檢查:

LED 接線
GPIO 編號
程式是否還在執行

並確認使用:

LED(17)

代表:

BCM GPIO17

問題 5:手機顯示無法連線

確認:

Raspberry Pi IP
手機與 Pi 網路互通
Flask 是否正在執行
Port 5000
host="0.0.0.0"

五十二、Raspberry Pi 重新開機後 IP 改變怎麼辦?

因為一般家用 Router 通常透過 DHCP 配發 IP。

例如原本:

192.168.1.100

重新開機後可能變:

192.168.1.105

因此實際 IoT 專案可以進一步考慮:

  • DHCP Reservation
  • 固定 LAN IP
  • mDNS Hostname
  • DNS

例如某些網路環境可使用:

http://raspberrypi.local:5000

不過 .local 是否可以正常解析取決於 Client、網路及 mDNS 環境,因此實驗初期建議直接使用:

Raspberry Pi LAN IP

最容易 Debug。

五十三、為什麼 Raspberry Pi 非常適合當 Web GPIO Server?

Arduino UNO 很適合:

GPIO
Sensor
Motor
Real-time Control

但是 Raspberry Pi 同時具有:

Linux
Python
Wi-Fi
Ethernet
TCP/IP
HTTP
Web Server
Database
Camera
MQTT
SSH

所以 Raspberry Pi 很適合建立:

Web + Hardware

系統。

例如:

Web Smart Home

Web Environment Monitor

Web Camera

Web Relay Controller

Web Robot Controller

IoT Gateway

這也是 Raspberry Pi 與一般微控制器最大的應用差異之一。

五十四、本章完成成果

完成本章後,我們已經建立:

Raspberry Pi 手機 Web GPIO 控制器

硬體:

Raspberry Pi
 │
GPIO17
 │
220Ω~330Ω
 │
LED
 │
GND

軟體:

Raspberry Pi OS
      │
    Python
      │
    Flask
      │
 GPIO Zero

網路:

Smartphone
    │
   Wi-Fi
    │
  Router
    │
Raspberry Pi

控制:

Browser
  │
  ├── LED ON
  │
  └── LED OFF

這已經是一套完整的小型:

Raspberry Pi IoT Web Control System

五十五、本章重點整理

本章最重要的不是只學會「用手機開 LED」。

真正需要理解的是以下架構:

Client
  │
  │ HTTP
  ▼
Server
  │
  ▼
Flask
  │
  ▼
Route
  │
  ▼
Python Function
  │
  ▼
GPIO Zero
  │
  ▼
GPIO
  │
  ▼
Hardware

其中:

Client = 手機 Browser
Server = Raspberry Pi
HTTP = 網路通訊
Flask = Python Web Framework
Route = URL 與程式功能對應
GPIO Zero = GPIO 控制 Library
GPIO17 = 硬體輸出
LED = 最終受控設備

只要理解這個架構,把 LED 換成:

Relay
Fan
Motor
Buzzer
Light
Pump
Camera

控制原理基本上完全相同。

五十六、下一章預告

下一章將正式進入:

第 18 章 Raspberry Pi IoT 入門:MQTT 遠端感測與裝置控制

我們會學習:

  • IoT
  • MQTT
  • Broker
  • Publisher
  • Subscriber
  • Topic
  • Mosquitto
  • Python MQTT
  • Sensor Data
  • 遠端控制
  • IoT Architecture

並完成:

Raspberry Pi MQTT 溫度監控與 LED 控制

系統會從本章:

手機
 ↓
HTTP
 ↓
Flask
 ↓
Raspberry Pi
 ↓
LED

進一步發展為:

Raspberry Pi
          │
          │ MQTT Publish
          ▼
       Mosquitto
        Broker
       ▲      │
       │      ▼
 Subscriber  Publisher
       │      │
       ▼      ▼
 Sensor     LED Control
 Monitor

這將正式進入真正的:

Raspberry Pi IoT 架構。

下一步學習

不要停在這一篇,接著把內容做成自己的實作

目前主題:Raspberry Pi。從完整學習路線、免費資源、會員下載,再接到實作所需材料。

同系列:Raspberry-Pi |  已是會員?直接前往 Getfile
相關資源與會員文章下載
文章可免費閱讀;下載完整 DOCX 或 PDF 需登入免費基本會員。
會員免費下載 DOCX 會員免費 PDF/列印

← 回文章列表