使用 Raspberry Pi 和 Prometheus 监控家庭温度和湿度

在 Raspberry Pi 上使用 Python 仪表化 Prometheus 应用程序以收集温度传感器数据。
93 位读者喜欢这篇文章。
Working from home at a laptop

Opensource.com

数据是美丽的。作为一名#CitizenScientist(公民科学家),我喜欢收集数据并尝试理解我周围的世界。在工作中,我们使用 Prometheus 来收集我们集群的指标数据,而在家里,我使用 Prometheus 来收集我的爱好的数据。本文探讨了如何获取一个应用程序(一个 Python 脚本,用于从传感器收集温度和湿度数据),并对其进行仪表化,以在 Prometheus 可以收集的模型中提供数据。我还将创建一个 systemd 服务来启动和管理该应用程序。

什么是 Prometheus?

Prometheus 是一个开源的监控和警报系统,它收集指标并提供强大的查询语言来探索数据。我写过关于在本地设置 Prometheus的文章。 Prometheus 经常被用于从容器编排集群(例如 KubernetesOpenShift)收集数据。

在我作为 Red Hat 的 OpenShift Dedicated 集群的站点可靠性工程师的工作中,Prometheus 是我们所有集群、operators 和应用程序的强大监控和警报系统的核心。 它被大型企业组织大规模使用,但它同样适用于家庭,可以为业余爱好者项目收集数据。

在我之前关于使用 Raspberry Pi Zero 和 DHT22 收集温度和湿度数据的文章中,我展示了如何编写一个 Python 脚本来收集数据并将其打印到屏幕上。 这对于手动检查每一刻的数据很有用,但是对于我来说,收集和存储数据以进行历史查看会更有用。 这正是 Prometheus 作为具有自己查询语言和图形功能的时间序列数据库的优势所在。

为 Prometheus 仪表化应用程序

简而言之,为 Prometheus 仪表化应用程序需要从传感器获取数据、标记它,并通过 HTTP 以文本形式提供它,以便 Prometheus 可以找到并存储数据。 Prometheus 将以指定的间隔检查这些文本页面或“targets”(目标),以查找数据更新。 因此,应用程序需要随着接收到新的传感器数据而更新目标指标。

为 Prometheus 公开的数据格式包含一个键(一个指标名称,即正在测量的内容)和一个用空格分隔的值

dht22_temperature{scale="fahrenheit"} 84.01999931335449

Prometheus 还支持可选标签,以使其更容易过滤和聚合数据。 此应用程序使用标签来区分 dht22_temperature 指标的摄氏和华氏刻度。 {scale="fahrenheit"} 是上面示例中的标签。 有关更多详细信息,请查看 Prometheus 数据模型

您可以手动修改脚本以设置 Web 服务器并打印传感器数据,但是 Prometheus 提供了一个 Prometheus Python 客户端,这使得该过程变得相当容易。 您可以使用 pip Python 包管理器安装客户端。 如果您还没有 pip,请使用您的发行版的包管理器安装它,然后使用它来安装 prometheus-client。 我在我的传感器系统上运行 Raspberry Pi OS,所以我将使用 apt-get,但是请替换为您选择的包管理器

# Install pip
sudo apt-get install pip3

# Install prometheus-client
sudo pip3 install prometheus-client

接下来,您需要调整上一篇文章的传感器脚本,以将传感器数据存储为 Prometheus 计量器。 计量器是“一个指标,它表示可以任意上升和下降的单个数值”,而不是例如只能上升的计数器。 Prometheus 有许多不同的指标类型。 计量器非常适合表示温度和湿度数据。

计量器由 prometheus_client.Gauge 模块提供,因此您需要在脚本中使用计量器之前导入该模块。 因为稍后将使用 start_http_server 通过 HTTP 显示指标,所以现在也导入它

# Import Gauge and start_http_server from prometheus_client
from prometheus_client import Gauge, start_http_server

接下来,创建计量器以存储湿度和温度数据。 ['scale'] 位为温度计量器添加了“scale”标签。 然后使用标签的 celsiusfahrenheit 值初始化计量器

# Create Prometheus gauges for humidity and temperature in
# Celsius and Fahrenheit
gh = Gauge('dht22_humidity_percent',
           'Humidity percentage measured by the DHT22 Sensor')
gt = Gauge('dht22_temperature',
           'Temperature measured by the DHT22 Sensor', ['scale'])

# Initialize the labels for the temperature scale
gt.labels('celsius')
gt.labels('fahrenheit')

您可以在检查传感器时使用传感器数据设置计量器

    try:
        # Get the sensor data
        humidity, temperature = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
    except RuntimeError as e:
        log.error("RuntimeError: {}".format(e))

    if humidity is not None and temperature is not None:
        # Update the gauge with the sensor data
        gh.set(humidity)
        gt.labels('celsius').set(temperature)
        gt.labels('fahrenheit').set(celsius_to_fahrenheit(temperature))

