Raspberry Pi的一個流行應用是構建Web服務器。為此,我們可以使用不同的技術,如Python、Node.JS甚至PHP。由于Raspberry Pi的絕大多數腳本都是用Python編寫的,因此使用Python創建REST API接口也是合情合理的。然后,我們可以調用特定的函數,例如控制或讀取GPIO。這可以方便地控制LED或其他傳感器/模塊。其美妙之處在于,我們可以使迄今為止為Raspberry Pi用Python編寫的幾乎所有代碼都可以輕松通過REST API進行調用。因此,在本教程中,我們將使用FastAPI創建這樣一個接口,并探討如何擴展和保障其安全。
所需硬件部件
原則上,本教程不需要太多的配件。但是,由于我們想測試我們的設置是否有效,我建議使用以下部件:
Raspberry Pi
LED燈
330Ω電阻
面包板
雌性-雌性跳線
當然,你可以根據自己的需求進行擴展,并連接傳感器(如?溫度傳感?器等),我們可以通過API對其進行查詢。
什么是REST API?
API(應用程序編程接口)是一種可以通過URL等調用的接口。REST(表述性狀態轉移)概括了一些原則,描述了接口應該如何表現,例如,GET請求應該是只讀的,并且不應該更改服務器上的任何內容。另一方面,POST命令允許創建新實體(例如,書籍的新實例)。你可以在這里了解更多關于實現的信息。
Raspberry Pi上的設置
在本教程中,Raspberry Pi上的設置非常簡單,因為我們只使用一個LED和一個按鈕。當然,你的場景可以(應該!)與此不同,因為它只是一個示例,因此也非常簡單。
LED通過330Ω串聯電阻連接到GPIO 17,按鈕連接到3.3V和GPIO 21。
此外,我們在以下內容中使用GPIO的BCM編號,而不是板載編號:
Raspberry PiGPIO引腳分配
Python REST API 的軟件組件
現在,我們將逐步創建API。首先,我們準備所需的工具。之后,我們創建并擴展我們的REST API,以切換或讀取GPIO。最后但同樣重要的是,我們要保障API的安全,以免任何人都可以訪問它。
順便說一下:你也可以在Github上找到我們將逐步講解的整個代碼。
安裝庫
在開始之前,我們需要Python3和一些庫,我們通過包安裝器pip加載它們。
sudo apt-get install python3 python3-pip
之后,我們可以安裝所需的Python庫:
pip3 install fastapi uvicorn[standard] rpi.gpio
可以在各自的文檔頁面(fastapi、uvicorn、rpi.gpio)上找到更多信息。
入門:首先通過API讀取狀態
讓我們開始第一次測試。為此,我們創建一個簡單的Python腳本。
sudo nano main.py
腳本內容如下:
from fastapi import FastAPIimport RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False) app = FastAPI() @app.get("/read/{gpio}")def read_root(gpio: int): GPIO.setup(gpio, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) return {"gpio": gpio, "on": GPIO.input(gpio)}
使用CTRL+O保存文件,并使用CTRL+X關閉nano編輯器。之后,我們就可以啟動程序了。
uvicorn main:app --reload
現在,你可以在Raspberry Pi的瀏覽器中打開以下URL:http://127.0.0.1:8000/read/17
如果按鈕連接到不同的引腳,你可以更改GPIO編號。如果你沒有按下按鈕,結果將如下所示:
{"gpio":17,"on":false}
這是我們在此端點下定義的響應。如果你按下按鈕并再次調用URL,結果將發生變化。僅用幾行代碼,我們就編寫了第一個REST端點。但現在我們想對其進行擴展。
擴展我們的Python API——設置GPIO狀態
純讀取有點無聊,所以我們當然還想控制和設置GPIO。因此,我們創建了另一個端點(這次是PATCH,因為我們要更改內容):
from fastapi import FastAPIfrom pydantic import BaseModelimport RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False) app = FastAPI() class SetGPIO(BaseModel): on: bool @app.get("/read/{gpio}")def read_root(gpio: int): GPIO.setup(gpio, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) return {"gpio": gpio, "on": GPIO.input(gpio)} @app.patch("/set/{gpio}")def read_item(gpio: int, value: SetGPIO): if value.on: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.HIGH) else: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.LOW) return {"gpio": gpio, "on": value.on}
如您所見,第一個參數再次是GPIO編號,
你可以使用Postman、瀏覽器擴展或cURL(sudo apt-get install curl)。我使用了后者:
curl -X PATCH http://127.0.0.1:8000/set/21 -H "Content-Type: application/json" -d '{"on": true}'
這樣,LED就亮了!
順便說一下,你可以在http://127.0.0.1:8000/docs找到API文檔,這是使用Swagger/OpenAPI自動生成的。為了使響應更具可讀性,我們定義了模型(response_model)。這只是一個具有屬性的類,在端點的定義中,我們聲明將返回此模型。
from fastapi import FastAPIfrom pydantic import BaseModelimport RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False) app = FastAPI() class GpioStatusResponse(BaseModel): gpio: int on: bool class SetGPIO(BaseModel): on: bool @app.get("/read/{gpio}", response_model=GpioStatusResponse)def read_root(gpio: int): GPIO.setup(gpio, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) return GpioStatusResponse(gpio=gpio, on=GPIO.input(gpio)) @app.patch("/set/{gpio}", response_model=GpioStatusResponse)def read_item(gpio: int, value: SetGPIO): if value.on: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.HIGH) else: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.LOW) return GpioStatusResponse(gpio=gpio, on=value.on)
最后一項練習:構建一個端點(POST),用于在GPIO上激活PWM,以便我們能夠調節LED的亮度(點擊此處訪問PWM文檔)。
https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/此外,您現在擁有足夠的資源來構建一個與用戶界面交互的GPIO,例如:
https://github.com/tutRPi/Raspberry-Pi-Simple-Web-GPIO-GUI
安全性——基本認證和其他方法
如果我們開放Raspberry Pi的8000端口,任何人都可以訪問該API。我們要防止這種情況發生,并加入認證機制。為此,我們有幾種選擇:
1.每次調用API時,都會在請求頭中發送用戶名和密碼。為此,我們使用基本認證,并在調用時驗證數據的正確性。
2.另外,我們還可以使用帶有JWT(JSON Web Tokens)的oauth2,它們也是通過請求頭發送的。為了簡化起見,本教程中不會進行此操作。如果您仍然想實現它(作為練習),可以在此處了解更多相關信息。
現在,我們再次打開腳本并相應地進行調整:
from fastapi.security import HTTPBasic, HTTPBasicCredentialsfrom pydantic import BaseModelfrom fastapi import Depends, FastAPI, HTTPException, statusimport RPi.GPIO as GPIOimport secrets GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False) app = FastAPI()security = HTTPBasic() class GpioStatusResponse(BaseModel): gpio: int on: bool class SetGPIO(BaseModel): on: bool def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): correct_username = secrets.compare_digest(credentials.username, "admin") correct_password = secrets.compare_digest(credentials.password, "passw0rd") if not (correct_username and correct_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", headers={"WWW-Authenticate": "Basic"}, ) return credentials.username @app.get("/read/{gpio}", response_model=GpioStatusResponse)def read_root(gpio: int, username: str = Depends(get_current_username)): GPIO.setup(gpio, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) return GpioStatusResponse(gpio=gpio, on=GPIO.input(gpio)) @app.patch("/set/{gpio}", response_model=GpioStatusResponse)def read_item(gpio: int, value: SetGPIO, username: str = Depends(get_current_username)): if value.on: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.HIGH) else: GPIO.setup(gpio, GPIO.OUT, initial=GPIO.LOW) return GpioStatusResponse(gpio=gpio, on=value.on)
為了使查詢能夠成功進行,我們需要包含用戶名和密碼(第24/25行)。使用curl或Postman可以很容易地實現這一點:
curl -X PATCH http://127.0.0.1:8000/set/21 -H "Content-Type: application/json" -d '{"on": false}' -u "admin:passw0rd"
最后但同樣重要的是:如果您希望通過互聯網訪問API(即向外部世界開放您的端口),建議使用SSL證書(如Let’s Encrypt),以確保連接加密。您可以在此頁面上了解更多相關信息。
結論
使用FastAPI,我們可以非常輕松、快速地創建一個REST接口,并調用特定于Raspberry Pi的函數。通過它,我們可以控制GPIO、讀取傳感器數據等等。如果外部系統需要調用Raspberry Pi,這是一個簡單且清晰的解決方案。然而,您應該注意適當的身份驗證,以確保不是每個人都可以遠程控制Raspberry Pi。
作為Python REST API的替代方案,有諸如MQTT之類的解決方案:如果只需要傳輸/接收數據,并且沒有公共API,MQTT是一個不錯的選擇。如果我們仍然需要API,也可以使用Node.JS來切換GPIO??偟膩碚f,我覺得通過Python的解決方案更加舒適,而且它擁有最多的兼容擴展。
-
GPIO
+關注
關注
16文章
1230瀏覽量
52990 -
樹莓派
+關注
關注
118文章
1882瀏覽量
106257
發布評論請先 登錄
相關推薦
詳解樹莓派的gpio功能及實用方法
樹莓派控制PWM控制電機轉速

樹莓派接繼電器的使用

評論