导读:使用微控制器、传感器、Python 以及 MQTT 持续追踪温室的温度、湿度以及环境光。       
本文字数:8908,阅读时长大约:10分钟
https://linux.cn/article-13504-1.html

作者:Darin London
译者:Mo
CircuitPython 提供了一种和微控制器板进行交互的革命性方式。这篇文章介绍了如何使用 CircuitPython 来监测温室的温度、湿度以及环境光,并且使用 CircuitPython MQTT 客户端将结果发布到一个 MQTT中介(broker)。你可以在若干个程序中订阅 MQTT 队列并进一步处理信息。
这个项目使用一个简单的 Python 程序来运行 Web 服务器,它发布一个 Prometheus 格式的采集端点,拉取监控指标到 Prometheus 进行不间断的监控。
关于 CircuitPython
CircuitPython 是一个由 Adafruit 创建的开源 Python 发行版,用于运行在低成本微控制器开发板上。CircuitPython 为与 兼容的开发板 的交互提供了简单的开发体验。你可以在连接你的开发板时挂载的 CIRCUITPYTHON 根驱动器上创建一个 code.py 文件来启动你的程序。CircuitPython 还为开发板提供了一个串行连接,包含一个交互式解释器(REPL)会话,你可以使用 Python 代码实时和开发板进行交互。
Adafruit 的网站提供了大量的文档,可以帮助你开始使用 CircuitPython。首先,参考下《欢迎来到 CircuitPython》指南。这份指南能够帮助你开始使用 CircuitPython 在开发板上运行代码以及和 REPL 交互。它还记录了如何安装 Adafruit 的 CircuitPython 库合集和范例,可以用在它出售的许多开发板和传感器上。接下来,阅读《CircuitPython 基础》指南来学习更多关于其功能的信息,里面还有链接指向在特定及兼容的开发板上使用 CircuitPython 的相关信息。最后,就如所有开源软件一样,你可以深入 CircuitPython 的源码,发布议题,以及做出贡献。
微控制器设置
微控制器系统非常简单。要完成这个示例项目,你会需要:
◈ 树莓派 4:你需要一台电脑来给微控制器系统编程,我用的是树莓派 4。
◈ CircuitPython 兼容的微控制器:我用的是 Adafruit Feather S2,带有内置 WiFi,环境光传感器,Qwiic 线缆输入。
◈ 微控制器 WiFi:Feather S2 内置了 WiFi。如果你的微控制器没有,你需要给开发板找个 WiFi 扩展板。
◈ 传感器:Feather S2 有个内置的环境光传感器,所以我还需要一个温湿度传感器。有很多不同厂商的产品可以选择,包括 Adafruit、SparkFun、亚马逊。我用的是一个 Adafruit 传感器,带有 Feather S2 输入兼容的 Qwiic 线缆。尽管多数 SparkFun 传感器可以在 Adafruit 库下工作,但如果你不是从 Adafruit 购买的传感器,你可能还是需要自己去找到它兼容 CircuitPython 的 Python 库。
◈ 跳线和线缆:为了避免使用面包板或焊接,我使用 Adafruit Qwiic 线缆。SparkFun 销售的包含不同长度的线缆套装中也有它。
在将微控制器连接到你的电脑之前,将传感器连接到微控制器上。
将传感器连接到微控制器上
现在你可以将微控制器用 USB 数据线连接到你的电脑。
MQTT 中介
你可以使用 这份说明 来在树莓派的系统上安装 Mosquitto MQTT 中介 和 Mosquitto 客户端。如果你想把树莓派做为长期服务器使用,在你的网络上给树莓派 4 设置一个静态 IP 地址。Mosquitto 中介运行起来之后,创建一份 用户名/密码文件,设置客户端向中介发布和订阅消息时用的认证信息。
你可以用树莓派上的 Mosquitto 客户端来测试 MQTT 中介。打开两个终端(如果你是无界面运行的话打开两个 SSH 会话):
在终端一输入:
  1. mosquitto_sub -h localhost -u $user -P $pass -t "mqtt/test"
