将传感器数据从 Raspberry Pi Pico 发送到 MQTT

Raspberry Pi 上的 MQTT(第 3 部分):将传感器数据从 Raspberry Pi Pico 发送到 HiveMQ Cloud 并在 JavaFX 仪表板上显示

本博客系列的第二篇文章中,我们在 Raspberry Pi 迷你计算机上使用 Java 将传感器数据发送到 HiveMQ Cloud,并在仪表板上将其可视化。在本系列的第三篇博客文章中,我将与 Raspberry Pi 家族的另一个成员 Raspberry Pi Pico 一起向消息传递系统添加更多数据。

树莓派Pico简介

2021 年 1 月,推出 Raspberry Pi Pico。这是一款全新类型的开发板,因为它不是完整的 Linux PC,而是由 Raspberry Pi 自己开发的微控制器芯片(RP2040),位于一块小型多功能板上。该 RP2040 具有双核 Arm Cortex-M0+ 处理器,内存为 264KB内部 RAM 并支持高达 16MB 的片外闪存,并结合各种 GPIO(支持 I2C、SPI 和可编程 I/O (PIO))。因此,它可与 Arduino 或类似的微控制器板相媲美。不过这款Pico最大的惊喜是:售价仅为4$!

Raspberry Pi 基金会确保在该板推出时提供非常广泛的文档站点。可以使用 C/C++ 和 MicroPython SDK 完成编程。

Pico 提供了大量 GPIO,通过接地连接将它们很好地分组。这些接地甚至在电路板上具有不同的形状(无圆角),以便更轻松地找到您想要使用的正确引脚。

Pico

在这篇文章中,我们将使用 WiFi 模块和一个距离传感器扩展 Pico,作为示例,您可以如何轻松地将传感器数据从这款廉价的板发送到 HiveMQ Cloud。为了实现如此低的价格,Pico 不包含无线功能。幸运的是,可以通过多种方式向 Pico 添加 WiFi,其中Adafruit AirLift ESP32 WiFi 协处理器分线板可能是最简单、最便宜的,价格为 9.95 美元。Adafruit 产品的另一个优势是它们在网站上提供了大量文档。这些示例中的大多数都使用 MicroPython 的不同“风格”,称为CircuitPython ,它基于相同的 Python 实现,但更侧重于初学者、教育和入门教程。

这篇文章中的项目是 Adafruit 中不同示例的组合:

  • 连接到 MQTT 代理
  • Raspberry Pi Pico 和 CircuitPython 入门
  • 快速入门物联网 – 带 WiFi 的 Raspberry Pi Pico RP2040
  • Python 和 CircuitPython
  • 安装 Mu 编辑器

为 CircuitPython 准备 Pico

让我们开始为本教程准备 Pico。我们需要连接组件、在 Pico 上刷新 CircuitPython、添加库并上传代码。

接线

使用面包板和一些电线来创建这个小型测试装置。

Adafruit 空运 WiFi

AirLift 是 WiFi 模块,它将处理 Pico 和 HiveMQ 云之间的所有通信。我们需要 8 根面包板电线来连接两个组件。通过使用引脚 10 至 15,我们将所有 GPIO 连接集中在一侧。

Adafruit 网站上的重要说明:您必须使用 Pico 的 VSYS 引脚为 AirLift Breakout 供电

皮克 — 空运

VSYS — Vin

接地 — 接地

GP10 (SPI1 SCK) — SCK

GP11 (SPI1 TX) — MOSI

GP12 (SPI1 RX) — MISO

GP13 (SPI1 CSn) — CS

GP14 — 忙碌

GP15 — !RST

距离传感器

面包板上的第三个组件是 HC-SR04 距离传感器,与 CrowPi 中的传感器类似。这里我们需要 4 根电线,对于 GPIO,我们使用 Pico 的另一侧。

比克 — HC-SR04

VBUS——Vcc

地线—地线

GP16 — 回声

GP17 — 触发器

Pico 上的 CircuitPython

为了让我们的 Pico 支持此示例 CircuitPython 项目,我们需要加载正确的固件并添加一些库。

固件

下载需要安装在 Pico 上的固件才能将其用作 CircuitPython 设备。Raspberry Pi Pico 的此 .uf2 文件可以从Circuitpython.org/board/raspberry_pi_pico  下载

