Raspberry Pi Pico W: начало работы с MQTT (MicroPython)
Это полное руководство по использованию MQTT с Raspberry Pi Pico, программируемым на MicroPython. MQTT — это протокол связи, широко используемый в системах домашней автоматизации и IoT-приложениях для соединения множества устройств. В этом руководстве вы узнаете, как выбрать и настроить MQTT-брокер, а также как публиковать и подписываться на MQTT-сообщения с помощью Raspberry Pi Pico.
Впервые работаете с Raspberry Pi Pico? Начните с руководства по началу работы с Raspberry Pi Pico.
Содержание:
В этом руководстве мы рассмотрим следующие темы:
Предварительные требования
Прежде чем продолжить, убедитесь, что выполнены следующие предварительные требования:
Прошивка MicroPython
Для выполнения этого руководства вам необходимо, чтобы прошивка MicroPython была установлена на вашей плате Raspberry Pi Pico. Вам также нужна IDE для написания и загрузки кода на плату.
Рекомендуемая IDE для MicroPython на Raspberry Pi Pico — Thonny IDE. Следуйте приведённому ниже руководству, чтобы узнать, как установить Thonny IDE, прошить прошивку MicroPython и загрузить код на плату.
Необходимые компоненты
Для выполнения примеров из этого руководства вам понадобятся следующие компоненты:
Raspberry Pi Pico W
BME280
Макетная плата
Соединительные провода
Введение в MQTT
Уже знакомы с MQTT? Перейдите к следующему разделу.
MQTT расшифровывается как Message Queuing Telemetry Transport. MQTT — это простой протокол обмена сообщениями, разработанный для устройств с ограниченными ресурсами и низкой пропускной способностью. Поэтому это идеальное решение для обмена данными между несколькими IoT-устройствами. MQTT-коммуникация работает по системе публикации и подписки. Устройства могут публиковать сообщения по определённому топику. Все устройства, которые подписаны на этот топик, получают сообщение.
Основные области применения включают отправку сообщений для управления выходами, чтение и публикацию данных с сенсорных узлов и многое другое.
Основные концепции MQTT
В MQTT есть несколько базовых концепций, которые вам необходимо понять:
Публикация/Подписка (Publish/Subscribe)
Сообщения (Messages)
Топики (Topics)
Брокер (Broker)
Публикация/Подписка
Первая концепция — это система публикации и подписки. В системе публикации и подписки устройство может публиковать сообщение по определённому топику или быть подписанным на определённый топик для получения сообщений.
Например, Устройство 1 публикует сообщение в топик;
Устройство 2 подписано на тот же топик, в который публикует Устройство 1;
Таким образом, Устройство 2 получает сообщение.
Сообщения MQTT
Сообщения — это информация, которой вы хотите обмениваться между устройствами. Это может быть сообщение, например команда для управления выходом, или данные, такие как показания датчиков.
Топики
Ещё одна важная концепция — это топики. Топики — это способ, с помощью которого вы регистрируете интерес к входящим сообщениям или указываете, куда хотите опубликовать сообщение.
Топики представлены строками, разделёнными прямой косой чертой. Каждая прямая косая черта указывает на уровень топика. Вот пример того, как можно создать топик для лампы в вашем домашнем офисе:
Примечание: топики чувствительны к регистру, что делает следующие топики различными.
Если вы хотите включить лампу в вашем домашнем офисе с помощью MQTT, вы можете представить следующий сценарий:
Устройство публикует сообщения «on» и «off» в топик home/office/lamp.
У вас есть устройство, которое управляет лампой (это может быть ваш Raspberry Pi Pico или любая другая плата или устройство). Pico, управляющий вашей лампой, подписан на тот же топик: home/office/lamp.
Таким образом, когда новое сообщение публикуется в этот топик, Pico получает сообщение «on» или «off» и включает или выключает лампу.
Устройство, которое публикует сообщения, может быть другой платой микроконтроллера или платформой управления домашней автоматизацией с поддержкой MQTT, такой как Node-RED, Home Assistant, Adafruit IO, Domoticz или OpenHAB, например.
Брокер
Наконец, ещё одна важная концепция — это брокер.
MQTT-брокер отвечает за получение всех сообщений, фильтрацию сообщений, определение того, кому они интересны, и затем публикацию сообщения всем подписанным клиентам.
Существует несколько брокеров, которые вы можете использовать. Например:
Облачные MQTT-брокеры: вы можете использовать коммерческие облачные MQTT-брокеры, например HiveMQ. Вам не нужно ничего настраивать. Достаточно создать учётную запись, и вы готовы к работе (именно этот вариант мы будем использовать в данном руководстве).
Локальный MQTT-брокер: вы можете установить MQTT-брокер локально на своём компьютере или на Raspberry Pi. MQTT-брокер Mosquitto, развёрнутый на Raspberry Pi, широко используется во многих любительских проектах и является решением, которое мы используем чаще всего.
Облачный MQTT-брокер: в качестве альтернативы предыдущему варианту вы также можете установить MQTT-брокер на собственном облачном сервере.
Подведём итог:
MQTT — это протокол связи, очень полезный в проектах Интернета вещей;
В MQTT устройства могут публиковать сообщения по определённым топикам и подписываться на топики для получения сообщений;
При использовании MQTT вам необходим брокер. Он получает все сообщения и отправляет их подписанным устройствам.
Настройка MQTT-брокера
Для использования MQTT вам нужен MQTT-брокер. Брокер получает все MQTT-сообщения и отправляет их всем подписанным клиентам.
Решения для MQTT-брокера
Существует множество решений для MQTT-брокеров, которые вы можете использовать. Здесь мы опишем те, с которыми мы знакомы лучше всего:
Mosquitto MQTT-брокер, установленный на Raspberry Pi: это MQTT-брокер с открытым исходным кодом, который вы можете установить локально на свой Raspberry Pi (компьютер Raspberry Pi, а не плату Pico). Мы часто используем этот вариант, и он всегда хорошо работал для нас.
Mosquitto MQTT-брокер, установленный на облачном сервере: отличная альтернатива, если вы хотите, чтобы ваш брокер был доступен по всему миру.
HiveMQ Broker: это облачный MQTT-брокер. Вам нужно только создать учётную запись и выбрать тарифный план. Они предоставляют бесплатный план, который подходит для большинства любительских IoT-проектов.
Для простоты в этом руководстве мы будем использовать HiveMQ, потому что вам не нужно ничего устанавливать или настраивать, как в случае с MQTT-брокером Mosquitto. Вам нужно только создать учётную запись, настроить кластер, и вы готовы к работе. В качестве альтернативы, если вы хотите использовать брокер Mosquitto или любой другой брокер по вашему выбору, не беспокойтесь. Код будет совместим с любым брокером, если вы укажете правильные данные брокера.
Независимо от того, какой MQTT-брокер вы используете, вам нужно иметь URL MQTT, имя пользователя и пароль перед переходом к следующим разделам.
Настройка MQTT-брокера HiveMQ
В этом разделе мы покажем вам, как настроить MQTT-брокер HiveMQ.
1) Сначала вам нужно создать учётную запись. Перейдите на hivemq.com и нажмите Start free.
2) Выберите тарифный план HiveMQ Cloud.
3) Войдите в систему или создайте новую учётную запись и заполните данные для завершения профиля.
4) По умолчанию у вас должен быть создан новый кластер. Нажмите Manage Cluster.
5) Скопируйте URL кластера в безопасное место, потому что он понадобится вам позже.
6) Нажмите на вкладку Access Management вверху.
7) Заполните форму именем пользователя и паролем. Вам нужно будет запомнить эти данные, чтобы позже подключиться к MQTT-брокеру. Установите разрешение на Publish and Subscribe.
8) Наконец, нажмите Create Credential.
Если ваши учётные данные успешно созданы, ваш MQTT-брокер настроен.
Убедитесь, что у вас есть следующая информация перед переходом к следующему разделу:
MQTT-сервер:
URL кластера (для HiveMQ)
IP-адрес или URL MQTT-брокера (если вы используете другой MQTT-брокер)
Имя пользователя MQTT
Пароль MQTT
Установка MQTT-модулей MicroPython
Для написания кода на MicroPython для использования протокола MQTT мы будем использовать два MQTT-модуля: umqtt.simple.py и umqtt.robust.py.
Следуйте приведённым ниже шагам, чтобы загрузить модули на ваш Raspberry Pi Pico.
Подключив Raspberry Pi Pico к компьютеру и установив соединение с Thonny IDE, перейдите в View > Files.
На боковой панели появятся все файлы в файловой системе Raspberry Pi Pico.
Щёлкните правой кнопкой мыши на боковой панели Raspberry Pi Pico и нажмите New directory…
Эта новая директория должна называться umqtt. Нажмите Ok.
Новая директория появится на левой боковой панели.
Щёлкните правой кнопкой мыши на папке umqtt и выберите New file…
Этот новый файл должен называться simple.py.
Скопируйте код simple.py в этот новый файл. Код можно найти по ссылке ниже:
# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.simple
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(
self,
client_id,
server,
port=0,
user=None,
password=None,
keepalive=0,
ssl=False,
ssl_params={},
):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False
def _send_str(self, s):
self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)
def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7F) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f
def set_last_will(self, topic, msg, retain=False, qos=0):
assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
def connect(self, clean_session=True):
self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ssl
self.sock = ssl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5
i = 1
while sz > 0x7F:
premsg[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
premsg[i] = sz
self.sock.write(premsg, i + 2)
self.sock.write(msg)
# print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1
def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7F:
pkt[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
# print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
# print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
# print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xF0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0
return op
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()
После копирования кода в файл simple.py сохраните код.
Теперь, если вы развернёте папку umqtt, вы увидите, что файл simple.py находится там.
Снова щёлкните правой кнопкой мыши на папке umqtt и создайте ещё один файл, нажав New file…
Этот новый файл должен называться robust.py.
Скопируйте код robust.py в этот новый файл. Код можно найти по ссылке ниже:
# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.robust
import utime
from . import simple
class MQTTClient(simple.MQTTClient):
DELAY = 2
DEBUG = False
def delay(self, i):
utime.sleep(self.DELAY)
def log(self, in_reconnect, e):
if self.DEBUG:
if in_reconnect:
print("mqtt reconnect: %r" % e)
else:
print("mqtt: %r" % e)
def reconnect(self):
i = 0
while 1:
try:
return super().connect(False)
except OSError as e:
self.log(True, e)
i += 1
self.delay(i)
def publish(self, topic, msg, retain=False, qos=0):
while 1:
try:
return super().publish(topic, msg, retain, qos)
except OSError as e:
self.log(False, e)
self.reconnect()
def wait_msg(self):
while 1:
try:
return super().wait_msg()
except OSError as e:
self.log(False, e)
self.reconnect()
def check_msg(self, attempts=2):
while attempts:
self.sock.setblocking(False)
try:
return super().wait_msg()
except OSError as e:
self.log(False, e)
self.reconnect()
attempts -= 1
После копирования кода в файл robust.py сохраните код. На данный момент у вас должна быть папка umqtt с файлами simple.py и robust.py внутри.
Модули, необходимые для MQTT, были успешно загружены на Raspberry Pi Pico.
Создание файла конфигурации
Мы создадим файл конфигурации для сохранения SSID, пароля и данных вашего MQTT-брокера: URL, имени пользователя и пароля.
Создайте новый файл с именем config.py в Thonny IDE и скопируйте следующий код:
wifi_ssid = 'REPLACE_WITH_YOUR_SSID'
wifi_password = 'REPLACE_WITH_YOUR_PASSWORD'
mqtt_server = b'MQTT_BROKER_URL'
mqtt_username = b'BROKER_USERNAME'
mqtt_password = b'BROKER_PASSWORD'
Замените переменные своими собственными данными.
Если вы используете локальный MQTT-брокер Mosquitto, вам следует указать IP-адрес брокера без порта. Например:
mqtt_server = b'192.168.1.79'
Затем перейдите в File > Save as… и выберите Raspberry Pi Pico. Сохраните файл как config.py (перезаписав любые существующие файлы с таким же именем). Этот файл должен быть сохранён в корне Raspberry Pi Pico, а не внутри папки umqtt.
Публикация MQTT-сообщений
В этом примере вы узнаете, как публиковать MQTT-сообщения по определённому топику с помощью вашего Raspberry Pi Pico. В качестве примера мы будем публиковать показания температуры, влажности и давления с датчика BME280. В качестве альтернативы вы можете использовать любой другой датчик или случайные значения для тестирования проекта и концепций.
Перед тем как продолжить, убедитесь, что:
Вы подключили датчик BME280 к Raspberry Pi Pico. Используйте GPIO 4 (SDA) и GPIO 5 (SCL);
Вы должны загрузить модуль BME280.py для управления BME280 с вашего Raspberry Pi Pico — ознакомьтесь с этим руководством и установите библиотеку, как указано там.
Связанный контент: Raspberry Pi Pico: BME280 — получение температуры, влажности и давления (MicroPython)
Следующий код получает данные с датчика BME280 и публикует показания по различным MQTT-топикам.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-mqtt-micropython/
from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
import BME280
# Constants for MQTT Topics
MQTT_TOPIC_TEMPERATURE = 'pico/temperature'
MQTT_TOPIC_PRESSURE = 'pico/pressure'
MQTT_TOPIC_HUMIDITY = 'pico/humidity'
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b"raspberrypi_picow"
MQTT_KEEPALIVE = 7200
MQTT_SSL = True # set to False if using local Mosquitto MQTT broker
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
# Initialize I2C communication
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
# Initialize BME280 sensor
bme = BME280.BME280(i2c=i2c, addr=0x76)
def get_sensor_readings():
temp = bme.temperature[:-1]
hum = bme.humidity[:-1]
pres = bme.pressure[:-3]
return temp, hum, pres
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
raise # Re-raise the exception to see the full traceback
def publish_mqtt(topic, value):
client.publish(topic, value)
print(topic)
print(value)
print("Publish Done")
try:
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
while True:
# Read sensor data
temperature, humidity, pressure = get_sensor_readings()
# Publish as MQTT payload
publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))
# Delay 10 seconds
sleep(10)
except Exception as e:
print('Error:', e)
Как работает код
Мы используем следующие MQTT-топики для публикации данных:
Для температуры — pico/temperature
Для влажности — pico/humidity
Для давления — pico/pressure
А рабочий процесс публикации данных выглядит следующим образом:
Подключить Pico к интернету;
Подключиться к MQTT-брокеру;
После подключения к брокеру мы можем непрерывно публиковать MQTT-сообщения.
Давайте рассмотрим, как работает код.
Импорт библиотек
Сначала нам нужно импортировать необходимые библиотеки. Мы импортируем Pin и I2C из модуля machine, и BME280 для взаимодействия с датчиком BME280. Модуль network для подключения к Wi-Fi и класс MQTTClient из umqtt.simple для использования MQTT-функций.
from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
import BME280
MQTT-топики
В следующих переменных мы сохраняем топики, в которые хотим публиковать наши сообщения (показания датчиков).
# Constants for MQTT Topics
MQTT_TOPIC_TEMPERATURE = 'pico/temperature'
MQTT_TOPIC_PRESSURE = 'pico/pressure'
MQTT_TOPIC_HUMIDITY = 'pico/humidity'
Данные MQTT
В следующих строках мы настраиваем параметры MQTT для подключения к нашему MQTT-брокеру. Мы импортируем URL сервера, имя пользователя и пароль из файла config.py.
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b"raspberrypi_picow"
MQTT_KEEPALIVE = 7200
MQTT_SSL = True
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
MQTT_CLIENT_ID должен быть уникальным идентификатором для идентификации MQTT-клиента. Вы можете дать ему любое имя, но оно должно быть уникальным среди MQTT-клиентов, подключённых к вашему брокеру. В нашем случае это raspberrypi_picow.
MQTT_CLIENT_ID = b"raspberrypi_picow"
Если вы используете локальный MQTT-брокер Mosquitto, вам следует установить параметр MQTT_SSL в False.
MQTT_SSL = False
Датчик BME280
В следующих строках мы инициализируем датчик BME280 и создаём функцию get_sensor_readings(), которая получает данные от BME280 и возвращает температуру, влажность и давление.
# Initialize I2C communication
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
# Initialize BME280 sensor
bme = BME280.BME280(i2c=i2c, addr=0x76)
def get_sensor_readings():
temp = bme.temperature[:-1]
hum = bme.humidity[:-1]
pres = bme.pressure[:-3]
return temp, hum, pres
Инициализация Wi-Fi
Функция initialize_wifi() подключает Raspberry Pi Pico к сети. Вам нужно инициализировать Wi-Fi для подключения к MQTT-брокеру и обмена сообщениями.
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
Подключение к MQTT
Функция connect_mqtt() подключается к MQTT-брокеру, используя данные о MQTT-брокере, которые вы настроили ранее.
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
raise # Re-raise the exception to see the full traceback
Публикация MQTT-сообщений
Функция publish_mqtt() публикует сообщение в топик. Передайте в качестве аргумента топик и сообщение, которое хотите отправить.
def publish_mqtt(topic, value):
client.publish(topic, value)
print(topic)
print(value)
print("Publish Done")
Публикация показаний датчиков
Теперь, когда у нас определены все функции и переменные, мы можем наконец подключиться к интернету и к брокеру, чтобы начать публиковать сообщения.
Сначала мы пытаемся подключиться к Wi-Fi, используя SSID и пароль, хранящиеся в файле config.py.
try:
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
Если подключение к Wi-Fi прошло успешно, мы можем подключиться к MQTT-брокеру.
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
После подключения мы получаем новые данные датчика и сохраняем их в переменных temperature, humidity и pressure.
# Read sensor data
temperature, humidity, pressure = get_sensor_readings()
Наконец, мы используем функцию publish_mqtt() для публикации показаний в их конкретные топики. Сообщение должно быть строкой. Поэтому нам нужно преобразовать данные датчика с помощью функции str().
# Publish as MQTT payload
publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))
Мы публикуем новые показания каждые 10 секунд.
sleep(10)
Тестирование кода
Запустите предыдущий код на вашем Raspberry Pi Pico. Он подключится к интернету и начнёт публиковать сообщения каждые 10 секунд.
Теперь мы можем проверить, можем ли мы получать сообщения на MQTT-клиенте, подписанном на эти топики. HiveMQ предоставляет веб-клиент, который позволяет подписываться и публиковать сообщения в топики для тестирования.
Перейдите в ваш кластер HiveMQ и нажмите на вкладку Web Client. Введите имя пользователя и пароль вашего MQTT-брокера и нажмите Connect Client.
Подпишитесь на топики, в которые публикует Raspberry Pi Pico. Введите pico/temperature и затем нажмите +Subscribe.
Повторите процесс для pico/humidity и pico/pressure.
После подписки на эти топики прокрутите страницу вниз. Вы должны начать получать MQTT-сообщения от Raspberry Pi Pico.
Вот и всё. Вы успешно опубликовали MQTT-сообщения с помощью Raspberry Pi Pico. Теперь вы можете использовать любой другой MQTT-клиент для подписки на эти сообщения и получения данных. Например, иметь ноды Node-RED или виджеты Adafruit IO, подписанные на MQTT-топики и отображающие данные на графиках и индикаторах.
Вы также можете подключить к этим топикам любой другой микроконтроллер для получения данных — это может быть другой Raspberry Pi Pico, ESP32, ESP8266 или другая плата.
Подписка на MQTT-топики
Чтобы показать вам, как подписаться на MQTT-топики с помощью Raspberry Pi Pico, мы создадим простой пример, в котором Pico подписан на топик pico/led. Затем, с помощью веб-клиента HiveMQ, мы будем публиковать сообщения ON и OFF в этот топик. Pico будет получать сообщения и управлять светодиодом соответственно.
Вот рабочий процесс подписки на MQTT-топики:
Подключить Raspberry Pi Pico к интернету;
Подключиться к MQTT-брокеру;
Подписаться на MQTT-топик;
Создать и назначить функцию обратного вызова (callback), которая будет выполняться при получении сообщения;
Создать цикл, который постоянно проверяет наличие новых MQTT-сообщений.
Следующий код подписывается на топик pico/led и управляет светодиодом в соответствии с полученным сообщением.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-mqtt-micropython/
from machine import Pin
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
# Define LED
led = Pin('LED', Pin.OUT)
# Constants for MQTT Topics
MQTT_TOPIC_LED = 'pico/led'
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b'raspberrypi_picow'
MQTT_KEEPALIVE = 7200
MQTT_SSL = True # set to False if using local Mosquitto MQTT broker
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
# Init Wi-Fi Interface
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
# Connect to MQTT Broker
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
# Subcribe to MQTT topics
def subscribe(client, topic):
client.subscribe(topic)
print('Subscribe to topic:', topic)
# Callback function that runs when you receive a message on subscribed topic
def my_callback(topic, message):
# Perform desired actions based on the subscribed topic and response
print('Received message on topic:', topic)
print('Response:', message)
# Check the content of the received message
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
else:
print('Unknown command')
try:
# Initialize Wi-Fi
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
client.set_callback(my_callback)
subscribe(client, MQTT_TOPIC_LED)
# Continuously checking for messages
while True:
sleep(5)
client.check_msg()
print('Loop running')
except Exception as e:
print('Error:', e)
Давайте кратко рассмотрим соответствующие разделы кода для этого примера.
Если вы используете локальный MQTT-брокер Mosquitto, вам следует установить параметр MQTT_SSL в False.
MQTT_SSL = False
Подписка на MQTT-топики
Мы создаём функцию subscribe(), которая принимает в качестве аргументов MQTT-клиент и топик, на который мы хотим подписаться.
def subscribe(client, topic):
client.subscribe(topic)
print('Subscribe to topic:', topic)
Функция обратного вызова (Callback)
Нам нужно создать функцию обратного вызова (callback), которая будет выполняться при получении нового сообщения в топике, на который мы подписаны. Аргументы topic и message автоматически передаются в функцию при её вызове.
def my_callback(topic, message):
# Perform desired actions based on the subscribed topic and response
print('Received message on topic:', topic)
print('Response:', message)
# Check the content of the received message
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
else:
print('Unknown command')
В этой функции мы проверяем содержимое сообщения. Если это ON, мы включим встроенный светодиод Raspberry Pi Pico.
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
Если сообщение — OFF, светодиод будет выключен.
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
Если мы получим какие-либо другие сообщения, мы выведем «Unknown command».
else:
print('Unknown command')
Подключение к Wi-Fi, MQTT-брокеру и проверка сообщений
Чтобы подписаться на MQTT-брокер и постоянно проверять входящие сообщения, сначала нам нужно подключиться к интернету.
Следующие строки пытаются подключиться к интернету:
try:
# Initialize Wi-Fi
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
Если подключение прошло успешно, мы также подключаемся к MQTT-брокеру.
client = connect_mqtt()
Затем назначаем функцию обратного вызова с помощью set_callback() и передаём в качестве аргумента созданную ранее функцию обратного вызова my_callback.
client.set_callback(my_callback)
Наконец, мы можем подписаться на MQTT-топики. В данном случае мы подписываемся только на MQTT_TOPIC_LED, но вы можете подписаться на несколько топиков.
subscribe(client, MQTT_TOPIC_LED)
Затем создаём цикл while для постоянной проверки входящих сообщений с помощью метода check_msg().
while True:
sleep(5)
client.check_msg()
print('Loop running')
Вы также можете добавить другие задачи в цикл. Мы проверяем наличие новых сообщений каждые пять секунд, но вы можете использовать меньшую или большую задержку в зависимости от того, как часто вы ожидаете получать сообщения.
Тестирование кода
Запустите предыдущий код на вашем Raspberry Pi Pico. Он подключится к интернету и подпишется на MQTT-топик.
Теперь давайте опубликуем несколько сообщений в топик pico/led для управления светодиодом с помощью веб-клиента HiveMQ.
Перейдите в веб-клиент вашего кластера HiveMQ. Введите имя пользователя и пароль вашего MQTT-брокера и нажмите Connect Client.
Прокрутите страницу вниз до раздела Publish Message.
Введите pico/led в поле Topic Name и введите ON в поле Message.
Наконец, нажмите кнопку Publish.
Ваш Raspberry Pi Pico получит сообщение и включит встроенный светодиод.
Вернитесь в клиент HiveMQ и отправьте сообщение OFF.
Raspberry Pi Pico получит сообщение и выключит светодиод.
Вот и всё. Вы успешно подписались на MQTT-топик и выполнили различные задачи в соответствии с полученным сообщением. Теперь вместо веб-клиента HiveMQ вы можете использовать любую платформу домашней автоматизации или IoT с поддержкой MQTT, которая позволяет создать веб-интерфейс с кнопками или переключателями для отправки MQTT-сообщений.
Заключение
В этом руководстве вы изучили все основные концепции для начала использования MQTT с Raspberry Pi Pico. Мы настроили MQTT-брокер и опубликовали и подписались на MQTT-топики с помощью Pico.
Надеемся, что это руководство оказалось для вас полезным.