ESP32 MQTT – Публикация показаний температуры DS18B20 (Arduino IDE)
Узнайте, как публиковать показания температуры DS18B20 через MQTT с помощью ESP32 на любую платформу, поддерживающую MQTT, или в любой другой MQTT-клиент. В качестве примера мы будем публиковать показания датчика на панель Node-RED Dashboard, а ESP32 будет программироваться с помощью Arduino IDE.
Рекомендуемое чтение: Что такое MQTT и как он работает
Обзор проекта
На следующей диаграмме показан общий обзор проекта, который мы будем создавать.
ESP32 запрашивает показания температуры с датчика DS18B20. Показания публикуются в топик esp32/ds18b20/temperature;
Node-RED подписан на топик esp32/ds18b20/temperature. Таким образом, он получает показания температуры DS18B20 и отображает их на шкале/графике;
Вы можете получать показания на любой другой платформе, поддерживающей MQTT, и обрабатывать их по своему усмотрению.
Предварительные требования
Перед тем как приступить к этому руководству, убедитесь, что вы выполнили следующие предварительные условия.
Arduino IDE
Мы будем программировать ESP32 с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение ESP32.
MQTT-брокер
Для использования MQTT вам нужен брокер. Мы будем использовать брокер Mosquitto, установленный на Raspberry Pi. Прочитайте Как установить брокер Mosquitto на Raspberry Pi.
Вы можете использовать любой другой MQTT-брокер, включая облачный MQTT-брокер. Мы покажем вам, как это сделать в коде позже.
Если вы не знакомы с MQTT, обязательно прочитайте наше вводное руководство: Что такое MQTT и как он работает.
Библиотеки MQTT
Для использования MQTT с ESP32 мы будем использовать библиотеку Async MQTT Client.
Установка библиотеки Async MQTT Client
Нажмите здесь, чтобы скачать библиотеку Async MQTT client. В папке «Загрузки» должен появиться .zip файл
Распакуйте .zip файл, и вы должны получить папку async-mqtt-client-master
Переименуйте папку из async-mqtt-client-master в async_mqtt_client
Переместите папку async_mqtt_client в папку библиотек вашей установки Arduino IDE
Наконец, перезапустите Arduino IDE
Альтернативно, вы можете перейти в Sketch > Include Library > Add .ZIP library и выбрать только что скачанную библиотеку.
Установка библиотеки Async TCP
Для использования MQTT с ESP вам также нужна библиотека Async TCP.
Нажмите здесь, чтобы скачать библиотеку Async TCP client. В папке «Загрузки» должен появиться .zip файл
Распакуйте .zip файл, и вы должны получить папку AsyncTCP-master
Переименуйте папку из AsyncTCP-master в AsyncTCP
Переместите папку AsyncTCP в папку библиотек вашей установки Arduino IDE
Наконец, перезапустите Arduino IDE
Альтернативно, вы можете перейти в Sketch > Include Library > Add .ZIP library и выбрать только что скачанную библиотеку.
Библиотеки датчика температуры DS18B20
Для работы с датчиком температуры DS18B20 вам нужно установить библиотеку One Wire от Paul Stoffregen и библиотеку Dallas Temperature. Выполните следующие шаги для установки этих библиотек.
Откройте Arduino IDE и перейдите в Sketch > Include Library > Manage Libraries. Должен открыться Менеджер библиотек.
Введите «onewire» в строке поиска и установите библиотеку OneWire от Paul Stoffregen.
Затем найдите «Dallas» и установите библиотеку DallasTemperature от Miles Burton.
После установки библиотек перезапустите Arduino IDE.
Чтобы узнать больше о датчике температуры DS18B20, прочитайте наше руководство: ESP32 DS18B20 с Arduino IDE (одиночный, множественные датчики, веб-сервер).
Необходимые компоненты
Для этого проекта вам понадобятся следующие компоненты:
ESP32 (читайте Лучшие платы разработки ESP32)
Плата Raspberry Pi (читайте Лучшие стартовые наборы Raspberry Pi)
Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Схема подключения
Подключите DS18B20 к ESP32, как показано на следующей схеме: вывод данных DS18B20 подключён к GPIO 4.
Код
Скопируйте следующий код в Arduino IDE. Чтобы он работал, вам нужно вставить свои сетевые учётные данные, а также данные MQTT-брокера.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-mqtt-publish-ds18b20-temperature-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// Raspberry Pi Mosquitto MQTT Broker
#define MQTT_HOST IPAddress(192, 168, 1, XXX)
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"
#define MQTT_PORT 1883
// Temperature MQTT Topic
#define MQTT_PUB_TEMP "esp32/ds18b20/temperature"
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// Temperature value
float temp;
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void WiFiEvent(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch(event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
connectToMqtt();
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
xTimerStart(wifiReconnectTimer, 0);
break;
}
}
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
/*void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
Serial.print(" qos: ");
Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}*/
void onMqttPublish(uint16_t packetId) {
Serial.println("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void setup() {
// Start the DS18B20 sensor
sensors.begin();
Serial.begin(115200);
Serial.println();
Serial.println();
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
WiFi.onEvent(WiFiEvent);
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
//mqttClient.onSubscribe(onMqttSubscribe);
//mqttClient.onUnsubscribe(onMqttUnsubscribe);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
// If your broker requires authentication (username and password), set them below
//mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
connectToWifi();
}
void loop() {
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
// New temperature readings
sensors.requestTemperatures();
// Temperature in Celsius degrees
temp = sensors.getTempCByIndex(0);
// Temperature in Fahrenheit degrees
//temp = sensors.getTempFByIndex(0);
// Publish an MQTT message on topic esp32/ds18b20/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: ", MQTT_PUB_TEMP);
Serial.println(packetIdPub1);
Serial.printf("Message: %.2f /n", sensors.getTempCByIndex(0));
}
}
Как работает код
Следующая секция импортирует все необходимые библиотеки.
#include <WiFi.h>
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
Укажите свои сетевые учётные данные в следующих строках.
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
Вставьте IP-адрес Raspberry Pi, чтобы ESP32 подключился к вашему брокеру.
#define MQTT_HOST IPAddress(192, 168, 1, 106)
Если вы используете облачный MQTT-брокер, вставьте доменное имя брокера, например:
#define MQTT_HOST "example.com"
Определите MQTT-порт.
#define MQTT_PORT 1883
Мы будем публиковать температуру в топик esp32/ds18b20/temperature. Если вы хотите изменить топик, измените его в следующей строке.
#define MQTT_PUB_TEMP "esp32/ds18b20/temperature"
Вы можете создать дополнительные топики, если хотите.
Настройте DS18B20 в следующих строках. В нашем случае он подключён к GPIO 4. Вы можете подключить его к любому другому GPIO.
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
Переменная temp будет хранить значение температуры от датчика DS18B20.
float temp;
Создайте объект AsyncMqttClient с именем mqttClient для управления MQTT-клиентом и таймеры для переподключения к MQTT-брокеру и роутеру при потере соединения.
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
Затем создайте вспомогательные переменные таймера для публикации показаний каждые 10 секунд. Вы можете изменить время задержки в переменной interval.
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
Функции MQTT: подключение к Wi-Fi, подключение к MQTT и события Wi-Fi
Мы не добавляли комментарии к функциям, определённым в следующей секции кода. Эти функции поставляются с библиотекой Async Mqtt Client. Названия функций говорят сами за себя.
Например, функция connectToWifi() подключает ESP32 к роутеру:
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
Функция connectToMqtt() подключает ESP32 к MQTT-брокеру:
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
Функция WiFiEvent() отвечает за обработку событий Wi-Fi. Например, после успешного подключения к роутеру и MQTT-брокеру она выводит IP-адрес ESP32. С другой стороны, если соединение потеряно, она запускает таймер и пытается переподключиться.
void WiFiEvent(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch(event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
connectToMqtt();
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
xTimerStop(mqttReconnectTimer, 0);
xTimerStart(wifiReconnectTimer, 0);
break;
}
}
Функция onMqttConnect() выполняется после установления сессии с брокером.
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
Функции MQTT: отключение и публикация
Если ESP32 теряет соединение с MQTT-брокером, вызывается функция onMqttDisconnect, которая выводит сообщение в монитор порта.
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
Когда вы публикуете сообщение в MQTT-топик, вызывается функция onMqttPublish(). Она выводит идентификатор пакета в монитор порта.
void onMqttPublish(uint16_t packetId) {
Serial.println("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
По сути, все эти функции, которые мы только что упомянули, являются callback-функциями. Поэтому они выполняются асинхронно.
setup()
Теперь перейдём к setup(). Инициализируйте датчик DS18B20 и запустите последовательную связь.
sensors.begin();
Serial.begin(115200);
Следующие две строки создают таймеры, которые позволят переподключиться к MQTT-брокеру и Wi-Fi при потере соединения.
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
Следующая строка назначает callback-функцию, чтобы при подключении ESP32 к Wi-Fi выполнялась функция WiFiEvent() для вывода описанных ранее деталей.
WiFi.onEvent(WiFiEvent);
Наконец, назначьте все callback-функции. Это означает, что эти функции будут выполняться автоматически при необходимости. Например, когда ESP32 подключается к брокеру, он автоматически вызывает функцию onMqttConnect(), и так далее.
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
//mqttClient.onSubscribe(onMqttSubscribe);
//mqttClient.onUnsubscribe(onMqttUnsubscribe);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
Аутентификация брокера
Если ваш брокер требует аутентификации, раскомментируйте следующую строку и вставьте свои учётные данные (имя пользователя и пароль).
mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
Наконец, подключитесь к Wi-Fi.
connectToWifi();
loop()
В loop() вы создаёте таймер, который позволяет публиковать новые показания температуры в топик esp32/ds18b20/temperature каждые 10 секунд.
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
// New temperature readings
sensors.requestTemperatures();
// Temperature in Celsius degrees
temp = sensors.getTempCByIndex(0);
Если вы предпочитаете температуру в градусах Фаренгейта, раскомментируйте следующую строку:
//temp = sensors.getTempFByIndex(0);
Узнайте больше о датчике температуры DS18B20: ESP32 с DS18B20 руководство.
Публикация в топики
Чтобы опубликовать сообщение в MQTT-топик, используйте следующую строку:
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
Если вы хотите публиковать дополнительные показания в другие топики, вы можете продублировать эту строку в loop().
По сути, метод publish() объекта mqttClient используется для публикации данных в топик. Метод publish() принимает следующие аргументы по порядку:
MQTT-топик (const char*)
QoS (uint8_t): качество обслуживания – может быть 0, 1 или 2
retain-флаг (bool): флаг сохранения
payload (const char*): полезная нагрузка
QoS (Quality of Service) – это способ гарантировать доставку сообщения. Он может быть одного из следующих уровней:
0: сообщение будет доставлено один раз или не доставлено вовсе. Сообщение не подтверждается. Нет возможности дублирования сообщений;
1: сообщение будет доставлено как минимум один раз, но может быть доставлено более одного раза;
2: сообщение всегда доставляется ровно один раз;
Загрузка кода
С включённым Raspberry Pi и работающим MQTT-брокером Mosquitto загрузите код в ESP32.
Откройте монитор порта на скорости 115200 бод, и вы увидите, что ESP32 начинает публиковать сообщения.
Подготовка панели Node-RED Dashboard
ESP32 публикует показания температуры каждые 10 секунд в топик esp32/ds18b20/temperature. Теперь вы можете использовать любую панель, поддерживающую MQTT, или любое другое устройство с поддержкой MQTT для подписки на этот топик и получения показаний.
В качестве примера мы создадим простой поток в Node-RED для подписки на этот топик и отображения показаний на шкале или графике.
Если у вас не установлен Node-RED, следуйте этим руководствам:
После запуска Node-RED на Raspberry Pi, перейдите по IP-адресу Raspberry Pi с портом :1880.
http://raspberry-pi-ip-address:1880
Должен открыться интерфейс Node-RED. Перетащите узлы MQTT in, chart и gauge в поток.
Нажмите на узел MQTT и измените его свойства следующим образом:
Поле Server относится к MQTT-брокеру. В нашем случае MQTT-брокером является Raspberry Pi, поэтому установлено значение localhost:1883. Если вы используете облачный MQTT-брокер, вам следует изменить это поле. Введите топик, на который хотите подписаться, и QoS.
Установите следующие свойства для узла gauge.
Отредактируйте узел chart следующим образом:
Соедините узлы, как показано ниже:
Наконец, разверните поток (нажмите кнопку в правом верхнем углу).
Альтернативно, вы можете перейти в Menu > Import и скопировать следующее в Clipboard для создания потока Node-RED.
[{"id":"5a45b8da.52b0d8","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp32/ds18b20/temperature","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":380,"y":280,"wires":[["3042e15e.80a4ee","4c53cb0f.3e6084"]]},{"id":"3042e15e.80a4ee","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"2b7ac01b.fc984","order":0,"width":0,"height":0,"gtype":"gage","title":"Temperature","label":"ºC","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":650,"y":240,"wires":[]},{"id":"4c53cb0f.3e6084","type":"ui_chart","z":"b01416d3.f69f38","name":"","group":"2b7ac01b.fc984","order":1,"width":0,"height":0,"label":"Temperature","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":650,"y":320,"wires":[[]]},{"id":"8db3fac0.99dd48","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"2b7ac01b.fc984","type":"ui_group","z":"","name":"DS18B20 Temperature Sensor","tab":"99ab8dc5.f435c","disp":true,"width":"6","collapse":false},{"id":"99ab8dc5.f435c","type":"ui_tab","z":"","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
Демонстрация
Перейдите по IP-адресу Raspberry Pi с :1880/ui.
http://raspberry-pi-ip-address:1880/ui
Вы должны получить доступ к текущим показаниям датчика на панели Dashboard (шкала и график).
Вот и всё! Ваша плата ESP32 публикует показания датчика в Node-RED через MQTT.
Заключение
MQTT – это отличный протокол связи для обмена небольшими объёмами данных между устройствами. В этом руководстве вы узнали, как публиковать показания температуры DS18B20 с ESP32 в MQTT-топик. Затем вы можете использовать любое устройство или платформу домашней автоматизации для подписки на этот топик и получения показаний.
Вместо датчика температуры DS18B20 вы можете использовать любой другой датчик, а также публиковать в несколько топиков одновременно.
Надеемся, это руководство оказалось полезным. Если вы хотите узнать больше об ESP32, ознакомьтесь с нашими ресурсами:
Спасибо за чтение.
Источник: :doc:`Random Nerd Tutorials – ESP32 MQTT Publish DS18B20 Temperature Readings (Arduino IDE) <../esp32-mqtt-publish-ds18b20-temperature-arduino/index>`