仅仅使用代码,就能点亮树莓派的 GPIO 世界

描述

 

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和一个按钮。当然,你的场景可以(应该!)与此不同,因为它只是一个示例,因此也非常简单。

 

GPIO

LED通过330Ω串联电阻连接到GPIO 17,按钮连接到3.3V和GPIO 21。

 

此外,我们在以下内容中使用GPIO的BCM编号,而不是板载编号:

 

Raspberry Pi GPIO引脚分配

 

GPIO

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。总的来说,我觉得通过Python的解决方案更加舒适,而且它拥有最多的兼容扩展。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分