使用 USB 数据线(并非仅限充电),按住 Pico 上的 BOOTSEL 按钮,然后连接 Pico 和计算机之间的数据线。等到您看到 PC 上出现新的 USB 驱动器“RPI-RP2”时,松开 BOOTSEL 按钮。

将下载的 .uf2 文件拖或复制到“RPI-RP2”驱动器。完成后,该驱动器将在 Pico 重新启动时消失,并重新显示为名为“CIRCUITPY”的驱动器。现在您的 Pico 已准备好使用 CircuitPython 进行编程。

CircuitPython 库

为了简化组件的使用,可以在Circuitpython.org/libraries上一次性下载一整套库下载 ZIP 文件,将其解压到您的 PC 上,然后将以下列表中的目录或文件复制到“CIRCUITPY”驱动器上的目录“libs”。

  • adafruit_bus_device
  • adafruit_esp32_spi
  • adafruit_hcsr04
  • 阿达水果_io
  • adafruit_minimqtt
  • adafruit_请求

集成开发环境

可以使用任何文本编辑器或 IDE 将代码文件直接写入 Pico。Adafruit 建议使用 Mu 编辑器,因为这样可以在一个工具中编写代码并查看应用程序输出。您可以从codewith.mu下载此工具

在您的 PC 上安装该应用程序,运行它并选择模式 > CircuitPython。

代码

该应用程序的源代码可以在 GitHub 上的同一存储库中找到,您可以在其中找到前两篇文章的源代码

秘密

要将通用代码与特定 WiFi 和 HiveMQ 云凭据分开,需要使用单独的文件。使用您的登录名、密码等创建一个文件secrets.py并将其保存到 Pico,其中包含以下内容。

secrets = {
'ssid' : 'WIFI_NETWORK_NAME',
'password' : 'WIFI_PASSWORD',
'timezone' : 'Europe/Brussels',
'mqtt_username' : 'HIVEMQ_USERNAME',
'mqtt_key' : 'HIVEMQ_PASSWORD',
'broker' : 'YOUR_INSTANCE.hivemq.cloud',
'port' : 8883
}

主要代码

下面您可以找到该项目的完整代码。我试图通过添加注释和打印来解释每一步。在 Mu 中创建一个新文件,复制此代码并将其另存到 Pico 中,文件名为code.py.

import time
import board
import busio
import adafruit_hcsr04
import adafruit_requests as requests
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import adafruit_minimqtt.adafruit_minimqtt as MQTT

from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi

# Load the WiFi and HiveMQ Cloud credentials from secrets.py
try:
from secrets import secrets
except ImportError:
print("Error, secrets could not be read")
raise

# MQTT Topic to publish data from Pico to HiveMQ Cloud
topic_name = "/img/blog/distance"

# Initialize the Pico pins, WiFi module and distance sensor
esp32_cs = DigitalInOut(board.GP13)
esp32_ready = DigitalInOut(board.GP14)
esp32_reset = DigitalInOut(board.GP15)
spi = busio.SPI(board.GP10, board.GP11, board.GP12)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
hcsr04 = adafruit_hcsr04.HCSR04(trigger_pin=board.GP17, echo_pin=board.GP16)

# Handle HTTP requests
requests.set_socket(socket, esp)

# Check ESP32 status
print("Checking ESP32")
if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
print("\tESP32 found and in idle mode")
print("\tFirmware version: ", esp.firmware_version)
print("\tMAC address: ", [hex(i) for i in esp.MAC_address])

# List the detected WiFi networks
print("Discovered WiFi networks:")
for ap in esp.scan_networks():
print("\t", (str(ap["ssid"], "utf-8")), "\t\tRSSI: ", ap["rssi"])

# Connect to the configured WiFi network
print("Connecting to WiFi: ", secrets["ssid"])
while not esp.is_connected:
try:
esp.connect_AP(secrets["ssid"], secrets["password"])
except RuntimeError as e:
print("\tCould not connect to WiFi: ", e)
continue
print("\tConnected to ", str(esp.ssid, "utf-8"), "\t\tRSSI:", esp.rssi)
print("\tIP address of this board: ", esp.pretty_ip(esp.ip_address))
print("\tPing google.com: " + str(esp.ping("google.com")) + "ms")

# Configure MQTT to use the ESP32 interface
MQTT.set_socket(socket, esp)

# Configure MQTT client (uses secure connection by default)
mqtt_client = MQTT.MQTT(
broker=secrets["broker"],
port=secrets["port"],
username=secrets["mqtt_username"],
password=secrets["mqtt_key"]
)