这在 while True: 循环内完成(上面未显示;请参见下面的完整脚本),以不断使用来自传感器的数据更新计量器。

最后,Prometheus 的 start_metrics_server 将通过 HTTP 提供收集的指标。 这在 while 循环之前调用,以便服务器首先启动

    # Start the Prometheus metrics server to display the metrics data
    metrics_port = 8000
    start_http_server(metrics_port)

总而言之,该脚本应如下所示

#!/usr/bin/env python3

import logging
import time

import Adafruit_DHT

from prometheus_client import Gauge, start_http_server
from systemd.journal import JournalHandler

# Setup logging to the Systemd Journal
log = logging.getLogger('dht22_sensor')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)

# Initialize the DHT22 sensor
# Read data from GPIO4 pin on the Raspberry Pi
SENSOR = Adafruit_DHT.DHT22
SENSOR_PIN = 4

# The time in seconds between sensor reads
READ_INTERVAL = 30.0

# Create Prometheus gauges for humidity and temperature in
# Celsius and Fahrenheit
gh = Gauge('dht22_humidity_percent',
           'Humidity percentage measured by the DHT22 Sensor')
gt = Gauge('dht22_temperature',
           'Temperature measured by the DHT22 Sensor', ['scale'])

# Initialize the labels for the temperature scale
gt.labels('celsius')
gt.labels('fahrenheit')

def celsius_to_fahrenheit(degrees_celsius):
        return (degrees_celsius * 9/5) + 32

def read_sensor():
    try:
        humidity, temperature = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
    except RuntimeError as e:
        # GPIO access may require sudo permissions
        # Other RuntimeError exceptions may occur, but
        # are common.  Just try again.
        log.error("RuntimeError: {}".format(e))

    if humidity is not None and temperature is not None:
        gh.set(humidity)
        gt.labels('celsius').set(temperature)
        gt.labels('fahrenheit').set(celsius_to_fahrenheit(temperature))

        log.info("Temp:{0:0.1f}*C, Humidity: {1:0.1f}%".format(temperature, humidity))

    time.sleep(READ_INTERVAL)

if __name__ == "__main__":
    # Expose metrics
    metrics_port = 8000
    start_http_server(metrics_port)
    print("Serving sensor metrics on :{}".format(metrics_port))
    log.info("Serving sensor metrics on :{}".format(metrics_port))

    while True:
        read_sensor()

设置 systemd 单元和日志记录

该脚本已准备就绪,可以与 Prometheus 一起使用。 但是,我正在无头(即,没有监视器、键盘等)的 Raspberry Pi Zero W 上运行此程序,这些 Raspberry Pi Zero W 安装在带有 DHT22 传感器的项目框中,并安装在房屋的不同房间中。 我将添加一个 systemd 服务以在启动时自动启动脚本,并确保它持续运行。 我还将利用 systemd 日志并将来自脚本的日志数据(例如,启动或错误消息)发送到日志。

systemd 服务将是一个单独的文件,systemd 使用它,但是它需要 python3-systemd 包才能从脚本将日志发送到日志。 您可以使用 apt-get(或您的软件包管理器)安装它

# Install the python3-systemd package for Journal integration
sudo apt-get install python3-systemd

您可以在服务监视脚本中配置 Python 记录器,以使用 systemd.journal.JournalHandler 模块将日志发送到日志。 导入它之后,您可以将 JournalHandler 添加为记录器的处理程序

from systemd.journal import JournalHandler

# Setup logging to the Systemd Journal
log = logging.getLogger('dht22_sensor')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)

现在可以使用 log.info() 记录到日志。 例如

# This will send the message to the Systemd Journal,
# and show up in `systemctl status` and with `journalctl`
log.info("Serving sensor metrics on :{}".format(metrics_port))

在更新脚本以记录到 systemd 日志后,为 sensor-metrics.py 脚本创建一个 systemd 服务

# /etc/systemd/system/sensor-metrics.service
[Unit]
Description=DHT22 Sensor Metrics Service
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
ExecStart=python3 /opt/sensor-metrics/sensor-metrics.py

[Install]
WantedBy=multi-user.target

这仅告诉 systemd 在 /opt/sensor-metrics/sensor-metrics.py 中查找脚本,启动它并使其保持运行。 这将成为 sensor-metrics 服务。

sensor-metrics.py 脚本链接(或者,如果您喜欢,移动)到 /opt/sensor-metrics/sensor-metrics.py

