我如何使用 CircuitPython 和开源工具监控我的温室

使用微控制器、传感器、Python 和 MQTT 跟踪您温室的温度、湿度和环境光。
75 位读者喜欢这篇文章。

CircuitPython 提供了一种与微控制器板交互的革命性方式。本文解释了如何使用 CircuitPython 测量温室的温度、湿度和环境光,并将结果发布到 MQTT 代理,使用 CircuitPython MQTT 客户端。您可以订阅任意数量的程序到 MQTT 队列以进一步处理信息。

此项目使用一个简单的 Python 程序,该程序运行一个 Web 服务器,该服务器发布一个 Prometheus 格式的抓取端点,并将这些指标拉入 Prometheus 以进行持续监控。

关于 CircuitPython

CircuitPython 是一个由 Adafruit 创建的开源 Python 发行版,可在低成本微控制器板上运行。CircuitPython 为与 兼容的板交互提供了简单的开发体验。您可以通过在连接板时挂载的 CIRCUITPYTHON 根驱动器中创建一个 code.py 文件来在板上启动程序。CircuitPython 还提供来自您板的串行连接,其中包括一个交互式读取-评估-打印循环 (REPL) 会话,您可以使用该会话使用 Python 代码实时与您的板交互。

Adafruit 的网站提供了丰富的文档,以帮助您开始使用 CircuitPython。首先,请查阅 欢迎使用 CircuitPython 指南。这将帮助您开始使用 CircuitPython 在微控制器上运行代码并与 REPL 交互。它还记录了如何安装 Adafruit 的 CircuitPython 库和示例捆绑包,用于其销售的许多板和传感器。接下来,阅读 CircuitPython Essentials 指南,以了解有关其功能的更多信息,并链接到有关将 CircuitPython 与特定兼容板一起使用的信息。最后,与所有开源软件一样,您可以深入研究 CircuitPython 的代码,发布问题并做出贡献。

微控制器设置

微控制器系统非常简单。要跟随此演示,您将需要

  • Raspberry Pi 4: 您需要一台计算机来编程微控制器系统,这就是我使用的。
  • 兼容 CircuitPython 的微控制器: 我使用了 Adafruit FeatherS2,它内置 WiFi、环境光传感器和 Qwiic 电缆输入。
  • 微控制器 WiFi: FeatherS2 具有内置 WiFi 无线电。如果您的微控制器没有,您将需要为其找到一个 WiFi 扩展板。
  • 传感器: Feather S2 具有内置环境光传感器,所以我需要获得一个温湿度传感器。供应商提供了各种各样的传感器,包括 Adafruit、SparkFun 和 Amazon。我使用了一个 Adafruit 传感器,它带有与 Feather S2 输入兼容的 Qwiic 电缆连接。您可能必须为非从 Adafruit 购买的传感器找到兼容 CircuitPython 的 Python 库,尽管许多 SparkFun 传感器都与 Adafruit 库兼容。
  • 跳线和电缆: 为了避免使用面包板或焊接,我使用了 Adafruit Qwiic 电缆。SparkFun 还在 不同长度电缆的捆绑包中出售它们。

在将微控制器插入计算机之前,将传感器连接到微控制器。

现在,您可以使用 USB 数据线将微控制器插入计算机。

MQTT 代理

您可以使用 这些说明 在运行 Raspberry Pi OS 的 Raspberry Pi 4 上安装 Mosquitto MQTT 代理 和 Mosquitto 客户端。如果您想将 Raspberry Pi 用作长期服务器,请在您的网络上为 Raspberry Pi 4 设置静态 IP 地址。一旦 Mosquitto 代理运行,创建一个 用户/密码文件,该文件设置客户端在发布和订阅代理时要使用的身份验证参数。

您可以使用 Raspberry Pi 上的 Mosquitto 客户端测试 MQTT 代理。打开两个终端(如果您以无头模式运行,则打开 SSH 会话)

在终端 1 上,输入

mosquitto_sub -h localhost -u $user -P $pass -t "mqtt/test"

这将启动一个长时间运行的进程,该进程侦听发布到 mqtt/test 队列的消息。

在终端 2 上,输入

mosquitto_pub -h localhost -u $user -P $pass -t "mqtt/test" -m hello

这将向 mqtt/test 队列发布一条消息,该消息应显示在终端 1 的输出中。

然后,您可以终止在终端 1 上运行的 sub 命令。

Mosquitto 代理允许客户端向任何队列发布消息,即使它没有订阅者。这些消息将永远丢失,但它们不会阻止客户端发布。

启动第三个终端并订阅以下队列(您的微控制器将向其发布消息的队列)

  • greenhouse/temperature
  • greenhouse/light
  • greenhouse/humidity

编码微控制器

现在您已准备好编码您的微控制器,以将其指标发布到在 Raspberry Pi 4 上运行的 MQTT 代理。

Adafruit 提供了 关于使用 CircuitPython 库捆绑包的库将您的微控制器连接到您的 WiFi 路由器并使其将指标发布到您的 MQTT 代理的优秀文档。

将以下库(温室监控器将使用这些库)安装到 CIRCUITPYTHON/lib 目录中。这些库都可以在 Adafruit CircuitPython 库捆绑包中找到

  • adafruit_bus_device: 包含多个 .mpy 文件的 Python 包目录(.mpy 是压缩的 Python 文件,可节省微控制器上的空间)
  • adafruit_requests: 单个 .mpy 文件
  • adafruit_register: 另一个包目录
  • adafruit_minimqtt: 另一个包目录
  • adafruit_si7021: 单个 .mpy 文件,适用于温湿度传感器

