在不到 30 分钟内构建一个树莓派监控仪表盘
监控 仪表盘
![](/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/) 荣誉推出


OK
If you’ve ever wondered about the performance of your Raspberry Pi, then you might need a dashboard for your Pi. In this article, I demonstrate how to quickly building an on-demand monitoring dashboard for your Raspberry Pi so you can see your CPU performance, memory and disk usage in real time, and add more views and actions later as you need them.

If you’re already using Appsmith, you can also import the [sample app](https://github.com/appsmithorg/foundry/tree/main/resources/blogs/Raspberry%20Pi%20Dashboard) directly and get started.

## Appsmith

Appsmith is an open source, [low-code](https://www.redhat.com/architect/low-code-platform?intcmp=7013a000002qLH8AAM) app builder that helps developers build internal apps like dashboards and admin panels easily and quickly. It’s a great choice for your dashboard, and reduces the time and complexity of traditional coding approaches.

For the dashboard in this example, I display usage stats for:

- CPU
- Percentage utilization
- Frequency or clock speed
- Count
- Temperature

- Memory
- Percentage utilization
- Percentage available memory
- Total memory
- Free memory

- Disk
- Percentage disk utilization
- Absolute disk space used
- Available disk space
- Total disk space


## Creating an endpoint

You need a way to get this data from your Raspberry Pi (RPi) and into Appsmith. The [psutils](https://psutil.readthedocs.io/en/latest/) Python library is useful for monitoring and profiling, and the [Flask-RESTful](https://flask-restful.readthedocs.io/en/latest/) Flask extension creates a [REST API](https://www.redhat.com/en/topics/api/what-is-a-rest-api?intcmp=7013a000002qLH8AAM).

Appsmith calls the REST API every few seconds to refresh data automatically, and gets a JSON object in response with all desired stats as shown:

```
``````
{ "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. Set up the REST API

If your Raspberry Pi doesn’t have Python on it yet, open a terminal on your Pi and run this install command:

```
````$ sudo apt install python3`


Now set up a [Python virtual environment](https://opensource.com/article/20/10/venv-python) for your development:

```
````$ python -m venv PiData`


Next, activate the environment. You must do this after rebooting your Pi.

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


To install Flask and Flask-RESTful and dependencies you’ll need later, create a file in your Python virtual environment called `requirements.txt`

and add these lines to it:

```
``````
flask
flask-restful
gunicorn
```


Save the file, and then use `pip`

to install them all at once. You must do this after rebooting your Pi.

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


Next, create a file named `pi_stats.py`

to house the logic for retrieving the RPi’s system stats with `psutils`

. Paste this code into your `pi_stat.py`

file:

```
``````
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)
```


Here’s what the code is doing:

- Use app = Flask(
**name**) to define the app that nests the API object. - Use Flask-RESTful’s
[API method](https://flask-restful.readthedocs.io/en/latest/api.html#id1)to define the API object. - Define PiData as a concrete
[Resource class](https://flask-restful.readthedocs.io/en/latest/api.html#flask_restful.Resource)in Flask-RESTful to expose methods for each supported HTTP method. - Attach the resource,
`PiData`

, to the API object,`api`

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

. - Whenever you hit the URL
`/get-stats`

,`PiData`

is returned as the response.

## 2. Read stats with psutils

To get the stats from your Pi, you can use these built-in functions from `psutils`

:

`cpu_percentage`

,`cpu_count`

,`cpu_freq`

, and`sensors_temperatures`

functions for the percentage utilization, count, clock speed, and temperature respectively, of the CPU`sensors_temperatures`

reports the temperature of all the devices connected to the RPi. To get just the CPU’s temperature, use the key`cpu-thermal`

.`virtual_memory`

for total, available, used, and free memory stats in bytes.`disk_usage`

to return the total, used, and free stats in bytes.

Combining all of the functions in a Python dictionary looks like this:

```
``````
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, }
```


The next section uses this dictionary.

## 3. Fetch data from the Flask-RESTful API

To see data from your Pi in the API response, update `pi_stats.py`

to include the dictionary `system_info_data`

in the class `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)
```


Your script’s ready. Run the `PiData.py`

script:

```
``````
$ 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!
```


You have a working API!

## 4. Make the API available to the internet

You can interact with your API on your local network. To reach it over the internet, however, you must open a port in your firewall and forward incoming traffic to the port made available by Flask. However, as the output of your test advised, running a Flask app from Flask is meant for development, not for production. To make your API available to the internet safely, you can use the `gunicorn`

production server, which you installed during the project setup stage.

Now you can start your Flask API. You must do this any time you’ve rebooted your Pi.

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


To reach your Pi from the outside world, open a port in your network firewall and direct incoming traffic to the IP address of your PI, at port 8000.

First, get the internal IP address of your Pi:

```
````$ ip addr show | grep inet`


Internal IP addresses start with 10 or 192 or 172.

Next, you must configure your firewall. There’s usually a firewall embedded in the router you get from your internet service provider (ISP). Generally, you access your home router through a web browser. Your router’s address is sometimes printed on the bottom of the router, and it begins with either 192.168 or 10. Every device is different, though, so there’s no way for me to tell you exactly what you need to click on to adjust your settings. For a full description of how to configure your firewall, read Seth Kenlon’s article [Open ports and route traffic through your firewall](https://opensource.com/article/20/9/firewall).

Alternately, you can use [localtunnel](https://theboroer.github.io/localtunnel-www/) to use a dynamic port-forwarding service.

Once you’ve got traffic going to your Pi, you can query your API:

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


If you have gotten this far, the toughest part is over.

## 5. Repetition

If you reboot your Pi, you must follow these steps:

- Reactivate your Python environment with
`source`

- Refresh the application dependencies with
`pip`

- Start the Flask application with
`gunicorn`


Your firewall settings are persistent, but if you’re using localtunnel, then you must also start a new tunnel after a reboot.

You can automate these tasks if you like, but that’s a whole other tutorial. The final section of this tutorial is to build a UI on Appsmith using the drag-and-drop widgets, and a bit of Javascript, to bind your RPi data to the UI. Believe me, it’s easy going from here on out!

## Build the dashboard on Appsmith.

![A hardware monitoring dashboard](https://opensource.com/sites/default/files/2023-02/dashboard.png)

(Keyur Paralkar, CC BY-SA 4.0)

To get to a dashboard like this, you need to connect the exposed API endpoint to Appsmith, build the UI using Appsmith’s widgets library, and bind the API’s response to your widgets. If you’re already using Appsmith, you can just import the [sample app](https://github.com/appsmithorg/foundry/tree/main/resources/blogs/Raspberry%20Pi%20Dashboard) directly and get started.

If you haven’t done so already, [sign up](https://appsmith.com/sign-up) for a free Appsmith account. Alternately, you can [self-host Appsmith](https://docs.appsmith.com/getting-started/setup).

## Connect the API as an Appsmith datasource

Sign in to your Appsmith account.

- Find and click the
**+**button next to**QUERIES/JS**in the left nav. - Click
**Create a blank API.** - At the top of the page, name your project
**PiData**. - Get your API’s URL. If you’re using localtunnel, then that’s a
`localtunnel.me`

address, and as always append`/get-stats`

to the end for the stat data. Paste it into the first blank field on the page, and click the**RUN**button.

Confirm that you see a successful response in the **Response** pane.

![The Appsmith interface](https://opensource.com/sites/default/files/2023-02/success.webp)

(Keyur Paralkar, CC BY-SA 4.0)

## Build the UI

The interface for AppSmith is pretty intuitive, but I recommend going through [building your first application on Appsmith](https://docs.appsmith.com/getting-started/start-building) tutorial if you feel lost.

For the title, drag and drop a Text, Image, and Divider widget onto the canvas. Arrange them like this:

![Set your project title](https://opensource.com/sites/default/files/2023-02/TITLE.webp)

(Keyur Paralkar, CC BY-SA 4.0)

The Text widget contains the actual title of your page. Type in something cooler than “Raspberry Pi Stats”.

The Image widget houses a distinct logo for the dashboard. You can use whatever you want.

Use a Switch widget for a toggled live data mode. Configure it in the **Property** pane to get data from the API you’ve built.

For the body, create a place for CPU Stats with a Container widget using the following widgets from the Widgets library on the left side:

- Progress Bar
- Stat Box
- Chart

Do the same for the Memory and Disk stats sections. You don’t need a Chart for disk stats, but don’t let that stop you from using one if you can find uses for it.

Your final arrangement of widgets should look something like this:

![Property settings in Appsmith](https://opensource.com/sites/default/files/2023-02/property.webp)

(Keyur Paralkar, CC BY-SA 4.0)

The final step is to bind the data from the API to the UI widgets you have.

## Bind data to the widgets

Head back to the canvas and find your widgets in sections for the three categories. Set the CPU Stats first.

To bind data to the Progress Bar widget:

- Click the Progress Bar widget to see the Property pane on the right.
- Look for the Progress property.
- Click the
**JS**button to activate Javascript. - Paste
`{{PiData.data.cpu_percent ?? 0}}`

in the field for**Progress**. That code references the stream of data from of your API named`PiData`

. Appsmith caches the response data within the`.data`

operator of`PiData`

. The key`cpu_percent`

contains the data Appsmith uses to display the percentage of, in this case, CPU utilization. - Add a Text widget below the Progress Bar widget as a label.

![Binding data in the config screen](https://opensource.com/sites/default/files/2023-02/config.webp)

(Keyur Paralkar, CC BY-SA 4.0)

There are three Stat Box widgets in the CPU section. Binding data to each one is the exact same as for the Progress Bar widget, except that you bind a different data attribute from the `.data`

operator. Follow the same procedure, with these exceptions:

`{{${PiData.data.cpu_freq[0]} ?? 0 }}`

to show clock speed.`{{${PiData.data.cpu_count} ?? 0 }}`

for CPU count.`{{${(PiData.data.sensor_temperatures).toPrecision(3)} ?? 0 }}`

for CPU temperature data.

Assuming all goes to plan, you end up with a pretty dashboard like this one:

![A dashboard for your Raspberry Pi](https://opensource.com/sites/default/files/2023-02/final.webp)

(Keyur Paralkar, CC BY-SA 4.0)

## CPU utilization trend

You can use a Chart widget to display the CPU utilization as a trend line, and have it automatically update over time.

First, click the widget, find the Chart Type property on the right, and change it to LINE CHART. To see a trend line, store `cpu_percent`

in an array of data points. Your API currently returns this as a single data point in time, so use Appsmith’s `storeValue`

function (an Appsmith-native implementation of a browser’s `setItem`

method) to get an array.

Click the **+** button next to **QUERIES/JS** and name it **utils**.

Paste this Javascript code into the **Code** field:

```
``````
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", []);
}
}
```


To initialize the `Store`

, you’ve created a JavaScript function in the object called `initialOnPageLoad`

, and you’ve housed the `storeValue`

function in it.

You store the values from `cpu_util_data`

into the `storeValue`

function using `storeValue("cpu_util_data", []);`

. This function runs on page load.

So far, the code stores one data point from `cpu_util_data`

in the `Store`

each time the page is refreshed. To store an array, you use the `x`

and `y`

subscripted variables, both storing values from the `cpu_percent`

data attribute.

You also want this data stored automatically by a set interval between stored values. When the function [setInterval](https://docs.appsmith.com/reference/appsmith-framework/widget-actions/intervals-time-events#setinterval) is executed:

- The value stored in
`cpu_util_data`

is fetched. - The API
`PiData`

is called. `cpu_util_data`

is updated as`x`

and`y`

variables with the latest`cpu_percent`

data returned.- The value of
`cpu_util_data`

is stored in the key`utilData`

. - Steps 1 through 4 are repeated if and only if the function is set to auto-execute. You set it to auto-execute with the Switch widget, which explains why there is a
`getLiveData`

parent function.

Navigate to the **Settings** tab to find all the parent functions in the object and set `initialOnPageLoad`

to **Yes** in the **RUN ON PAGE LOAD** option.

![Set the function to execute on page load](https://opensource.com/sites/default/files/2023-02/load-on-page.webp)

(Keyur Paralkar, CC BY-SA 4.0)

Now refresh the page for confirmation

Return to the canvas. Click the Chart widget and locate the Chart Data property. Paste the binding `{{ appsmith.store.disk_util_data }}`

into it. This gets your chart if you run the object `utils`

yourself a few times. To run this automatically:

- Find and click the
**Live Data Switch**widget in your dashboard’s title. - Look for the
`onChange`

event. - Bind it to
`{{ utils.getLiveData() }}`

. The Javascript object is`utils`

, and`getLiveData`

is the function that activates when you toggle the Switch on, which fetches live data from your Raspberry Pi. But there’s other live data, too, so the same switch works for them. Read on to see how.

## Bind all the data

Binding data to the widgets in the Memory and Disk sections is similar to how you did it for the CPU Stats section.

For Memory, bindings change to:

`{{( PiData.data.cpu_mem_avail/1000000000).toPrecision(2) \* 100 ?? 0 }}`

for the Progress Bar.`{{ \${(PiData.data.cpu_mem_used/1000000000).toPrecision(2)} ?? 0 }} GB`

,`{{ \${(PiData.data.cpu_mem_free/1000000000).toPrecision(2)} ?? 0}} GB`

, and`{{ \${(PiData.data.cpu_mem_total/1000000000).toPrecision(2)} ?? 0 }} GB`

for the three Stat Box widgets.

For Disk, bindings on the Progress Bar, and Stat Box widgets change respectively to:

`{{ 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`

and`{{ \${(PiData.data.disk_usage_total/1000000000).toPrecision(2)} ?? 0 }} GB`

for the three Stat Box widgets.

The Chart here needs updating the `utils`

object you created for CPU Stats with a `storeValue`

key called `disk_util_data`

nested under `getLiveData`

that follows the same logic as `cpu_util_data`

. For the disk utilization chart, we store disk_util_data that follows the same logic as that of the CPU utilization trend chart.

```
``````
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", []);
}
}
```


Visualizing the flow of data triggered by the Switch toggling live data on and off with the `utils`

Javascript object looks like this:

![Toggling](https://opensource.com/sites/default/files/2023-02/toggle.gif)

(Keyur Paralkar, CC BY-SA 4.0)

Toggled on, the charts change like this:

![Live data display](https://opensource.com/sites/default/files/2023-02/final.gif)

(Keyur Paralkar, CC BY-SA 4.0)


Pretty, minimalistic, and totally useful.

## Enjoy

As you get more comfortable with `psutils`

, Javascript, and Appsmith, I think you’ll find you can tweak your dashboard easily and endlessly to do really cool things like:

- See trends from the previous week, month, quarter, year, or any custom range that your RPi data allows
- Build an alert bot for threshold breaches on any stat
- Monitor other devices connected to your Raspberry Pi
- Extend
`psutils`

to another computer with Python installed - Monitor your home or office network using another library
- Monitor your garden
- Track your own life habits

Until the next awesome build, happy hacking!

## Comments are closed.