# Create /opt/sensor-metrics and link the sensor-metrics.py script from the current directory into it
sudo mkdir /opt/sensor-metrics
sudo ln -s $(pwd)/sensor-metrics.py /opt/sensor-metrics/

sensor-metrics.service 文件链接到 /etc/systemd/system

# Link the sensor-metrics.service file into the Systemd directory
sudo ln -s $(pwd)/sensor-metrics.service /etc/systemd/system/

现在,您可以启用 sensor-metrics 服务以在启动时启动并检查状态

# Enable and start the sensor-metrics.service
sudo systemctl enable sensor-metrics.service
sudo systemctl start sensor-metrics.service

现在该服务正在运行,并设置为在启动时启动。

要了解一切是否正在运行,请使用 systemctl 检查服务状态

sudo systemctl status sensor-metrics.service

如果一切正常,您应该会看到类似以下内容

● sensor-metrics.service - DHT22 Sensor Metrics Service
   Loaded: loaded (/home/chris/sensor-metrics.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-06-30 03:33:02 BST; 8s ago
 Main PID: 4129 (python3)
    Tasks: 2 (limit: 877)
   CGroup: /system.slice/sensor-metrics.service
           └─4129 /usr/bin/python3 /opt/sensor-metrics/sensor-metrics.py

Jun 30 03:33:02 cumulo systemd[1]: Started DHT22 Sensor Metrics Service.
Jun 30 03:33:05 cumulo /opt/sensor-metrics/sensor-metrics.py[4129]: Serving sensor metrics on :8000
Jun 30 03:33:05 cumulo /opt/sensor-metrics/sensor-metrics.py[4129]: Temp:30.6*C, Humidity: 47.1%

成功!

检查指标目标

在运行该服务并修改脚本以在计量器中收集传感器数据并将其显示给 Prometheus 之后,您可以像 Prometheus 一样查看数据。

在浏览器中,导航到 http://<您的主机的 IP 地址>:8000,替换运行 sensor-metrics 服务的机器的 IP 地址。

您应该看到一个页面,其中包含有关 Python 客户端的几个指标(奖励!),以及 dht22_temperature 和 dht22_humidity 指标。 它应该看起来像这样

数据确实很美! 看看! 以两种不同的比例显示湿度温度!

每次服务脚本检查传感器数据时,数据都会更新。 现在进行最后一步:向 Prometheus 显示在哪里查找所有这些数据。

创建一个 Prometheus 抓取配置

在继续之前,我建议您阅读我之前关于在家运行 Prometheus的文章,并已经设置了一个实例。 如果您还没有这样做,请立即进行操作(并告诉您的所有朋友这是一个多么美好的体验)。 该文章展示了如何设置 Prometheus 以从文件中读取动态抓取配置并自动重新加载。 这些抓取配置将 Prometheus 指向它应摄取(即“抓取”)的指标数据目标。

将传感器指标数据的抓取配置添加到上一篇文章中设置的抓取配置 JSON 设置中的数组(如果有)。 请注意,下面的数组具有单个 Prometheus sensor-metrics 目标。 您的可能已经有其他目标。 只需添加到列表中。

// This scrape config target points to the IP Address of the Raspberry Pi and the Port used in the sensor-metrics.py script
// Substitute your own IP and the port you chose
[
  {"labels": {"job": "dht22"}, "targets": ["192.168.1.119:8000"]}
]

在重新启动 Prometheus(或等待它找到并加载新的抓取配置)之后,Prometheus 将开始在您在上面指定的目标中查找指标数据。

将所有内容整合在一起

最后,一切都运行起来了,你可以看看你收集到的数据了!打开你的 Prometheus 服务器的 Prometheus Web 界面。我的地址是 http://localhost:9090/graph,如果之前你按照文章的步骤操作,你的地址可能也是一样的。点击 "graph" 标签,搜索 dht22_temperature{scale=~"fahrenheit"} 来查看收集到的温度数据。

嗯。有点让人失望。

好的,有两件事。

  1. 时序数据一开始往往不那么吸引人,因为你还没有太多数据。随着时间的推移会变得更好。
  2. 环境温度数据需要更长的时间才能显示出有趣的东西,因为它变化不大。

所以,给它一些时间。最终,它会变得更有趣,更好。

好*得*多!

做一些#公民科学

Prometheus 在收集指标数据、将其存储为时序数据以及提供探索方法方面非常出色。我希望这篇文章能激励你在家进行一些#公民科学,创建你自己的数据并进行探索!

接下来阅读什么
Chris Collins
Chris Collins 是 Red Hat 的 SRE,也是 OpenSource.com 的通讯员,对自动化、容器编排及其周围的生态系统充满热情,并且喜欢为了好玩而在家中重现企业级技术。

评论已关闭。

Creative Commons License本作品采用知识共享署名 - 相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.