安装完这些库后,将以下内容写入 CIRCUITPYTHON 目录中的 code.py

import time
import ssl
import socketpool
import wifi
import adafruit_minimqtt.adafruit_minimqtt as MQTT
import board
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn
import adafruit_si7021
 
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
	from secrets import secrets
except ImportError:
	print("WiFi secrets are kept in secrets.py, please add them there!")
	raise
 
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
### Feeds ###
light_feed = "greenhouse/light"
temp_feed = "greenhouse/temperature"
humidity_feed = "greenhouse/humidity"
 
# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connected(client, userdata, flags, rc):
	# This function will be called when the client is connected
	# successfully to the broker.
	print("Connected to MQTT!")
 
def disconnected(client, userdata, rc):
	# This method is called when the client is disconnected
	print("Disconnected from MQTT!")
 
 
def get_voltage(pin):
    	return (pin.value * 3.3) / 65536
 
# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)
 
# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
	broker=secrets["broker"],
	port=secrets["port"],
	username=secrets["aio_username"],
	password=secrets["aio_key"],
	socket_pool=pool,
	ssl_context=ssl.create_default_context(),
)
 
# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
 
# Connect the client to the MQTT broker.
print("Connecting to MQTT...")
mqtt_client.connect()
 
# Create library object using our Bus I2C port
sensor = adafruit_si7021.SI7021(board.I2C())
light_pin = AnalogIn(board.IO4)
 
while True:
	# Poll the message queue
	mqtt_client.loop()
 
	# get the current temperature
	light_val = get_voltage(light_pin)
	temp_val = ((sensor.temperature * 9)/5) + 32
	humidity_val = sensor.relative_humidity
 
	# Send a new messages
	mqtt_client.publish(light_feed, light_val)
	mqtt_client.publish(temp_feed, temp_val)
	mqtt_client.publish(humidity_feed, humidity_val)
	time.sleep(0.5)

保存您的代码。然后连接到串行监视器并观看它连接到您的 MQTT 代理。您也可以通过切换到 Raspberry Pi 4 上订阅此发布队列的终端来查看输出。

处理指标

像 MQTT 这样的发布/订阅工作流程为微控制器系统提供了许多优势。您可以拥有多个微控制器 + 传感器安装,报告关于同一系统的不同指标,或者并行报告同一指标的许多读数。您还可以拥有许多不同的进程订阅每个队列,以并行响应这些消息。甚至可能让多个不同的进程订阅同一个队列以进行不同的操作,例如当值过高时发送电子邮件或向另一个 MQTT 队列发布消息。

另一种选择是让微控制器订阅一个外部队列,该队列发送信号以告诉微控制器执行操作,例如关闭或启动新会话。最后,发布/订阅工作流程可能更适合低功耗微控制器安装(例如那些使用电池或太阳能供电的微控制器安装),因为这些设备可以以长延迟分隔的批次发送指标,并在报告之间的间隔期间关闭耗电的 WiFi 无线电。

为了处理这些指标,我创建了一个 Python 客户端,该客户端使用 Paho Python MQTT 客户端 来订阅指标队列。我还使用了官方的 Prometheus Python 客户端 来创建一个 Web 服务器,该服务器生成一个 Prometheus 兼容的抓取端点,其中这些指标作为仪表。我在同一台 Raspberry Pi 4 上运行它、Prometheus 服务器和 Mosquitto MQTT 代理。

from prometheus_client import start_http_server, Gauge
import random
import time
import paho.mqtt.client as mqtt

gauge = {
  "greenhouse/light": Gauge('light','light in lumens'),
  "greenhouse/temperature": Gauge('temperature', 'temperature in fahrenheit'),
  "greenhouse/humidity": Gauge('humidity','relative % humidity')
}

try:
	from mqtt_secrets import mqtt_secrets
except ImportError:
	print("WiFi secrets are kept in secrets.py, please add them there!")
	raise

def on_connect(client, userdata, flags, rc):
	print("Connected with result code "+str(rc))
	# Subscribing in on_connect() means that if we lose the connection and
	# reconnect then subscriptions will be renewed.
	client.subscribe("greenhouse/light")
	client.subscribe('greenhouse/temperature')
	client.subscribe('greenhouse/humidity')

def on_message(client, userdata, msg):
	topic = msg.topic
	payload = msg.payload
	gauge[topic].set(payload)

client = mqtt.Client()
client.username_pw_set(mqtt_secrets["mqtt_user"],mqtt_secrets['mqtt_password'])
client.on_connect = on_connect
client.on_message = on_message
client.connect('localhost',1883,60)

if __name__ == '__main__':
	# Start up the server to expose the metrics.

	client = mqtt.Client()
	client.username_pw_set('london','abc123')
	client.on_connect = on_connect
	client.on_message = on_message
	client.connect('localhost',1883,60)

	start_http_server(8000)
	client.loop_forever()

然后我配置 Prometheus 服务器以抓取 localhost:8000 上的该端点。

您可以在我的 MIT 许可的 Greenhouse MQTT Microcontroller GitHub 存储库中访问此项目的所有代码。

接下来阅读什么
User profile image.
我的主要经验是使用编程为研究人员在进行研究工作时遇到的问题提供工业强度解决方案。

评论已关闭。

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