在 30 分钟内构建树莓派监控仪表板

使用 Python 创建一个 API 来监控您的树莓派硬件,并使用 Appsmith 构建一个仪表板。
3 位读者喜欢这篇文章。
8 fun Raspberry Pi projects to try

互联网档案馆图书图像。由 Opensource.com 修改。CC BY-SA 4.0

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

如果您已经在使用 Appsmith,您也可以直接导入示例应用并开始使用。

Appsmith

Appsmith 是一个开源的低代码应用构建器,可帮助开发人员轻松快速地构建内部应用,如仪表板和管理面板。对于您的仪表板来说,这是一个绝佳的选择,并减少了传统编码方法的时间和复杂性。

对于此示例中的仪表板,我显示了以下使用统计数据:

  • CPU
    • 使用率百分比
    • 频率或时钟速度
    • 计数
    • 温度
  • 内存
    • 使用率百分比
    • 可用内存百分比
    • 总内存
    • 可用内存
  • 磁盘
    • 磁盘使用率百分比
    • 已用磁盘空间
    • 可用磁盘空间
    • 总磁盘空间

创建端点

您需要一种方法从您的树莓派 (RPi) 获取这些数据并将其导入 Appsmith。psutils Python 库对于监控和性能分析非常有用,而 Flask-RESTful Flask 扩展创建了一个 REST API

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,请在您的 Pi 上打开一个终端并运行此安装命令:

$ sudo apt install python3

现在为您的开发设置一个 Python 虚拟环境

$ python -m venv PiData

接下来,激活环境。您必须在重启您的 Pi 后执行此操作。

$ source PiData/bin/activate
$ cd PiData

要安装 Flask 和 Flask-RESTful 以及稍后您需要的依赖项,请在您的 Python 虚拟环境中创建一个名为 requirements.txt 的文件,并将以下行添加到其中:

flask
flask-restful
gunicorn

保存文件,然后使用 pip 一次性安装所有这些。您必须在重启您的 Pi 后执行此操作。

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

接下来,创建一个名为 pi_stats.py 的文件,以存放使用 psutils 检索 RPi 系统统计数据的逻辑。将此代码粘贴到您的 pi_stat.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 方法 定义 API 对象。
  • 将 PiData 定义为 Flask-RESTful 中的具体 Resource 类,以公开每个受支持的 HTTP 方法的方法。
  • 使用 api.add_resource(PiData, '/get-stats') 将资源 PiData 附加到 API 对象 api
  • 每当您访问 URL /get-stats 时,PiData 将作为响应返回。

2. 使用 psutils 读取统计数据

要从您的 Pi 获取统计数据,您可以使用 psutils 中的这些内置函数:

  • cpu_percentagecpu_countcpu_freqsensors_temperatures 函数分别用于 CPU 的使用率百分比、计数、时钟速度和温度。sensors_temperatures 报告连接到 RPi 的所有设备的温度。要仅获取 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 的数据,请更新 pi_stats.py 以在类 PiData 中包含字典 system_info_data

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 可在 Internet 上访问

您可以在您的本地网络上与您的 API 交互。但是,要通过 Internet 访问它,您必须在您的防火墙中打开一个端口,并将传入的流量转发到 Flask 提供的端口。但是,正如您的测试输出所建议的那样,从 Flask 运行 Flask 应用仅用于开发,不用于生产。为了安全地使您的 API 可在 Internet 上访问,您可以使用 gunicorn 生产服务器,您在项目设置阶段已安装了它。

现在您可以启动您的 Flask API。您必须在每次重启您的 Pi 后执行此操作。

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

要从外部世界访问您的 Pi,请在您的网络防火墙中打开一个端口,并将传入的流量定向到您的 PI 的 IP 地址,端口为 8000。

首先,获取您的 Pi 的内部 IP 地址:

$ ip addr show | grep inet

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

