ESP8266 NodeMCU MQTT – публикация показаний датчика BME280 (Arduino IDE)
Узнайте, как публиковать показания датчика BME280 (температура, влажность и давление) через MQTT с ESP8266 на любую платформу, поддерживающую MQTT, или любой MQTT-клиент. В качестве примера мы опубликуем показания датчика на панель Node-RED Dashboard, а ESP8266 будет запрограммирован с помощью Arduino IDE.
Рекомендуемое чтение: Что такое MQTT и как он работает
Обзор проекта
На следующей диаграмме показан общий обзор проекта, который мы создадим.
ESP8266 запрашивает показания температуры от датчика BME280;
Показания температуры публикуются в топике esp/bme280/temperature;
Показания влажности публикуются в топике esp/bme280/humidity;
Показания давления публикуются в топике esp/bme280/pressure;
Node-RED подписан на эти топики;
Node-RED получает показания датчика и отображает их на индикаторах (gauges);
Вы можете получать показания на любой другой платформе, поддерживающей MQTT, и обрабатывать их по своему усмотрению.
Предварительные условия
Прежде чем приступить к этому руководству, убедитесь, что вы выполнили следующие предварительные условия.
Arduino IDE
Мы будем программировать ESP8266 с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение ESP8266.
MQTT-брокер
Для использования MQTT вам нужен брокер. Мы будем использовать брокер Mosquitto, установленный на Raspberry Pi. Прочитайте Как установить брокер Mosquitto на Raspberry Pi.
Вы можете использовать любой другой MQTT-брокер, включая облачный MQTT-брокер. Мы покажем вам, как это сделать в коде далее.
Если вы не знакомы с MQTT, обязательно прочитайте наше вводное руководство: Что такое MQTT и как он работает.
Библиотеки MQTT
Для использования MQTT с ESP8266 мы будем использовать библиотеку 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 и выбрать только что скачанную библиотеку.
Установка библиотеки ESPAsync TCP
Для использования MQTT с ESP8266 вам также необходима библиотека ESPAsync TCP.
Нажмите здесь, чтобы скачать библиотеку ESPAsync TCP client. У вас должен появиться файл .zip в папке загрузок
Распакуйте .zip файл, и вы получите папку ESPAsyncTCP-master
Переименуйте папку из ~~**ESPAsyncTCP-master**~~ в ESPAsyncTCP
Переместите папку ESPAsyncTCP в папку библиотек вашей Arduino IDE
Наконец, перезапустите Arduino IDE
В качестве альтернативы вы можете перейти в Sketch > Include Library > Add .ZIP library и выбрать только что скачанную библиотеку.
Библиотеки датчика BME280
Для получения показаний от модуля датчика BME280 мы будем использовать библиотеку Adafruit_BME280. Вам также необходимо установить библиотеку Adafruit_Sensor. Выполните следующие шаги для установки библиотек в вашей Arduino IDE:
Откройте Arduino IDE и перейдите в Sketch > Include Library > Manage Libraries. Должен открыться Library Manager.
Найдите «adafruit bme280» в поле поиска и установите библиотеку.
Для использования библиотеки BME280 вам также необходимо установить Adafruit Unified Sensor. Выполните следующие шаги для установки библиотеки в вашей Arduino IDE:
Найдите «Adafruit Unified Sensor» в поле поиска. Прокрутите вниз до конца, чтобы найти библиотеку и установить её.
После установки библиотек перезапустите Arduino IDE.
Чтобы узнать больше о датчике BME280, прочитайте: ESP8266 с BME280 с использованием Arduino IDE (давление, температура, влажность)
Необходимые компоненты
Для этого руководства вам понадобятся следующие компоненты:
ESP8266 (прочитайте Сравнение лучших плат разработки ESP8266)
Плата Raspberry Pi (прочитайте Лучшие стартовые наборы Raspberry Pi)
Вы можете использовать ссылки выше или перейти напрямую на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Схема подключения
Подключите BME280 к ESP8266, как показано на следующей схеме: вывод SDA подключён к GPIO 4, а вывод SCL подключён к GPIO 5.
Код
Скопируйте следующий код в вашу Arduino IDE. Чтобы он работал для вас, вам нужно вставить ваши сетевые учётные данные, а также данные MQTT-брокера.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-mqtt-publish-bme280-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 <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// Raspberri 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 Topics
#define MQTT_PUB_TEMP "esp/bme280/temperature"
#define MQTT_PUB_HUM "esp/bme280/humidity"
#define MQTT_PUB_PRES "esp/bme280/pressure"
// BME280 I2C
Adafruit_BME280 bme;
// Variables to hold sensor readings
float temp;
float hum;
float pres;
AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker 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 onWifiConnect(const WiFiEventStationModeGotIP& event) {
Serial.println("Connected to Wi-Fi.");
connectToMqtt();
}
void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
Serial.println("Disconnected from Wi-Fi.");
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
wifiReconnectTimer.once(2, connectToWifi);
}
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
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()) {
mqttReconnectTimer.once(2, connectToMqtt);
}
}
/*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.print("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void setup() {
Serial.begin(115200);
Serial.println();
// Initialize BME280 sensor
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
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 BME280 sensor readings
temp = bme.readTemperature();
//temp = 1.8*bme.readTemperature() + 32;
hum = bme.readHumidity();
pres = bme.readPressure()/100.0F;
// Publish an MQTT message on topic esp/bme280/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: %i ", MQTT_PUB_TEMP, packetIdPub1);
Serial.printf("Message: %.2f \n", temp);
// Publish an MQTT message on topic esp/bme280/humidity
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(hum).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_HUM, packetIdPub2);
Serial.printf("Message: %.2f \n", hum);
// Publish an MQTT message on topic esp/bme280/pressure
uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_PRES, 1, true, String(pres).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_PRES, packetIdPub3);
Serial.printf("Message: %.3f \n", pres);
}
}
Как работает код
Следующий раздел импортирует все необходимые библиотеки.
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
Вставьте ваши сетевые учётные данные в следующие строки.
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
Вставьте IP-адрес Raspberry Pi, чтобы ESP8266 подключился к вашему брокеру.
#define MQTT_HOST IPAddress(192, 168, 1, 106)
Если вы используете облачный MQTT-брокер, вставьте доменное имя брокера, например:
#define MQTT_HOST "example.com"
Определите порт MQTT.
#define MQTT_PORT 1883
Температура, влажность и давление будут публиковаться в следующих топиках:
#define MQTT_PUB_TEMP "esp/bme280/temperature"
#define MQTT_PUB_HUM "esp/bme280/humidity"
#define MQTT_PUB_PRES "esp/bme280/pressure"
Инициализируйте объект Adafruit_BME280 с именем bme.
Adafruit_BME280 bme;
Переменные temp, hum и pres будут хранить значения температуры, влажности и давления от датчика BME280.
float temp;
float hum;
float pres;
Создайте объект AsyncMqttClient с именем mqttClient для управления MQTT-клиентом и таймеры для переподключения к MQTT-брокеру и маршрутизатору при потере соединения.
AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker 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() подключает ваш ESP8266 к маршрутизатору:
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
Функция connectToMqtt() подключает ваш ESP8266 к MQTT-брокеру:
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
Функция onMqttConnect() выполняется после установления сессии с брокером.
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
Функции MQTT: отключение и публикация
Если ESP8266 теряет соединение с MQTT-брокером, вызывается функция onMqttDisconnect, которая выводит сообщение в Serial Monitor.
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
mqttReconnectTimer.once(2, connectToMqtt);
}
}
Когда вы публикуете сообщение в MQTT-топик, вызывается функция onMqttPublish(). Она выводит идентификатор пакета в Serial Monitor.
void onMqttPublish(uint16_t packetId) {
Serial.print("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
По сути, все эти функции, которые мы только что упомянули, являются функциями обратного вызова (callback). Поэтому они выполняются асинхронно.
setup()
В функции setup() инициализируйте датчик BME280.
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
Следующие две строки создают обработчики, которые позволят как MQTT-брокеру, так и Wi-Fi-соединению переподключиться в случае потери связи.
wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
Наконец, назначьте все функции обратного вызова. Это означает, что эти функции будут вызываться автоматически при необходимости. Например, когда ESP8266 подключается к брокеру, он автоматически вызывает функцию 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() вы создаёте таймер, который позволит получать новые показания от датчика BME280 и публиковать их в соответствующем топике каждые 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 BME280 sensor readings
temp = bme.readTemperature();
//temp = 1.8*bme.readTemperature() + 32;
hum = bme.readHumidity();
pres = bme.readPressure()/100.0F;
Узнайте больше о получении показаний от датчика BME280: ESP8266 с датчиком BME280: руководство по температуре, влажности и давлению.
Публикация в топики
Для публикации показаний в соответствующие MQTT-топики используйте следующие строки:
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(hum).c_str());
uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_PRES, 1, true, String(pres).c_str());
По сути, используйте метод publish() объекта mqttClient для публикации данных в топик. Метод publish() принимает следующие аргументы (по порядку):
MQTT-топик (const char*)
QoS (uint8_t): качество обслуживания – может быть 0, 1 или 2
Флаг retain (bool): флаг сохранения
Полезная нагрузка (const char*) – в данном случае полезная нагрузка соответствует показаниям датчика
QoS (quality of service, качество обслуживания) – это способ гарантировать доставку сообщения. Он может быть одним из следующих уровней:
0: сообщение будет доставлено один раз или не доставлено вовсе. Сообщение не подтверждается. Нет возможности дублирования сообщений;
1: сообщение будет доставлено как минимум один раз, но может быть доставлено более одного раза;
2: сообщение всегда доставляется ровно один раз;
Загрузка кода
Включив Raspberry Pi с запущенным MQTT-брокером Mosquitto, загрузите код на ваш ESP8266.
Откройте Serial Monitor на скорости 115200 бод, и вы увидите, что ESP8266 начинает публиковать сообщения в топики, которые мы определили ранее.
Подготовка панели Node-RED Dashboard
ESP8266 публикует показания температуры каждые 10 секунд в топики esp/bme280/temperature, esp/bme280/humidity и esp/bme280/pressure. Теперь вы можете использовать любую панель управления, поддерживающую MQTT, или любое другое устройство, поддерживающее MQTT, для подписки на эти топики и получения показаний.
В качестве примера мы создадим простой поток (flow) с использованием Node-RED для подписки на эти топики и отображения показаний на индикаторах.
Если у вас не установлен Node-RED, следуйте следующим руководствам:
Запустив Node-RED на вашем Raspberry Pi, перейдите по IP-адресу Raspberry Pi с портом :1880.
http://raspberry-pi-ip-address:1880
Интерфейс Node-RED должен открыться. Перетащите три узла MQTT in и три узла gauge на поток.
Нажмите на узел MQTT и отредактируйте его свойства.
Поле Server относится к MQTT-брокеру. В нашем случае MQTT-брокер – это Raspberry Pi, поэтому установлено значение localhost:1883. Если вы используете облачный MQTT-брокер, вам следует изменить это поле.
Вставьте топик, на который хотите подписаться, и QoS. Предыдущий узел MQTT подписан на топик esp/bme280/temperature.
Нажмите на другие узлы MQTT in и отредактируйте их свойства с тем же сервером, но для других топиков: esp/bme280/humidity и esp/bme280/pressure.
Нажмите на узлы gauge и отредактируйте их свойства для каждого показания. Следующий узел настроен для показаний температуры. Отредактируйте другие узлы для остальных показаний.
Соедините узлы, как показано ниже:
Наконец, разверните ваш поток (нажмите кнопку в правом верхнем углу).
В качестве альтернативы вы можете перейти в Menu > Import и скопировать следующий код в Clipboard для создания вашего потока Node-RED.
[{"id":"5a45b8da.52b0d8","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/temperature","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":310,"y":60,"wires":[["3042e15e.80a4ee"]]},{"id":"3042e15e.80a4ee","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":2,"width":0,"height":0,"gtype":"gage","title":"Temperature","label":"ºC","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#f7df09","#ca3838"],"seg1":"","seg2":"","x":590,"y":60,"wires":[]},{"id":"8ff168f0.0c74a8","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/humidity","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":300,"y":140,"wires":[["29251f29.6687c"]]},{"id":"29251f29.6687c","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":2,"width":0,"height":0,"gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":"30","max":"100","colors":["#53a4e6","#1d78a9","#4e38c9"],"seg1":"","seg2":"","x":580,"y":140,"wires":[]},{"id":"294f7eea.999d72","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/pressure","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":300,"y":220,"wires":[["58610d70.bb9764"]]},{"id":"58610d70.bb9764","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":4,"width":0,"height":0,"gtype":"gage","title":"Pressure","label":"hPa","format":"{{value}}","min":0,"max":"1200","colors":["#b366ff","#8000ff","#440088"],"seg1":"","seg2":"","x":580,"y":220,"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":"37de8fe8.46846","type":"ui_group","z":"","name":"BME280","tab":"53b8c8f9.cfbe48","order":1,"disp":true,"width":"6","collapse":false},{"id":"53b8c8f9.cfbe48","type":"ui_tab","z":"","name":"Home","icon":"dashboard","order":2,"disabled":false,"hidden":false}]
Демонстрация
Перейдите по IP-адресу вашего Raspberry Pi с добавлением :1880/ui.
http://raspberry-pi-ip-address:1880/ui
Вы должны получить доступ к текущим показаниям датчика BME280 на панели Dashboard. Вы можете использовать другие типы узлов панели для отображения показаний различными способами.
Вот и всё! Ваша плата ESP8266 публикует показания температуры, влажности и давления BME280 в Node-RED через MQTT.
Заключение
MQTT – это отличный протокол связи для обмена небольшими объёмами данных между устройствами. В этом руководстве вы узнали, как публиковать показания температуры, влажности и давления от датчика BME280 с ESP8266 в различные MQTT-топики. Затем вы можете использовать любое устройство или платформу домашней автоматизации для подписки на эти топики и получения показаний.
Вместо BME280 вы можете использовать другой датчик:
Мы надеемся, что это руководство было полезным для вас. Если вы хотите узнать больше об ESP8266, ознакомьтесь с нашими ресурсами:
Спасибо за чтение.