在不到 30 分钟内构建一个树莓派监控仪表盘
使用 Python 制作一个 API 来监控你的树莓派硬件，并使用 Appsmith 建立一个仪表盘。
监控 仪表盘
使用 Python 制作一个 API 来监控你的树莓派硬件，并使用 Appsmith 建立一个仪表盘。
![](/data/attachment/album/202307/10/102705vfe3pb0wbqnf0see.jpg)



> 
> 使用 Python 制作一个 API 来监控你的树莓派硬件，并使用 Appsmith 建立一个仪表盘。
> 
> 
> 


如果你想知道你的树莓派的性能如何，那么你可能需要一个树莓派的仪表盘。在本文中，我将演示如何快速构建一个按需监控仪表盘，以实时查看你的树莓派的 CPU 性能、内存和磁盘使用情况，并根据需要随时添加更多视图和操作。


如果你已经使用 Appsmith，你还可以直接导入 [示例应用程序](https://github.com/appsmithorg/foundry/tree/main/resources/blogs/Raspberry%20Pi%20Dashboard) 并开始使用。


### Appsmith


Appsmith 是一个开源的 [低代码](https://www.redhat.com/architect/low-code-platform?intcmp=7013a000002qLH8AAM) 应用构建工具，帮助开发人员轻松快速地构建内部应用，如仪表盘和管理面板。它是一个用于仪表盘的很好选择，并减少了传统编码方法所需的时间和复杂性。


在此示例的仪表盘中，我显示以下统计信息：


* CPU
	+ 占用百分比
	+ 频率或时钟速度
	+ 计数
	+ 温度
* 内存
	+ 占用百分比
	+ 可用内存百分比
	+ 总内存
	+ 空闲内存
* 磁盘
	+ 磁盘使用百分比
	+ 绝对磁盘空间使用量
	+ 可用磁盘空间
	+ 总磁盘空间


### 创建一个端点


你需要一种从树莓派获取这些数据并传递给 Appsmith 的方法。[psutil](https://psutil.readthedocs.io/en/latest/) 是一个用于监控和分析的 Python 库，而 [Flask-RESTful](https://flask-restful.readthedocs.io/en/latest/) 是一个创建 [REST API](https://www.redhat.com/en/topics/api/what-is-a-rest-api?intcmp=7013a000002qLH8AAM) 的 Flask 扩展。


Appsmith 每隔几秒钟调用 REST API 以自动刷新数据，并以 JSON 对象作为响应，其中包含所有所需的统计信息，如下所示：



```
{ "cpu_count": 4,
"cpu_freq": [
600.0,
600.0,
1200.0 ],
"cpu_mem_avail": 463953920,
"cpu_mem_free": 115789824,
"cpu_mem_total": 971063296,
"cpu_mem_used": 436252672,
"cpu_percent": 1.8,
"disk_usage_free": 24678121472,
"disk_usage_percent": 17.7,
"disk_usage_total": 31307206656,
"disk_usage_used": 5292728320,
"sensor_temperatures": 52.616 }

```

#### 1、设置 REST API


如果你的树莓派尚未安装 Python，请在树莓派上打开终端并运行此安装命令：



```
$ sudo apt install python3

```

现在为你的开发设置一个 [Python 虚拟环境](https://opensource.com/article/20/10/venv-python)：



```
$ python -m venv PiData

```

接下来，激活该环境。你必须在重新启动树莓派后执行此操作。



```
$ source PiData/bin/activate
$ cd PiData

```

为了安装 Flask、Flask-RESTful 和以后需要的依赖项，请在你的 Python 虚拟环境中创建一个名为 `requirements.txt` 的文件，并将以下内容添加到其中：



```
flask
flask-restful
gunicorn

```

保存文件，然后使用 `pip` 一次性安装它们。你必须在重新启动树莓派后执行此操作。



```
(PyData)$ python -m pip install -r requirements.txt

```

接下来，创建一个名为 `pi_stats.py` 的文件来存放使用 `psutil` 检索树莓派系统统计信息的逻辑。将以下代码粘贴到 `pi_stats.py` 文件中：



```
from flask import Flask
from flask_restful import Resource, Api
import psutil
app = Flask(__name__)

api = Api(app)
class PiData(Resource):
    def get(self):
        return "RPI Stat dashboard"

api.add_resource(PiData, '/get-stats')

if __name__ == '__main__':
    app.run(debug=True)

```

这段代码的作用如下：


* 使用 `app = Flask(name)` 来定义嵌套 API 对象的应用程序。
* 使用 Flask-RESTful 的 [API 方法](https://flask-restful.readthedocs.io/en/latest/api.html#id1) 来定义 API 对象。
* 在 Flask-RESTful 中将 `PiData` 定义为具体的 [Resource 类](https://flask-restful.readthedocs.io/en/latest/api.html#flask_restful.Resource) ，以公开每个支持的 HTTP 方法。
* 使用 `api.add_resource(PiData, '/get-stats')` 将资源 `PiData` 附加到 API 对象 `api`。
* 每当你访问 URL `/get-stats` 时，将返回 `PiData` 作为响应。


#### 2、使用 psutil 读取统计信息


要从你的树莓派获取统计信息，你可以使用 `psutil` 提供的这些内置函数：


* `cpu_percentage`、`cpu_count`、`cpu_freq` 和 `sensors_temperatures` 函数分别用于获取 CPU 的占用百分比、计数、时钟速度和温度。`sensors_temperatures` 报告了与树莓派连接的所有设备的温度。要仅获取 CPU 的温度，请使用键 `cpu-thermal`。
* `virtual_memory` 函数可返回总内存、可用内存、已使用内存和空闲内存的统计信息（以字节为单位）。
* `disk_usage` 函数可返回总磁盘空间、已使用空间和可用空间的统计信息（以字节为单位）。


将所有函数组合到一个 Python 字典中的示例如下：



```
system_info_data = {
'cpu_percent': psutil.cpu_percent(1),
'cpu_count': psutil.cpu_count(),
'cpu_freq': psutil.cpu_freq(),
'cpu_mem_total': memory.total,
'cpu_mem_avail': memory.available,
'cpu_mem_used': memory.used,
'cpu_mem_free': memory.free,
'disk_usage_total': disk.total,
'disk_usage_used': disk.used,
'disk_usage_free': disk.free,
'disk_usage_percent': disk.percent,
'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current,
}

```

下一节将使用该字典。


#### 3、从 Flask-RESTful API 获取数据


为了在 API 响应中看到来自树莓派的数据，请更新 `pi_stats.py` 文件，将字典 `system_info_data` 包含在 `PiData` 类中：



```
from flask import Flask
from flask_restful import Resource, Api
import psutil
app = Flask(__name__)
api = Api(app)

class PiData(Resource):
    def get(self):
        memory = psutil.virtual_memory()
        disk = psutil.disk_usage('/')
        system_info_data = {
            'cpu_percent': psutil.cpu_percent(1),
            'cpu_count': psutil.cpu_count(),
            'cpu_freq': psutil.cpu_freq(),
            'cpu_mem_total': memory.total,
            'cpu_mem_avail': memory.available,
            'cpu_mem_used': memory.used,
            'cpu_mem_free': memory.free,
            'disk_usage_total': disk.total,
            'disk_usage_used': disk.used,
            'disk_usage_free': disk.free,
            'disk_usage_percent': disk.percent,
            'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current, }

    return system_info_data

api.add_resource(PiData, '/get-stats')

if __name__ == '__main__':
    app.run(debug=True)

```

你的脚本已经就绪，下面运行 `PiData.py`：



```
$ python PyData.py
 * Serving Flask app "PiData" (lazy loading)
 * Environment: production
 WARNING: This is a development server. Do not run this in a production environment.
 
 * Debug mode: on
 * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!

```

你有了一个可以工作的 API。


#### 4、将 API 提供给互联网


你可以在本地网络中与 API 进行交互。然而，要在互联网上访问它，你必须在防火墙中打开一个端口，并将传入的流量转发到由 Flask 提供的端口。然而，正如你的测试输出建议的那样，在 Flask 中运行 Flask 应用程序仅适用于开发，而不适用于生产。为了安全地将 API 提供给互联网，你可以使用安装过程中安装的 `gunicorn` 生产服务器。


现在，你可以启动 Flask API。每次重新启动树莓派时都需要执行此操作。



```
$ gunicorn -w 4 'PyData:app'
Serving on http://0.0.0.0:8000

```

要从外部世界访问你的树莓派，请在网络防火墙中打开一个端口，并将流量定向到你树莓派的 IP 地址，端口为 8000。


首先，获取树莓派的内部 IP 地址：



```
$ ip addr show | grep inet

```

内部 IP 地址通常以 10 或 192 或 172 开头。


接下来，你必须配置防火墙。通常，你从互联网服务提供商（ISP）获取的路由器中嵌入了防火墙。通常，你可以通过网络浏览器访问家用路由器。路由器的地址有时会打印在路由器的底部，它以 192.168 或 10 开头。不过，每个设备都不同，因此我无法告诉你需要点击哪些选项来调整设置。关于如何配置防火墙的完整描述，请阅读 Seth Kenlon 的文章 《[打开端口并通过你的防火墙路由流量](https://opensource.com/article/20/9/firewall)》。


或者，你可以使用 [localtunnel](https://theboroer.github.io/localtunnel-www/) 来使用动态端口转发服务。


一旦你的流量到达树莓派，你就可以查询你的 API：



```
$ curl https://example.com/get-stats
{
   "cpu_count": 4,
   "cpu_freq": [
      600.0,
      600.0,
      1200.0 ],
   "cpu_mem_avail": 386273280,
   ...

```

如果你已经执行到这一步，那么最困难的部分已经过去了。


#### 5、重复步骤


如果你重新启动了树莓派，你必须按照以下步骤进行操作：


* 使用 `source` 重新激活 Python 环境
* 使用 `pip` 刷新应用程序的依赖项
* 使用 `gunicorn` 启动 Flask 应用程序


你的防火墙设置是持久的，但如果你使用了 localtunnel，则必须在重新启动后启动新的隧道。


如果你愿意，可以自动化这些任务，但那是另一个教程的内容。本教程的最后一部分是在 Appsmith 上构建一个用户界面，使用拖放式小部件和一些 JavaScript，将你的树莓派数据绑定到用户界面。相信我，从现在开始很容易！


### 在 Appsmith 上构建仪表盘


![硬件监控仪表盘](/data/attachment/album/202307/10/102926j2mkk9aak9n92rxk.png)


要制作一个像这样的仪表盘，你需要将公开的 API 端点连接到 Appsmith，使用 Appsmith 的小部件库构建用户界面，并将 API 的响应绑定到小部件上。如果你已经使用 Appsmith，你可以直接导入 [示例应用程序](https://github.com/appsmithorg/foundry/tree/main/resources/blogs/Raspberry%20Pi%20Dashboard) 并开始使用。


如果你还没有，请 [注册](https://appsmith.com/sign-up) 一个免费的 Appsmith 帐户。或者，你可以选择 [自托管 Appsmith](https://docs.appsmith.com/getting-started/setup)。


### 将 API 作为 Appsmith 数据源连接


登录到你的 Appsmith 帐户。


* 在左侧导航栏中找到并点击 “<ruby> 查询或 JS <rt>  QUERIES/JS </rt></ruby>” 旁边的 “+” 按钮。
* 点击 “<ruby> 创建一个空白 API <rt>  Create a blank API </rt></ruby>”。
* 在页面顶部，将你的项目命名为 “PiData”。
* 获取你的 API 的 URL。如果你使用的是 localtunnel，则是一个 `localtunnel.me` 地址，总是在末尾添加 `/get-stats` 以获取统计数据。将其粘贴到页面的第一个空白字段中，然后点击 “RUN” 按钮。


确保在 “<ruby> 响应 <rt>  Response </rt></ruby>” 面板中看到成功的响应。


![Appsmith 界面](/data/attachment/album/202307/10/103200q8rrrn082ar0rrwr.jpg)


### 构建用户界面


Appsmith 的界面非常直观，但如果你感到迷失，我建议你查看 [在 Appsmith 上构建你的第一个应用程序](https://docs.appsmith.com/getting-started/start-building) 教程。


对于标题，将 “<ruby> 文本 <rt>  Text </rt></ruby>”、“<ruby> 图像 <rt>  Image </rt></ruby>” 和 “<ruby> 分隔线 <rt>  Divider </rt></ruby>” 小部件拖放到画布上。将它们排列如下：


![设置项目标题](/data/attachment/album/202307/10/103210gz1ksff34zn66n11.jpg)


“<ruby> 文本 <rt>  Text </rt></ruby>” 小部件包含你页面的实际标题。键入比“Raspberry Pi Stats”更酷的内容。


“<ruby> 图像 <rt>  Image </rt></ruby>” 小部件用于展示仪表盘的独特标志。你可以使用你喜欢的任何标志。


使用 “<ruby> 开关 <rt>  Switch </rt></ruby>” 小部件来切换实时数据模式。在 “<ruby> 属性 <rt>  Property </rt></ruby>” 面板中进行配置，以从你构建的 API 获取数据。


对于主体部分，使用来自左侧的小部件库的以下小部件创建一个 CPU 统计信息区域，使用以下小部件：


* <ruby> 进度条 <rt>  Progress Bar </rt></ruby>
* <ruby> 统计框 <rt>  Stat Box </rt></ruby>
* <ruby> 图表 <rt>  Chart </rt></ruby>


对于内存和磁盘统计信息部分，重复相同的步骤。磁盘统计信息部分不需要图表，但如果你能找到用途，那也可以使用它。


你的最终小部件布局应该类似于以下：


![Appsmith 中的属性设置](/data/attachment/album/202307/10/103222zc4h4yb8h4fog2wx.jpg)


最后一步是将 API 的数据绑定到你的小部件上。


### 将数据绑定到小部件上


返回到画布，并在三个类别的部分中找到你的小部件。首先设置 CPU 统计信息。


要将数据绑定到 “<ruby> 进度条 <rt>  Progress Bar </rt></ruby>” 小部件：


* 单击 “<ruby> 进度条 <rt>  Progress Bar </rt></ruby>” 小部件，以打开右侧的 “<ruby> 属性 <rt>  Property </rt></ruby>” 面板。
* 查找 “<ruby> 进度 <rt>  Progress </rt></ruby>” 属性。
* 单击 “JS” 按钮以激活 JavaScript。
* 在 “<ruby> 进度 <rt>  Progress </rt></ruby>” 字段中粘贴 `{{PiData.data.cpu_percent ?? 0}}`。此代码引用了你的 API 的数据流，名为 `PiData`。Appsmith 将响应数据缓存在 `PiData` 的 `.data` 运算符内。键 `cpu_percent` 包含了 Appsmith 用来显示 CPU 利用率百分比的数据。
* 在 “<ruby> 进度条 <rt>  Progress Bar </rt></ruby>” 小部件下方添加一个 “<ruby> 文本 <rt>  Text </rt></ruby>” 小部件作为标签。


![在配置屏幕中绑定数据](/data/attachment/album/202307/10/103234kbryjjgjsk060bkb.jpg)


在 CPU 部分有三个 “<ruby> 统计框 <rt>  Stat Box </rt></ruby>” 小部件。将数据绑定到每个小部件的步骤与绑定 “<ruby> 进度条 <rt>  Progress Bar </rt></ruby>” 小部件的步骤完全相同，只是你需要从 `.data` 运算符中绑定不同的数据属性。按照相同的步骤进行操作，但有以下例外：


* 使用 `{{${PiData.data.cpu_freq[0]} ?? 0 }}` 来显示时钟速度。
* 使用 `{{${PiData.data.cpu_count} ?? 0 }}` 来显示 CPU 计数。
* 使用 `{{${(PiData.data.sensor_temperatures).toPrecision(3)} ?? 0 }}` 来显示 CPU 温度数据。


如果一切顺利，你将得到一个漂亮的仪表盘，如下所示：


![树莓派的仪表盘](/data/attachment/album/202307/10/103242jiiam03mki3i0r60.jpg)


### CPU 利用率趋势图


你可以使用 “<ruby> 图表 <rt>  Chart </rt></ruby>” 小部件将 CPU 利用率显示为趋势线，并使其随时间自动更新。


首先，单击小部件，在右侧找到 “<ruby> 图表类型 <rt>  Chart Type </rt></ruby>” 属性，并将其更改为 “<ruby> 折线图 <rt>  LINE CHART </rt></ruby>”。为了显示趋势线，需要将 `cpu_percent` 存储在数据点数组中。你的 API 目前将其作为单个时间数据点返回，因此可以使用 Appsmith 的 `storeValue` 函数（Appsmith 内置的 `setItem` 方法的一个原生实现）来获取一个数组。


在 “<ruby> 查询或 JS <rt>  QUERIES/JS </rt></ruby>” 旁边单击 “+” 按钮，并将其命名为 “utils”。


将以下 JavaScript 代码粘贴到 “<ruby> 代码 <rt>  Code </rt></ruby>” 字段中：



```
export default {
  getLiveData: () => {
  //When switch is on:
    if (Switch1.isSwitchedOn) {
      setInterval(() => {
        let utilData = appsmith.store.cpu_util_data;

        PiData.run()
          storeValue("cpu_util_data", [...utilData, {
            x: PiData.data.cpu_percent,
            y: PiData.data.cpu_percent
          }]);           
        }, 1500, 'timerId')
      } else {
    clearInterval('timerId');
  }
},
initialOnPageLoad: () => {
  storeValue("cpu_util_data", []);
  }
}

```

为了初始化 `Store`，你在 `initialOnPageLoad` 对象中创建了一个 JavaScript 函数，并将 `storeValue` 函数放在其中。


你使用 `storeValue("cpu_util_data", []);` 将 `cpu_util_data` 中的值存储到 `storeValue` 函数中。此函数在页面加载时运行。


到目前为止，每次刷新页面时，代码都会将 `cpu_util_data` 中的一个数据点存储到 `Store` 中。为了存储一个数组，你使用了 `x` 和 `y` 的下标变量，两者都存储了来自 `cpu_percent` 数据属性的值。


你还希望通过设定存储值之间的固定时间间隔来自动存储这些数据。当执行 [setInterval](https://docs.appsmith.com/reference/appsmith-framework/widget-actions/intervals-time-events#setinterval) 函数时：


* 获取存储在 `cpu_util_data` 中的值。
* 调用 API `PiData`。
* 使用返回的最新 `cpu_percent` 数据将 `cpu_util_data` 更新为 `x` 和 `y` 变量。
* 将 `cpu_util_data` 的值存储在键 `utilData` 中。
* 仅当设置为自动执行函数时，才重复执行步骤 1 到 4。你使用 Switch 小部件将其设置为自动执行，这就解释了为什么有一个 `getLiveData` 父函数。


在 “<ruby> 设置 <rt>  Settings </rt></ruby>” 选项卡中，找到对象中的所有父函数，并在 “<ruby> 页面加载时运行 <rt>  RUN ON PAGE LOAD </rt></ruby>” 选项中将 `initialOnPageLoad` 设置为 “Yes（是）”。


![设置页面加载时要执行的函数](/data/attachment/album/202307/10/103253apiwjbjbiu6fj3wp.jpg)


现在刷新页面进行确认。


返回到画布。单击 “<ruby> 图表 <rt>  Chart </rt></ruby>” 小部件，并找到 “<ruby> 图表数据 <rt>  Chart Data </rt></ruby>” 属性。将绑定 `{{ appsmith.store.disk_util_data }}` 粘贴到其中。这样，如果你自己多次运行对象 `utils`，就可以获得图表数据。要自动运行此操作：


* 查找并单击仪表盘标题中的 “<ruby> 实时数据开关 <rt>  Live Data Switch </rt></ruby>” 小部件。
* 查找 `onChange` 事件。
* 将其绑定到 `{{ utils.getLiveData() }}`。JavaScript 对象是 `utils`，而 `getLiveData` 是在你切换开关时激活的函数，它会从你的树莓派获取实时数据。但是还有其他实时数据，因此同一开关也适用于它们。继续阅读以了解详情。


将数据绑定到内存和磁盘部分的小部件与你在 CPU 统计信息部分所做的方式类似。


对于内存部分，绑定如下所示：


* 进度条中的绑定为：`{{( PiData.data.cpu_mem_avail/1000000000).toPrecision(2) \* 100 ?? 0 }}`。
* 三个统计框小部件的绑定分别为：`{{ \${(PiData.data.cpu_mem_used/1000000000).toPrecision(2)} ?? 0 }} GB`、`{{ \${(PiData.data.cpu_mem_free/1000000000).toPrecision(2)} ?? 0}} GB` 和 `{{ \${(PiData.data.cpu_mem_total/1000000000).toPrecision(2)} ?? 0 }} GB`。


对于磁盘部分，进度条和统计框小部件的绑定分别变为：


* 进度条的绑定为：`{{ PiData.data.disk_usage_percent ?? 0 }}`。
* 三个统计框小部件的绑定分别为：`{{ \${(PiData.data.disk_usage_used/1000000000).toPrecision(2)} ?? 0 }} GB`、`{{ \${(PiData.data.disk_usage_free/1000000000).toPrecision(2)} ?? 0 }} GB` 和 `{{ \${(PiData.data.disk_usage_total/1000000000).toPrecision(2)} ?? 0 }} GB`。


这里的图表需要更新你为 CPU 统计信息创建的 `utils` 对象，使用 `storeValue` 键名为 `disk_util_data`，嵌套在 `getLiveData` 下面，其逻辑与 `cpu_util_data` 类似。对于磁盘利用率图表，我们存储的 `disk_util_data` 的逻辑与 CPU 利用率趋势图的逻辑相同。



```
export default {
  getLiveData: () => {
  //When switch is on:
    if (Switch1.isSwitchedOn) {
      setInterval(() => {
       const cpuUtilData = appsmith.store.cpu_util_data;
       const diskUtilData = appsmith.store.disk_util_data;                   
       
       PiData.run();
       
       storeValue("cpu_util_data", [...cpuUtilData, { x: PiData.data.cpu_percent,y: PiData.data.cpu_percent }]);
       storeValue("disk_util_data", [...diskUtilData, { x: PiData.data.disk_usage_percent,y: PiData.data.disk_usage_percent }]);
    }, 1500, 'timerId')
  } else {
    clearInterval('timerId');
  }
},
  initialOnPageLoad: () => {
    storeValue("cpu_util_data", []);
    storeValue("disk_util_data", []);
  }
}

```

通过使用 `utils` JavaScript 对象在打开和关闭真实数据开关时触发的数据流可视化如下所示：


![切换](/data/attachment/album/202307/10/102928s4lkngonzh787bkh.gif)


在打开实时数据开关时，图表会变成这样：


![显示实时数据](/data/attachment/album/202307/10/102932vh4s65lhjlhjppzp.gif)


整体上，它既漂亮，又简约，而且非常有用。


### 祝你使用愉快！


当你对 `psutils`、JavaScript 和 Appsmith 更加熟悉时，我相信你会发现可以轻松无限地调整你的仪表板，实现非常酷的功能，例如：


* 查看先前一周、一个月、一个季度、一年或根据你的树莓派数据允许的任何自定义范围的趋势
* 为任何统计数据的阈值违规构建报警机制
* 监控连接到你的树莓派的其他设备
* 将 `psutils` 扩展到另一台安装有 Python 的计算机上
* 使用其他库监控你家庭或办公室的网络
* 监控你的花园
* 跟踪你自己的生活习惯


在下一个令人兴奋的项目中，祝你玩得愉快！


*（题图：MJ/9754eb1f-1722-4897-9c35-3f20c285c332）*




---


via: <https://opensource.com/article/23/3/build-raspberry-pi-dashboard-appsmith>


作者：[Keyur Paralkar](https://opensource.com/users/keyur-paralkar) 选题：[lkxed](https://github.com/lkxed/) 译者：ChatGPT 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