接下来,您必须配置您的防火墙。通常在您从互联网服务提供商 (ISP) 处获得的路由器中嵌入了防火墙。通常,您可以通过 Web 浏览器访问您的家庭路由器。您的路由器的地址有时印在路由器的底部,它以 192.168 或 10 开头。但是,每台设备都不同,所以我无法准确地告诉您需要单击什么来调整您的设置。有关如何配置防火墙的完整说明,请阅读 Seth Kenlon 的文章打开端口并通过防火墙路由流量

或者,您可以使用 localtunnel 来使用动态端口转发服务。

一旦您的流量到达您的 Pi,您就可以查询您的 API:

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

如果您已走到这一步,那么最困难的部分已经结束。

5. 重复

如果您重启您的 Pi,您必须按照以下步骤操作:

  1. 使用 source 重新激活您的 Python 环境。
  2. 使用 pip 刷新应用程序依赖项。
  3. 使用 gunicorn 启动 Flask 应用程序。

您的防火墙设置是持久的,但是如果您使用 localtunnel,那么您还必须在重启后启动一个新的隧道。

如果您愿意,您可以自动化这些任务,但这完全是另一个教程。本教程的最后一节是在 Appsmith 上使用拖放式小部件和一点 Javascript 构建 UI,以将您的 RPi 数据绑定到 UI。相信我,从这里开始就很容易了!

在 Appsmith 上构建仪表板。

A hardware monitoring dashboard

(Keyur Paralkar, CC BY-SA 4.0)

要获得像这样的仪表板,您需要将公开的 API 端点连接到 Appsmith,使用 Appsmith 的小部件库构建 UI,并将 API 的响应绑定到您的小部件。如果您已经在使用 Appsmith,您可以直接导入示例应用并开始使用。

如果您尚未这样做,请注册一个免费的 Appsmith 帐户。或者,您可以自托管 Appsmith

将 API 连接为 Appsmith 数据源

登录到您的 Appsmith 帐户。

  1. 在左侧导航栏中找到并单击 QUERIES/JS 旁边的 + 按钮。
  2. 单击 创建空白 API
  3. 在页面顶部,将您的项目命名为 PiData
  4. 获取您的 API 的 URL。如果您使用 localtunnel,那么它是一个 localtunnel.me 地址,并且始终在末尾附加 /get-stats 以获取统计数据。将其粘贴到页面上的第一个空白字段中,然后单击 RUN 按钮。

确认您在 Response 窗格中看到成功响应。

The Appsmith interface

(Keyur Paralkar, CC BY-SA 4.0)

构建 UI

AppSmith 的界面非常直观,但是如果您感到迷茫,我建议您浏览 在 Appsmith 上构建您的第一个应用程序 教程。

对于标题,将文本、图像和分隔线小部件拖放到画布上。像这样排列它们:

Set your project title

(Keyur Paralkar, CC BY-SA 4.0)

文本小部件包含您页面的实际标题。输入一些比“树莓派统计信息”更酷的东西。

图像小部件容纳仪表板的独特徽标。您可以使用任何您想要的东西。

使用开关小部件来切换实时数据模式。在 Property 面板中配置它以从您构建的 API 获取数据。

对于正文,使用左侧小部件库中的以下小部件,为 CPU 统计信息创建一个容器小部件:

  • 进度条
  • 统计框
  • 图表

对内存和磁盘统计信息部分执行相同的操作。您不需要磁盘统计信息的图表,但是如果可以找到它的用途,请不要阻止您使用它。

您的小部件的最终排列应如下所示:

Property settings in Appsmith

(Keyur Paralkar, CC BY-SA 4.0)

最后一步是将来自 API 的数据绑定到您拥有的 UI 小部件。

将数据绑定到小部件

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