这条命令会启动一个持续运行的进程,监听发布到 mqtt/test 队列的消息。
在终端二输入:
  1. mosquitto_pub -h localhost -u $user -P $pass -t "mqtt/test"-m hello`
这条命令会向 mqtt/test 队列发布一条消息,它应该会显示在终端一的输出里。
现在你可以中止终端一运行的 sub 命令了。
Mosquitto 中介允许客户端发布消息到任何队列,甚至没有任何订阅的队列也可以。这些消息会永久丢失,但这不会阻止客户端继续发布消息。
打开第三个终端,订阅下列队列(你的控制器会发布消息到这些队列上):
◈ greenhouse/temperature
◈ greenhouse/light
◈ greenhouse/humidity
给微控制器编码
现在你已经准备好给微控制器编码,发布它的监测指标到树莓派 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 文件中:
  1. importtime
  2. import ssl
  3. import socketpool
  4. import wifi
  5. import adafruit_minimqtt.adafruit_minimqtt as MQTT
  6. import board
  7. from digitalio importDigitalInOut,Direction,Pull
  8. from analogio importAnalogIn
  9. import adafruit_si7021
  10. #Add a secrets.py to your filesystem that has a dictionary called secrets with"ssid"and
  11. #"password" keys with your WiFi credentials. DO NOT share that fileor commit it into Gitor other
  12. # source control.
  13. # pylint: disable=no-name-in-module,wrong-import-order
  14. try:
  15. from secrets import secrets
  16. exceptImportError:
  17. print("WiFi secrets are kept in secrets.py, please add them there!")
  18. raise
  19. print("Connecting to %s"% secrets["ssid"])
  20. wifi.radio.connect(secrets["ssid"], secrets["password"])
  21. print("Connected to %s!"% secrets["ssid"])
  22. ### Feeds ###
  23. light_feed ="greenhouse/light"
  24. temp_feed ="greenhouse/temperature"
  25. humidity_feed ="greenhouse/humidity"
  26. #Define callback methods which are called when events occur
  27. # pylint: disable=unused-argument, redefined-outer-name
  28. def connected(client, userdata, flags, rc):
  29. #Thisfunction will be called when the client is connected
  30. # successfully to the broker.
  31. print("Connected to MQTT!")
  32. def disconnected(client, userdata, rc):
  33. #This method is called when the client is disconnected
  34. print("Disconnected from MQTT!")
  35. def get_voltage(pin):
  36. return(pin.value *3.3)/65536
  37. #Create a socket pool
  38. pool = socketpool.SocketPool(wifi.radio)
  39. #Set up a MiniMQTTClient
  40. mqtt_client = MQTT.MQTT(
  41.         broker=secrets["broker"],
  42.         port=secrets["port"],
  43.         username=secrets["aio_username"],
  44.         password=secrets["aio_key"],
  45.         socket_pool=pool,
  46.         ssl_context=ssl.create_default_context(),
  47. )
  48. #Setup the callback methods above
  49. mqtt_client.on_connect = connected
  50. mqtt_client.on_disconnect = disconnected
  51. #Connect the client to the MQTT broker.
  52. print("Connecting to MQTT...")
  53. mqtt_client.connect()
  54. #Create library object usingourBus I2C port
  55. sensor = adafruit_si7021.SI7021(board.I2C())
  56. light_pin =AnalogIn(board.IO4)
  57. whileTrue:
  58. #Poll the message queue
  59.         mqtt_client.loop()
  60. #get the current temperature
  61.         light_val = get_voltage(light_pin)
  62.         temp_val =((sensor.temperature *9)/5)+32
  63.         humidity_val = sensor.relative_humidity
  64. #Send a new messages
  65.         mqtt_client.publish(light_feed, light_val)
  66.         mqtt_client.publish(temp_feed, temp_val)
  67.         mqtt_client.publish(humidity_feed, humidity_val)
  68. time.sleep(0.5)
保存你的代码。然后连接到串行监视器,看程序连接到你的 MQTT 中介。你还可以将树莓派 4 上的终端切换到订阅了它的发布队列的终端来查看输出。
处理监测指标
像 MQTT 这样的发布/订阅工作流给微控制器系统提供了诸多好处。你可以有多个微控制器 + 传感器来回报同一个系统的不同指标或并行回报相同指标的若干读数。你还可以有多个不同进程订阅各个队列,并行地对这些消息进行回应。甚至还可以有多个进程订阅相同的队列,对消息做出不同的动作,比如数值过高时发送通知邮件或将消息发送到另一个 MQTT 队列上去。
另一个选项是让一个微控制器订阅一个外部队列,可以发送信号告诉微控制器做出动作,比如关闭或开始一个新会话。最后,发布/订阅工作流对低功耗微控制器系统更佳(比如那些使用电池或太阳能的系统),因为这些设备可以在更长的延迟周期后批量发布监测指标,并在回报的间隔期间关闭大量消耗电量的 WiFi 广播。
要处理这些监测指标,我创建了一个 Python 客户端,使用 Paho Python MQTT 客户端 订阅监测指标队列。我还使用官方的 Prometheus Python 客户端 创建了一个 Web 服务器,它产生一个符合 Prometheus 标准的采集端点,使用这些监测指标作为面板信息。Prometheus 服务器和 Mosquitto MQTT 中介我都是运行在同一个树莓派 4 上的。
  1. from prometheus_client import start_http_server,Gauge
  2. import random
  3. importtime
  4. import paho.mqtt.client as mqtt
  5. gauge ={
  6. "greenhouse/light":Gauge('light','light in lumens'),
  7. "greenhouse/temperature":Gauge('temperature','temperature in fahrenheit'),
  8. "greenhouse/humidity":Gauge('humidity','relative % humidity')
  9. }
  10. try:
  11. from mqtt_secrets import mqtt_secrets
  12. exceptImportError:
  13. print("WiFi secrets are kept in secrets.py, please add them there!")
  14. raise
  15. def on_connect(client, userdata, flags, rc):
  16. print("Connected with result code "+str(rc))
  17. #Subscribingin on_connect() means that if we lose the connection and
  18. # reconnect then subscriptions will be renewed.
  19.         client.subscribe("greenhouse/light")
  20.         client.subscribe('greenhouse/temperature')
  21.         client.subscribe('greenhouse/humidity')
  22. def on_message(client, userdata, msg):
  23.         topic = msg.topic
  24.         payload = msg.payload
  25.         gauge[topic].set(payload)
  26. client = mqtt.Client()
  27. client.username_pw_set(mqtt_secrets["mqtt_user"],mqtt_secrets['mqtt_password'])
  28. client.on_connect = on_connect
  29. client.on_message = on_message
  30. client.connect('localhost',1883,60)
  31. if __name__ =='__main__':
  32. #Start up the server to expose the metrics.
  33.         client = mqtt.Client()
  34.         client.username_pw_set('london','abc123')
  35.         client.on_connect = on_connect
  36.         client.on_message = on_message
  37.         client.connect('localhost',1883,60)
  38.         start_http_server(8000)
  39.         client.loop_forever()
然后我配置 Prometheus 服务器采集端点数据到 localhost:8000
你可以在 Github 上访问 温室 MQTT 微控制器 这个项目的代码,项目采用 MIT 许可证授权。

作者:Darin London 选题:lujun9972 译者:alim0x 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出
欢迎遵照 CC-BY-NC-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。
继续阅读
阅读原文