ESP32 MQTT – Публикация показаний температуры DS18B20 (Arduino IDE)

Узнайте, как публиковать показания температуры DS18B20 через MQTT с помощью ESP32 на любую платформу, поддерживающую MQTT, или в любой другой MQTT-клиент. В качестве примера мы будем публиковать показания датчика на панель Node-RED Dashboard, а ESP32 будет программироваться с помощью Arduino IDE.

ESP32 MQTT публикация показаний температуры DS18B20 Arduino IDE

Рекомендуемое чтение: Что такое MQTT и как он работает

Обзор проекта

На следующей диаграмме показан общий обзор проекта, который мы будем создавать.

ESP32 MQTT публикация температуры DS18B20 обзор проекта
  • ESP32 запрашивает показания температуры с датчика DS18B20. Показания публикуются в топик esp32/ds18b20/temperature;

  • Node-RED подписан на топик esp32/ds18b20/temperature. Таким образом, он получает показания температуры DS18B20 и отображает их на шкале/графике;

  • Вы можете получать показания на любой другой платформе, поддерживающей MQTT, и обрабатывать их по своему усмотрению.

Предварительные требования

Перед тем как приступить к этому руководству, убедитесь, что вы выполнили следующие предварительные условия.

Arduino IDE

Мы будем программировать ESP32 с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение ESP32.

MQTT-брокер

Установка Mosquitto MQTT брокера на Raspberry Pi

Для использования MQTT вам нужен брокер. Мы будем использовать брокер Mosquitto, установленный на Raspberry Pi. Прочитайте Как установить брокер Mosquitto на Raspberry Pi.

Вы можете использовать любой другой MQTT-брокер, включая облачный MQTT-брокер. Мы покажем вам, как это сделать в коде позже.

Если вы не знакомы с MQTT, обязательно прочитайте наше вводное руководство: Что такое MQTT и как он работает.

Библиотеки MQTT

Для использования MQTT с ESP32 мы будем использовать библиотеку Async MQTT Client.

Установка библиотеки Async MQTT Client

  1. Нажмите здесь, чтобы скачать библиотеку Async MQTT client. В папке «Загрузки» должен появиться .zip файл

  2. Распакуйте .zip файл, и вы должны получить папку async-mqtt-client-master

  3. Переименуйте папку из async-mqtt-client-master в async_mqtt_client

  4. Переместите папку async_mqtt_client в папку библиотек вашей установки Arduino IDE

  5. Наконец, перезапустите Arduino IDE

Альтернативно, вы можете перейти в Sketch > Include Library > Add .ZIP library и выбрать только что скачанную библиотеку.

Установка библиотеки Async TCP

Для использования MQTT с ESP вам также нужна библиотека Async TCP.

  1. Нажмите здесь, чтобы скачать библиотеку Async TCP client. В папке «Загрузки» должен появиться .zip файл

  2. Распакуйте .zip файл, и вы должны получить папку AsyncTCP-master

  3. Переименуйте папку из AsyncTCP-master в AsyncTCP

  4. Переместите папку AsyncTCP в папку библиотек вашей установки Arduino IDE

  5. Наконец, перезапустите Arduino IDE

Альтернативно, вы можете перейти в Sketch > Include Library > Add .ZIP library и выбрать только что скачанную библиотеку.

Библиотеки датчика температуры DS18B20

Для работы с датчиком температуры DS18B20 вам нужно установить библиотеку One Wire от Paul Stoffregen и библиотеку Dallas Temperature. Выполните следующие шаги для установки этих библиотек.

  1. Откройте Arduino IDE и перейдите в Sketch > Include Library > Manage Libraries. Должен открыться Менеджер библиотек.

  2. Введите «onewire» в строке поиска и установите библиотеку OneWire от Paul Stoffregen.

Установка библиотеки OneWire от Paul Stoffregen в Arduino IDE
  1. Затем найдите «Dallas» и установите библиотеку DallasTemperature от Miles Burton.

Установка библиотеки DallasTemperature от Miles Burton в Arduino IDE

После установки библиотек перезапустите Arduino IDE.

Чтобы узнать больше о датчике температуры DS18B20, прочитайте наше руководство: ESP32 DS18B20 с Arduino IDE (одиночный, множественные датчики, веб-сервер).

Необходимые компоненты

Для этого проекта вам понадобятся следующие компоненты:

Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!

Схема подключения

Подключите DS18B20 к ESP32, как показано на следующей схеме: вывод данных DS18B20 подключён к GPIO 4.

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: сообщение всегда доставляется ровно один раз;

  • Узнайте больше о MQTT QoS.

Загрузка кода

С включённым Raspberry Pi и работающим MQTT-брокером Mosquitto загрузите код в ESP32.

Откройте монитор порта на скорости 115200 бод, и вы увидите, что ESP32 начинает публиковать сообщения.

ESP32 Arduino IDE монитор порта MQTT публикация показаний датчика

Подготовка панели 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 в поток.

Node-RED перетаскивание узлов MQTT In Chart Gauge

Нажмите на узел MQTT и измените его свойства следующим образом:

MQTT In узел ESP32 публикация температуры Node-RED поток

Поле Server относится к MQTT-брокеру. В нашем случае MQTT-брокером является Raspberry Pi, поэтому установлено значение localhost:1883. Если вы используете облачный MQTT-брокер, вам следует изменить это поле. Введите топик, на который хотите подписаться, и QoS.

Установите следующие свойства для узла gauge.

Узел Gauge ESP32 публикация температуры Node-RED поток

Отредактируйте узел chart следующим образом:

Узел Chart ESP32 публикация температуры Node-RED поток

Соедините узлы, как показано ниже:

ESP32 MQTT публикация температуры Node-RED поток

Наконец, разверните поток (нажмите кнопку в правом верхнем углу).

Кнопка Deploy Node-RED

Альтернативно, вы можете перейти в 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 MQTT публикация температуры Node-RED 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>`