ESP32:Примеры/Подключение ESP32 к Node-RED при помощи MQTT
Подключение ESP32 к Node-RED при помощи MQTT
В этом примере мы продемонстрируем, как использовать панель управления Node-RED для управления GPIO-контактами ESP32 и показывать на графике данные, считанные с температурного датчика. Мы создадим простой проект, с помощью которого научимся нескольким важным вещам – тому, как настроить подписку и публикацию при помощи Node-RED.
Вот общая схема проекта, который мы сделаем:
- ESP32 подключена к кнопке. При нажатии на эту кнопку ESP32 опубликует сообщение в топик «esp32/led/toggle», на который подписана Node-RED. Получив это сообщение, Node-RED переключит состояние у переключателя «LED» на панели управления;
- Когда состояние у переключателя «LED» на панели управления изменится, сообщение об этом будет опубликовано в топик «esp32/led», на который подписана плата ESP32. Таким образом, получив это сообщение, ESP32 переключит состояние подключенного к ней светодиода (вместо него можно использовать любое другое устройство вывода данных);
- ESP32 будет считывать данные о температуре с температурного датчика DS18B20 и публиковать их в топик «esp32/temperature»;
- Node-RED подписана на топик «esp32/temperature» и потому будет получать температурные данные от датчика DS18B20, а затем публиковать их в график.
Справочная информация
Использование MQTT с ESP32: введение
Этот Раздел будет введением в тему MQTT и то, как ее можно использовать вместе с ESP32.
Аббревиатура MQTT означает «message queuing telemetry transport», что можно перевести как «передача сообщений о телеметрии при помощи очереди». Это упрощенная система публикации и подписки, позволяющая публиковать сообщения и, будучи клиентом, получать их.
MQTT – это простой протокол передачи данных, предназначенный для устройств с низкой пропускной способностью. Это делает его идеальным для проектов в области интернета вещей. MQTT позволяет отправлять команды для управления устройствами вывода данных, считывать и публиковать данные от датчиков и многое другое.
Базовые концепты MQTT
В MQTT есть несколько базовых концептов, которые нужно знать и понимать:
- Публикация/подписка;
- Сообщения;
- Топики;
- Брокер;
Публикация/подписка
Первый концепт – это система публикации и подписки. Ее суть в том, что устройство может публиковать сообщения в топик или быть подписано на него, чтобы получать его сообщения.
Для примера представьте такую ситуацию:
- Устройство 1 публикует данные в топик;
- Устройство 2 подписано на топик, куда публикует свои данные Устройство 1;
- Это позволяет Устройству 2 получать сообщения Устройства 1;
Сообщения – это фрагменты информации, переходящие от одного устройства к другому. Это могут быть и данные, и команды.
Топики
Еще один важный концепт MQTT – это топики. Для устройства-отправителя это место, куда оно может публиковать свои сообщения, а для устройства-получателя это место, к сообщениям которого оно может проявить заинтересованность.
Топики представляются в виде строк, разбитых на части при помощи прямых слешей («/»). Каждый слеш означает уровень топика. Ниже – пример топика для лампы, находящейся кабинете, который в свою очередь находится у вас дома.
Итак, если представить сценарий, при котором вы управляете лампой в своем домашнем кабинете при помощи ESP32 и MQTT, то он будет выглядеть примерно так:
- У нас есть устройство, которое публикует сообщения «вкл» и «выкл» в топик «home/office/lamp»;
- На этот топик подписана ESP32, управляющая включением/выключением лампы;
- Таким образом, когда в этом топике публикуется новое сообщение, ESP32 получает команду «вкл» или «выкл» и, соответственно, включает либо выключает лампу;
Первым устройством может быть ESP32, ESP8266 или контроллер, на который установлена платформа для домашней автоматизации вроде Node-RED, Home Assistant, Domoticz или OpenHAB.
Брокер
Наконец, вам также нужно понимать, что такое «брокер». Он в основном ответственен за получение всех сообщений, фильтрацию сообщений, принятие решений о том, кто в них заинтересован, и отправку этих сообщений всем подписанным клиентам.
Брокеры бывают разными. Есть, к примеру, брокер Mosquitto, установленный на Raspberry Pi, или бесплатный облачный брокер CloudMQTT.
Мы будем использовать брокер Mosquitto, установленный на Raspberry Pi.
Итого
Итак, в этом Разделе мы научились следующему:
- MQTT – это коммуникационный протокол, хорошо подходящий для проектов в области интернета вещей;
- В MQTT устройства могут публиковать сообщения в топики и быть подписаны на другие топики, чтобы получать их сообщения;
- При использовании MQTT необходим брокер. Он получает все сообщения и отправляет их подписанным клиентам;
Node-RED
Этот Раздел – краткое введение в тему Node-RED. Здесь мы расскажем о том, что такое Node-RED и как ее установить. Мы также покажем, как установить ноды панели управления Node-RED.
Что такое Node-RED?
Node-RED – это мощный open-source инструмент для создания проектов в области интернета вещей при помощи визуального программирования.
Визуальное программирование – это способ создания программ с помощью подключения друг к другу блоков кода (называемых «нодами»), что сильно упрощает значительную часть программирования. Последовательность подключенных друг к другу нод называется «потоком».
Почему Node-RED – это хорошее решение?
Node-RED – это open-source проект, который разработан IBM и отлично работает на Raspberry Pi.
Node-RED дает возможность быстро делать прототипы сложных систем домашней автоматизации, благодаря чему у вас остается больше времени на проектирование и прочие интересные вещи.
Что можно сделать при помощи Node-RED?
Node-RED упрощает:
- Доступ к GPIO-контактам Raspberry Pi;
- Настройку MQTT-коммуникации с другими платами (ESP32, ESP8266, Arduino и т.д.);
- Создание отзывчивого GUI для проектов (при помощи панели управления Node-RED);
- Коммуникацию со сторонними сервисами (IFTTT.com, Adafruit.io, Thing Speak и т.д.);
- Считывание данных из сети (прогнозы погоды, курсы акций, имейлы и т.д.);
- Создание событий, управляемых с помощью времени;
- Хранение и считывание информации из базы данных;
Вот библиотека с примерами потоков и нод для Node-RED.
Устанавливаем библиотеки
Нам нужно установить в IDE Arduino необходимые библиотеки, которые понадобятся для того, чтобы использовать вместе с ESP32 протокол MQTT – «AsyncTCP» и «async MQTT client».
Устанавливаем библиотеку «AsyncTCP»
- Кликните тут, чтобы загрузить ZIP-архив библиотеки;
- Распакуйте скачанный архив. У вас должна получиться папка «AsyncTCP-master»;
- Переименуйте ее на «AsyncTCP»;
- Переместите папку «AsyncTCP» в папку «libraries», которая находится в папке, куда установлена ваша IDE Arduino;
- Перезапустите IDE Arduino если она была запущена;
Устанавливаем библиотеку «async MQTT client»
- Кликните тут, чтобы загрузить ZIP-архив библиотеки;
- Распакуйте скачанный архив. У вас должна получиться папка «async-mqtt-client-master»;
- Переименуйте ее на «async_mqtt_client»;
- Переместите папку «async_mqtt_client» в папку «libraries», которая находится внутри папки, куда установлена ваша IDE Arduino;
- Перезапустите IDE Arduino если она была запущена;
Нам также нужно установить библиотеки «OneWire» (автор – Пол Стоффреген) и «Arduino Temperature Control» – они необходимы для использования датчика DS18B20.
Устанавливаем библиотеку «OneWire»
- Кликните тут, чтобы скачать ZIP-архив библиотеки;
- Распакуйте скачанный архив. У вас должна получиться папка «OneWire-master»;
- Переименуйте папку «OneWire-master» на «OneWire»;
- Переместите папку «OneWire» в папку «libraries», которая находится внутри папки, куда установлена ваша IDE Arduino;
- Перезапустите IDE Arduino если она была запущена;
Устанавливаем библиотеку «Arduino Temperature Control»
- Кликните тут, чтобы скачать ZIP-архив библиотеки;
- Распакуйте скачанный архив. У вас должна получиться папка «Arduino-Temperature-Control-Library-master»;
- Переименуйте папку «Arduino-Temperature-Control-Library-master» на «DallasTemperature»;
- Переместите папку «DallasTemperature» в папку «libraries», находящуюся внутри папки, куда установлена ваша IDE Arduino;
- Перезапустите IDE Arduino если она была запущена;
Установка MQTT-брокера Mosquitto на Raspberry Pi
В этом Разделе мы установим брокер Mosquitto на Raspberry Pi. Как уже говорилось в предыдущем разделе, брокер в основном ответственен за получение всех сообщений, фильтрацию сообщений, принятие решение о том, кто в них заинтересован, и публикацию этих сообщений для всех подписанных клиентов.
Брокеры бывают разными. В этом примере мы будем использовать брокер Mosquitto, установленный на Raspberry Pi.
Откройте новое окно терминала Raspberry Pi.
Чтобы установить брокер Mosquitto, введите следующие команды:
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
Чтобы Mosquitto автоматически запускался при загрузке, впишите следующее:
sudo systemctl enable mosquitto.service
Проверяем, установлен ли Mosquitto
Отправляем команду:
mosquitto -v
Эта команда возвращает версию Mosquitto, установленную на Raspberry Pi. Она должна быть 1.4.x или выше.
IP-адрес Raspberry Pi
Чтобы узнать IP-адрес своей Raspberry Pi, впишите в терминал следующую команду:
hostname -I
В нашем случае IP-адрес Raspberry Pi – это «192.168.1.2». Сохраните его, т.к. он понадобится нам далее, чтобы ESP32 можно было подключить к MQTT-брокеру Mosquitto.
Итого
Итак, в этом Разделе мы научились устанавливать брокер Mosquitto на Raspberry Pi.
Устанавливаем Node-RED
Node-RED устанавливается на Raspberry Pi очень быстро и просто. Откройте терминал Raspberry Pi и введите туда следующую команду:
bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)
Через несколько минут установка должна завершиться.
Настраиваем автоматический запуск Node-RED при загрузке
Чтобы Node-RED автоматически запускалась при загрузке Raspberry Pi, вам нужно ввести следующую команду:
sudo systemctl enable nodered.service
Теперь перезапустите Raspberry Pi, чтобы автозапуск вступил в силу:
sudo reboot
Ищем IP-адрес Raspberry Pi
Чтобы узнать IP-адрес Raspberry Pi, впишите в терминале следующую команду:
hostname -I
В моем случае IP-адрес Raspberry Pi – это «192.168.1.2». Сохраните IP-адрес, который получился у вас, потому что он еще пригодится нам в этом и следующем Разделах.
Проверяем, установилась ли Node-RED
Когда Raspberry Pi снова включится, мы можем протестировать установку Node-RED, введя в браузере IP-адрес Raspberry Pi, который мы узнали выше, а после него – номер порта «1880».
http://IP_АДРЕС_ВАШЕЙ_RPi:1880
В моем случаем он выглядит так:
http://192.168.1.2:1880
В результате в браузере должна загрузиться вот такая страница:
Обзор интерфейса Node-RED
В левой части находится список блоков. Эти блоки называются нодами, и они разделены на группы по функциональности. Выбрав ноду, взгляните на вкладку info – там должна появиться информация о том, как работает выбранная нода.
В центре расположена область для потока – сюда вы будете помещать свои ноды.
Установка панели управления Node-RED
Панель управления Node-RED – это набор нод, предоставляющих инструменты для создания пользовательского интерфейса, который оснащен кнопками, графиками, текстом и так далее.
Более подробно о панели управления Node-RED можно почитать по этим ссылкам:
- Сайт Node-RED: http://flows.nodered.org/node/node-red-dashboard
- GitHub-репозиторий Node-RED: https://github.com/node-red/node-red-dashboard
Чтобы установить панель управления Node-RED, перейдите в меню Settings (это кнопка с тремя горизонтальными полосками в правом верхнем углу страницы) и нажмите на Manage palette:
Откроется меню пользовательских настроек – User Settings. Кликните на вкладку Install, вбейте в поиске «node-red-dashboard» и нажмите на кнопку Install:
Закройте это меню. В левой панели появится новая группа нодов под названием «dashboard»:
Теперь у вас все готово, чтобы встроить Node-RED в систему с ESP32 и создать пользовательский интерфейс для взаимодействия с ESP32.
Создаем поток Node-RED
Перед созданием потока на вашей Raspberry Pi должны быть установлены:
- Node-RED;
- Панель управления Node-RED;
- MQTT-брокер Mosquitto;
Импортируем поток
После этого импортируем поток Node-RED. Для этого копируем RAW-версию этого потока:
[{"id":"9e58624.7faaba","type":"mqtt out","z":"c02b79b2.501998","name":"","topic":"esp32/led","qos":"","retain":"","broker":"10e78a89.5b4fd5","x":740,"y":520,"wires":[]},{"id":"abf7079a.653be8","type":"mqtt in","z":"c02b79b2.501998","name":"","topic":"esp32/temperature","qos":"2","broker":"10e78a89.5b4fd5","x":430,"y":300,"wires":[["cc79021b.9a751","46e7770d.86d9e8"]]},{"id":"83cf37cf.c76988","type":"ui_switch","z":"c02b79b2.501998","name":"","label":"LED","group":"61285987.c20328","order":0,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"on","onvalueType":"str","onicon":"","oncolor":"","offvalue":"off","offvalueType":"str","officon":"","offcolor":"","x":590,"y":520,"wires":[["9e58624.7faaba"]]},{"id":"cc79021b.9a751","type":"debug","z":"c02b79b2.501998","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":630,"y":260,"wires":[]},{"id":"dd25cb97.5921d8","type":"mqtt in","z":"c02b79b2.501998","name":"","topic":"esp32/led/toggle","qos":"2","broker":"10e78a89.5b4fd5","x":420,"y":480,"wires":[["83cf37cf.c76988","b9659d3c.bf3d3"]]},{"id":"b9659d3c.bf3d3","type":"debug","z":"c02b79b2.501998","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":440,"wires":[]},{"id":"46e7770d.86d9e8","type":"ui_chart","z":"c02b79b2.501998","name":"","group":"61285987.c20328","order":0,"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,"x":630,"y":340,"wires":[[],[]]},{"id":"10e78a89.5b4fd5","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"61285987.c20328","type":"ui_group","z":"","name":"Main","tab":"e7c46d5e.a1283","disp":true,"width":"6","collapse":false},{"id":"e7c46d5e.a1283","type":"ui_tab","z":"","name":"Dashboard","icon":"dashboard"}]
Далее в Node-RED жмем на кнопку в правом верхнем углу (с тремя горизонтальными полосками), а затем на Import > Clipboard.
Затем вставляем скопированный поток в поле и жмем на кнопку Import.
В поток должны загрузиться следующие ноды:
Внеся в поток необходимые изменения, кликните на кнопку Deploy, чтобы сохранить их.
Что это за поток
Теперь давайте поближе взглянем на каждую ноду этого потока, чтобы понять, как он работает.
Нода MQTT-подписки (mqtt in)
Самая первая нода – это нода MQTT-подписки (mqtt in). Если дважды кликнуть по ней, откроется такое окно:
В этой ноде можно задать топик, на который вы хотите подписаться. В данном случае мы подписываемся на топик «esp32/temperature», чтобы получать от него данные о температуре.
В поле Server вписывается IP-адрес MQTT-брокера. В нашем случае брокер Mosquitto и Node-RED работают на одной и той же Raspberry Pi, что позволяет нам использовать «localhost».
В поле QoS вписывается уровень качества обслуживания MQTT, а в поле Name – название ноды.
Нода графика (chart)
При помощи этой ноды мы, получив из топика «esp32/temperature» данные о температуре, будем показывать их на графике. Дважды кликните по этой ноде – откроется новое окно, где можно отредактировать свойства этой ноды.
Еще одна нода MQTT-подписки (mqtt in)
Это вторая в потоке MQTT-нода для подписки, но теперь – на топик «esp32/led/toggle», в который будут приходить данные об управлении (включении/выключении) светодиодом. В него может прийти сообщение «on» или «off».
Нода переключателя светодиода (switch)
Сконструированная нами система позволит управлять светодиодом двумя способами:
- При помощи программного переключателя на панели управления Node-RED. В этом случае при изменении положения переключателя в топик «esp32/led» будет опубликовано MQTT-сообщение, дающее команду включить/выключить светодиод;
- При помощи нажатия на аппаратную кнопку, подключенную к ESP32. После нажатия на нее ESP32 опубликует в топик «esp32/led/toggle» соответствующее сообщение. Поскольку на этот топик подписан программный переключатель на панели управления Node-RED (о котором рассказывалось выше), он автоматически переключится согласно присланному сообщению и, соответственно, изменит состояние светодиода.
Нода MQTT-публикации (mqtt out)
Это нода для публикации MQTT-сообщения от переключателя светодиода в топик «esp32/led».
Логику взаимодействия этих нод будет проще понять, если взглянуть на схему проекта в самом начале этого руководства.
Настройки MQTT-брокера
Все вышесказанное строится на том, что Node-RED и MQTT-брокер установлены на одной и той же Raspberry Pi. Но если вы используете другой MQTT-брокер, то вам нужно будет сделать еще кое-что. Во-первых, дважды кликните по одной из MQTT-нод:
Затем нажмите на кнопку Edit рядом с полем Server:
Впишите туда IP-адрес и номер порта вашего MQTT-сервера:
Панель управления Node-RED
Итак, проект готов. Чтобы открыть панель управления Node-RED и посмотреть, как выглядит наше приложение, откройте любой браузер в вашей локальной сети и впишите туда следующее:
http://IP-адрес-вашей-Raspberry-Pi:1880/ui
Ваше приложение должно выглядеть примерно как на скриншоте ниже:
Что нужно сделать перед загрузкой кода
Чтобы этот скетч заработал сразу, вставьте в трех строчках ниже SSID и пароль для своей WiFi-сети, а также IP-адрес MQTT-брокера.
// впишите в двух строчках ниже SSID и пароль для своей WiFi-сети,
// чтобы ваша ESP32 могла подключиться к WiFi-роутеру:
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// вставьте в переменную «MQTT_HOST» IP-адрес своей Raspberry Pi,
// чтобы ESP32 могла подключиться к MQTT-брокеру Mosquitto:
#define MQTT_HOST IPAddress(192, 168, 1, X)
Температура в градусах Цельсия/Фаренгейта
По умолчанию этот скетч публикует температуру в градусах Цельсия. Если вы хотите, чтобы он публиковал температуру в градусах Фаренгейта, перейдите в блок loop() и закомментируйте вот эти две строчки кода:
// публикуем в топик «esp32/temperature»
// MQTT-сообщение с температурой в градусах Цельсия:
// uint16_t packetIdPub2 = mqttClient.publish("esp32/temperature",
// 2, true, String(sensors.getTempCByIndex(0)).c_str());
Затем раскомментируйте вот эти две строчки:
// публикуем в топик «esp32/temperature»
// MQTT-сообщение с температурой в градусах Фаренгейта:
uint16_t packetIdPub2 = mqttClient.publish("esp32/temperature",
2, true, String(sensors.getTempFByIndex(0)).c_str());
Демонстрация
Попробуйте включить/выключить светодиод, щелкая переключатель «LED»:
Кроме того, если нажать на кнопку, подключенную к ESP32, это тоже должно изменить состояние светодиода, т.к. его автоматически обновляет переключатель на панели управления Node-RED.
Наконец, каждые 10 секунд на графике будут показываться новые данные о температуре от датчика DS18B20.
Итого
В этом проекте-примере мы продемонстрировали, как настроить коммуникацию между ESP32 и Node-RED при помощи MQTT. В частности, мы показали, как публиковать в топик (чтобы управлять контактами ESP32) и подписываться на топики (чтобы получать команды и данные о температуре).
Теперь вы можете без труда создать систему для управления ESP32 при помощи панели управления Node-RED – например, для какого-нибудь проекта домашней автоматизации.
Необходимое оборудование
- Плата ESP32 - 1шт.;
- Кнопка - 1шт.;
- Резистор на 10 кОм - 1шт.;
- Резистор на 330 Ом - 1 шт.;
- Резистор на 4,7кОм - 1шт.;
- Светодиод - 1шт.;
- Температурный датчик DS18B20 - 1шт.;
- Провода-перемычки;
- Макетная плата - 1 шт.;
- Плата Raspberry Pi - 1шт.
- Карта памяти для Raspberry Pi - 1шт.;
- Блок питания для Raspberry Pi - 1шт.;
Схема
Код
/*********
Руи Сантос
Более подробно о проекте на: https://randomnerdtutorials.com
*********/
#include <WiFi.h>
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// впишите в двух строчках ниже SSID и пароль для своей WiFi-сети,
// чтобы ваша ESP32 могла подключиться к WiFi-роутеру:
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// вставьте в переменную «MQTT_HOST» IP-адрес своей Raspberry Pi,
// чтобы ESP32 могла подключиться к MQTT-брокеру Mosquitto:
#define MQTT_HOST IPAddress(192, 168, 1, X)
#define MQTT_PORT 1883
// создаем объекты для управления MQTT-клиентом:
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
unsigned long previousMillis = 0; // время, когда в последний раз
// была опубликована температура
const long interval = 10000; // интервал, с которым будут
// публиковаться данные от датчика
const int ledPin = 25; // GPIO-контакт,
// к которому подключен светодиод
int ledState = LOW; // текущее состояние
// выходного контакта
// GPIO-контакт, к которому подключен датчик DS18B20:
const int oneWireBus = 27;
// создаем объект «oneWire» для коммуникации с OneWire-устройствами:
OneWire oneWire(oneWireBus);
// передаем объект «oneWire» объекту температурного датчика:
DallasTemperature sensors(&oneWire);
const int buttonPin = 32; // задаем GPIO-контакт,
// к которому подключена кнопка
int buttonState; // текущее состояние
// входного контакта (кнопки)
int lastButtonState = LOW; // предыдущее состояние
// входного контакта (кнопки)
unsigned long lastDebounceTime = 0; // время, когда в последний раз
// был переключен
// выходной контакт
unsigned long debounceDelay = 50; // время антидребезга
// (увеличьте это значение,
// если выходной сигнал
// по-прежнему «прыгает»)
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
// "Подключаемся к WiFi..."
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
// "Подключаемся к MQTT..."
mqttClient.connect();
}
void WiFiEvent(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("WiFi connected"); // "Подключились к WiFi"
Serial.println("IP address: "); // "IP-адрес: "
Serial.println(WiFi.localIP());
connectToMqtt();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
// "WiFi-связь потеряна"
// делаем так, чтобы
// ESP32 не переподключалась к MQTT
// во время переподключения к WiFi:
xTimerStop(mqttReconnectTimer, 0);
xTimerStart(wifiReconnectTimer, 0);
break;
}
}
// в этой функции можно добавить новые топики для подписки:
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT."); // "Подключились к MQTT."
Serial.print("Session present: "); // "Текущая сессия: "
Serial.println(sessionPresent);
// подписываем ESP32 на топик «esp32/led»:
uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0);
Serial.print("Subscribing at QoS 0, packetId: ");
// "Подписываемся при QoS 0, ID пакета: "
Serial.println(packetIdSub);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
// "Отключились от MQTT."
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
// "Подписка подтверждена."
Serial.print(" packetId: "); // " ID пакета: "
Serial.println(packetId);
Serial.print(" qos: "); // " уровень качества обслуживания: "
Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
// "Отписка подтверждена."
Serial.print(" packetId: "); // " ID пакета: "
Serial.println(packetId);
}
void onMqttPublish(uint16_t packetId) {
Serial.println("Publish acknowledged.");
// "Публикация подтверждена."
Serial.print(" packetId: "); // " ID пакета: "
Serial.println(packetId);
}
// в этой функции задается, что произойдет,
// когда ESP32 получит то или иное сообщение в топик «esp32/led»
// (эту функцию можно отредактировать):
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
String messageTemp;
for (int i = 0; i < len; i++) {
//Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}
// проверяем, пришло ли MQTT-сообщение в топик «esp32/led»:
if (strcmp(topic, "esp32/led") == 0) {
// если светодиод выключен, включаем его (и наоборот):
if (messageTemp == "on") {
digitalWrite(ledPin, HIGH);
}
else if (messageTemp == "off") {
digitalWrite(ledPin, LOW);
}
}
Serial.println("Publish received.");
// "Опубликованные данные получены."
Serial.print(" message: "); // " сообщение: "
Serial.println(messageTemp);
Serial.print(" topic: "); // " топик: "
Serial.println(topic);
Serial.print(" qos: "); // " уровень качества обслуживания: "
Serial.println(properties.qos);
Serial.print(" dup: "); // " дублирование сообщения: "
Serial.println(properties.dup);
Serial.print(" retain: "); // " сохраненные сообщения: "
Serial.println(properties.retain);
Serial.print(" len: "); // " размер: "
Serial.println(len);
Serial.print(" index: "); // " индекс: "
Serial.println(index);
Serial.print(" total: "); // " суммарно: "
Serial.println(total);
}
void setup() {
// запускаем датчик DS18B20:
sensors.begin();
// делаем контакт светодиода выходным (OUTPUT)
// и задаем ему значение «LOW»:
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// делаем контакт кнопки входным (INPUT):
pinMode(buttonPin, INPUT);
Serial.begin(115200);
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.onMessage(onMqttMessage);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
connectToWifi();
}
void loop() {
unsigned long currentMillis = millis();
// каждые Х секунд («interval» = 5 секунд)
// ESP32 будет публиковать новое MQTT-сообщение
// в топик «esp32/temperature»:
if (currentMillis - previousMillis >= interval) {
// сохраняем время, когда в последний раз
// были опубликованы новые данные от датчика:
previousMillis = currentMillis;
// новые температурные данные:
sensors.requestTemperatures();
// публикуем в топик «esp32/temperature»
// MQTT-сообщение с температурой в градусах Цельсия:
uint16_t packetIdPub2 = mqttClient.publish("esp32/temperature", 2,
true, String(sensors.getTempCByIndex(0)).c_str());
// публикуем в топик «esp32/temperature»
// MQTT-сообщение с температурой в градусах Фаренгейта:
// uint16_t packetIdPub2 = mqttClient.publish("esp32/temperature",
// 2, true, String(sensors.getTempFByIndex(0)).c_str());
Serial.print("Publishing on topic esp32/temperature at QoS 2, packetId: ");
// "Публикуем в топик «esp32/temperature»
// при QoS 2, ID пакета: "
Serial.println(packetIdPub2);
}
// считываем состояние кнопки
// и сохраняем его в локальную переменную:
int reading = digitalRead(buttonPin);
// если состояние кнопки изменилось (из-за шума или нажатия),
// сбрасываем таймер:
if (reading != lastButtonState) {
// сбрасываем таймер «антидребезга»:
lastDebounceTime = millis();
}
// если состояние кнопки изменилось после периода «антидребезга»:
if ((millis() - lastDebounceTime) > debounceDelay) {
// и если новое значение отличается от того,
// что хранится сейчас в переменной «buttonState»:
if (reading != buttonState) {
buttonState = reading;
// публикуем MQTT-сообщение в топик «esp32/led/toggle»
// чтобы переключить состояние светодиода
// (т.е. чтобы включить или выключить его):
if ((buttonState == HIGH)) {
if (!digitalRead(ledPin)) {
mqttClient.publish("esp32/led/toggle", 0, true, "on");
Serial.println("Publishing on topic esp32/led/toggle topic at QoS 0");
// "Публикуем в топик «esp32/led/toggle»
// при QoS 0"
}
else if (digitalRead(ledPin)) {
mqttClient.publish("esp32/led/toggle", 0, true, "off");
Serial.println("Publishing on topic esp32/led/toggle topic at QoS 0");
// "Публикуем в топик «esp32/led/toggle»
// при QoS 0"
}
}
}
}
// сохраняем новое значение кнопки в переменную «lastButtonState»;
// в результате при следующем проходе через loop()
// новое значение кнопки будет считаться ее предыдущим значением:
lastButtonState = reading;
}
См.также
Внешние ссылки