要将数据绑定到进度条小部件:

  1. 单击进度条小部件以在右侧查看属性面板。
  2. 查找 Progress 属性。
  3. 单击 JS 按钮以激活 Javascript。
  4. Progress 的字段中粘贴 {{PiData.data.cpu_percent ?? 0}}。该代码引用了来自您的名为 PiData 的 API 的数据流。Appsmith 将响应数据缓存在 PiData.data 运算符中。键 cpu_percent 包含 Appsmith 用于显示百分比的数据,在本例中为 CPU 使用率。
  5. 在进度条小部件下方添加一个文本小部件作为标签。
Binding data in the config screen

(Keyur Paralkar, CC BY-SA 4.0)

CPU 部分中有三个统计框小部件。将数据绑定到每个小部件与绑定到进度条小部件完全相同,不同之处在于您从 .data 运算符绑定不同的数据属性。按照相同的步骤进行,但有以下例外:

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

假设一切按计划进行,您最终会得到像这样的漂亮仪表板:

A dashboard for your Raspberry Pi

(Keyur Paralkar, CC BY-SA 4.0)

CPU 使用率趋势

您可以使用图表小部件将 CPU 使用率显示为趋势线,并使其随时间自动更新。

首先,单击小部件,在右侧找到 Chart Type 属性,并将其更改为 LINE CHART。要查看趋势线,请将 cpu_percent 存储在数据点数组中。您的 API 当前将其作为时间上的单个数据点返回,因此请使用 Appsmith 的 storeValue 函数(浏览器 setItem 方法的 Appsmith 原生实现)来获取数组。

单击 QUERIES/JS 旁边的 + 按钮,并将它命名为 utils

将此 Javascript 代码粘贴到 Code 字段中:

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 中。要存储数组,您可以使用下标变量 xy,它们都存储来自 cpu_percent 数据属性的值。

您还希望通过存储值之间的设定间隔自动存储此数据。当 setInterval 函数执行时:

  1. 将获取存储在 cpu_util_data 中的值。
  2. 将调用 API PiData
  3. cpu_util_data 将更新为 xy 变量,其中包含返回的最新 cpu_percent 数据。
  4. cpu_util_data 的值将存储在键 utilData 中。
  5. 步骤 1 到 4 将重复执行,当且仅当该函数设置为自动执行时。您可以使用开关小部件将其设置为自动执行,这解释了为什么存在 getLiveData 父函数。

导航到 Settings 选项卡以查找对象中的所有父函数,并在 RUN ON PAGE LOAD 选项中将 initialOnPageLoad 设置为 Yes

Set the function to execute on page load

(Keyur Paralkar, CC BY-SA 4.0)

现在刷新页面以进行确认。

返回画布。单击图表小部件并找到 Chart Data 属性。粘贴绑定 {{ appsmith.store.disk_util_data }} 到其中。如果您自己运行对象 utils 几次,这将获得您的图表。要自动运行此操作:

  1. 在仪表板的标题中找到并单击 Live Data Switch 小部件。
  2. 查找 onChange 事件。
  3. 将其绑定到 {{ 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 对象,其中名为 disk_util_datastoreValue 键嵌套在 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 对象触发的数据流,如下所示:

Toggling

(Keyur Paralkar, CC BY-SA 4.0)

切换开启后,图表会像这样变化:

Live data display

(Keyur Paralkar, CC BY-SA 4.0)

美观、简约且非常实用。

尽情享用

随着您越来越熟悉 psutils、Javascript 和 Appsmith,我认为您会发现您可以轻松且无休止地调整您的仪表板,以完成非常酷的事情,例如:

  • 查看来自前一周、前一个月、前一季度、前一年或您的 RPi 数据允许的任何自定义范围的趋势
  • 为任何统计信息的阈值突破构建警报机器人
  • 监控连接到您的树莓派的其他设备
  • psutils 扩展到安装了 Python 的另一台计算机
  • 使用另一个库监控您的家庭或办公室网络
  • 监控您的花园
  • 跟踪您自己的生活习惯

直到下一个精彩的构建,祝您黑客愉快!

标签

评论已关闭。

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.