# Define callback methods and assign them to the MQTT events
def connected(client, userdata, flags, rc):
print("\tConnected to MQTT broker: ", client.broker)

def disconnected(client, userdata, rc):
print("\tDisconnected from MQTT broker!")

def publish(mqtt_client, userdata, topic, pid):
print("\tPublished a message to: ", topic)

mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_publish = publish

# Connect to the MQTT broker
print("Connecting to MQTT broker...")
try:
mqtt_client.connect()
print("\tSucceeded")
except Exception as e:
print("\tMQTT connect failed: ", e)

# Continuously measure the distance and send the value to HiveMQ
print("Starting the distance measurement")
killed = False
while not killed:
# Measure distance
distance = 0
try:
distance = hcsr04.distance
except Exception as e:
print("Distance measurement failure\n", e)

# Send to HiveMQ Cloud
try:
json = "{\"value\": " + str(distance) + "}"
print("\tMessage for queue: " + json)
mqtt_client.publish(topic_name, json)
except Exception as e:
print("\tMQTT publish Failed, retrying\n", e)
killed = True
continue

# Sleep a second
time.sleep(1)

因为是主代码的默认文件名,所以该文件将直接执行,或者您可以在 Mu 的终端中code.py使用软重置板。CTRL+D

程序输出

在 Mu 的终端中,显示打印输出。

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Checking ESP32
ESP32 found and in idle mode
Firmware version: bytearray(b'1.2.2\x00')
MAC address: ['0x50', '0x18', '0x49', '0x95', '0xab', '0x34']
Discovered WiFi networks:
*****1 RSSI: -73
*****2 RSSI: -79
Connecting to WiFi: *****1
Connected to *****1 RSSI: -71
IP address of this board: 192.168.0.189
Ping google.com: 20ms
Connecting to MQTT broker...
Connected to MQTT broker: ***.s1.eu.hivemq.cloud
Succeeded
Starting the distance measurement
Message for queue: {"value": 106.777}
Published a message to: /img/blog/distance
Message for queue: {"value": 106.352}
Published a message to: /img/blog/distance
Message for queue: {"value": 107.202}

将数据添加到我们的 JavaFX 仪表板

通过一些小的更改,我们现在可以将 Pico 消息的数据添加到我们在上一篇文章中创建的 JavaFX 应用程序中。唯一需要修改的文件是DashboardView.java.

代码变更

首先我们添加一个新变量:

private final Tile gaucheDistancePico;

在构造函数内,我们初始化与现有图块类似的图块,并定义对 thePico 发布其距离测量的主题的订阅。

gaucheDistancePico = TileBuilder.create()
.skinType(Tile.SkinType.GAUGE)
.prefSize(TILE_WIDTH, TILE_HEIGHT)
.title("Distance Pico")
.unit("cm")
.maxValue(255)
.build();

client.toAsync().subscribeWith()
.topicFilter("/img/blog/distance")
.qos(MqttQos.AT_LEAST_ONCE)
.callback(this::handlePicoData)
.send();

需要最后一个附加方法来解析接收到的数据并更新图块:

public void handlePicoData(Mqtt5Publish message) {
var sensorData = new String(message.getPayloadAsBytes());
logger.info("Pico distance data: {}", sensorData);
try {
var sensor = mapper.readValue(sensorData, DoubleValue.class);
gaucheDistancePico.setValue(sensor.getValue());
} catch (JsonProcessingException ex) {
logger.error("Could not parse the data to JSON: {}", ex.getMessage());
}
}

扩展布局

通过这些小修改,我们现在可以在一个仪表板中看到 CrowPi 和 Pico 的数据。

一个伟大的组合:Raspberry Pi Pico 和 HiveMQ 云 MQTT 代理

Raspberry Pi Pico 是一款用途广泛、价格低廉的设备。借助附加的 Adafruit WiFi 模块,您可以轻松添加无线通信。与此同时,已经有许多基于相同 RP2040 微控制器的新板上市,其中一些甚至板载 WiFi。可以在tomshardware.com上找到很好的概述HiveMQ Cloud 允许您免费连接最多 100 个设备。这是尝试消息传递的好方法。当将其与 Java、Raspberry Pi 和电子元件结合使用时,不同应用程序和设备之间交换数据变得非常容易。

我希望这三篇文章可以帮助您开始创建自己的项目!