Mqtt брокер на esp8266 пошаговая инструкция

Время на прочтение
3 мин

Количество просмотров 48K

Как говорится, лень — двигатель прогресса. Для облегчения жизни сейчас делаю себе небольшое устройство в виде модуля ESP8266 и преобразователя RS485 для связи с датчиками-газоанализаторами по протоколу Modbus. В производстве постоянно возникает необходимость подключаться к приборам для выполнения различного рода диагностики по 485 интерфейсу, но каждый раз тащить с собой ноутбук неудобно, а вот мобильный телефон всегда в кармане.

В процессе разработки получилась библиотека, которая позволяет подключаться напрямую с телефона к модулю и обмениваться данными через приложение MQTT клиента. Возможно кому-то такое решение тоже пригодится, ведь отпадает необходимость иметь сторонний MQTT брокер (будь то локальный брокер на Raspberry или брокер в интернете) и подключение к интернету, что в моем случае самое главное.

Приложение для телефона

В качестве приложения я выбрал IoTmanager. Основная фича — это очень гибкая настройка виджетов с помощью HTML5+CSS, все настройки производятся в устройствах, а не в приложении. Топики отправляются в JSON формате и содержат в себе имена заголовков, значения и стили отображения. Возможно кому-то это будет неудобно, но мне такой подход понравился.

Приложение может работать на двух MQTT библиотеках: Paho.js и MQTT.js. С ходу у меня получилось установить WebSocket соединение через библиотеку Paho, на ней я и остался работать. Если выбрать в настройках MQTT, соединения не происходит, подозреваю, что нужно поковырять библиотеку WebSocketServer.

Я долго презирал Arduino, но все же сдался

Не хочу разводить дискуссию по поводу выбора среды, просто скажу, что для меня важную роль в выборе Arduino IDE для написания прошивки ESP8266 сыграло наличие тонны готовых библиотек и документации. Все просто и быстро, благо проект обещает быть не сложным.

Оффтопик

Хотите верьте, хотите нет, но даже ракеты улетают в космос с микроконтроллерами, запрограммированными в среде Arduino. Решающую роль очень часто играет скорость разработки — подключил готовые библиотеки и в путь.

Open Source наше все

Репозиторий на GitHub. Библиотека пока сыровата, в некоторых случаях настройки виджетов вызывают реконнект IoTmanager’a, причину которого я найти пока не могу, возможно совместная разработка пойдет быстрее.

Проект содержит в себе две реализации библиотеки:

MQTTbroker.h это попытка реализовать реальный брокер с контролем подписок. Т.е когда приходит сообщение в топик, брокер проходит по всем клиентам и их подпискам и ищет совпадения (в том числе по маскам /+/) и рассылает сообщения только тем, у кого подписки соответствуют имени топика, не забывая про самого себя.

MQTTbroker_lite.h работает немного быстрее за счет того, что в ней отсутствует автоматическая логика обработки подписок. Все приходящие сообщения перенаправляются в callback функцию основной программе, а там уже, если надо, обрабатываем их сами. Для конкретно моего случая нужна именно такая реализация: одно устройство — один подключаемый клиент, я знаю на что он подписан и чего от меня ждет.

Пример работы

Берем любой модуль с ESP8266 (у меня это NodeMcu) и загружаем в него скетч примера из библиотеки. Порт для отладки в инструментах Arduino IDE предлагаю отключить, иначе библиотека будет слать кучу отладочных сообщений, потом на них посмотрите. Открываем последовательный порт и наблюдаем IP адрес.

На телефоне подключаемся к созданной Wi-Fi точке доступа. В приложении IoTmanager заходим в настройки подключения: выбираем движок PAHO, вбиваем IP адрес модуля, 80 порт, префикс топиков /IoTmanager и чуть ниже отключаем SSL/TLS.

Жмем на спидометр в углу, после небольшой задержки должно подключиться и отобразить переключатели. Если не подключается, попробуйте убить и заново запустить приложение. На первом переключателе у меня настроен светодиод (см.видео).

Иногда возникает задержка при подключении. Как я думаю, это связано с тем, что IoTmanager выдает все начальные сообщения за один раз, ESP немного подвисает, обрабатывая их, а дальше уже работает без тормозов.

Короткое описание

Обе части библиотеки очень похожи, приведу описание версии _lite:

typedef void(*callback_t)(uint8_t num, Events_t event , String topic_name, uint8_t * payload, uint8_t length_payload); //функция callback'a должна иметь такой вид

MQTTbroker_lite(WebSocketsServer * webSocket); //конструктору класса передаем указатель на WebSocket
void setCallback(callback_t cb); //установка функции callback'a
void begin(void); //начальная инициализация (обнуление массивов)
void parsing(uint8_t num, uint8_t * payload, uint8_t length); //парсинг пришедшего в WS сообщения
void publish(uint8_t num, String topic, uint8_t* payload, uint8_t length); //публикация сообщения клиенту num
void disconnect(uint8_t num); //отключение клиента
bool clientIsConnected(uint8_t num); //проверка клиента на соединение 

Видео демонстрация

Спасибо за внимание. Присоединяйтесь к разработке, библиотека еще сыровата.
За помощью можно обращаться в Telegram oWart

Ссылки:

1. Проект на GitHub
2. Описание виджетов IoTmanager
3. Спецификация протокола MQTT v.3.1.1

ESP8266 as a MQTT Broker

In this tutorial i am telling to you ” How To use ESP8266 as a MQTT Broker”. uMQTTBroker is a MQTT Broker library for ESP8266 Arduino, available on GitHub.

Now we Arduino IDE, If you don’t familier with ESP8266 using Arduino IDE. Please Visit given below post.

Arduino Support for ESP8266 with simple test code

First Download uMQTT Broker library from Github. Download Now.  Create new sketch and paste given below code.

/*
 * uMQTTBroker demo for Arduino
 * 
 * Minimal Demo: the program simply starts a broker and waits for any client to connect.
 */

#include 
#include "uMQTTBroker.h"

uMQTTBroker myBroker;

/*
 * Your WiFi config here
 */
char ssid[] = "iotbyhvm";      // Replace with your network SSID (name)
char pass[] = "asdf7890"; // Replace with your network password

/*
 * WiFi init stuff
 */
void startWiFiClient()
{
  Serial.println("Connecting to "+(String)ssid);
  WiFi.begin(ssid, pass);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  
  Serial.println("WiFi connected");
  Serial.println("IP address: " + WiFi.localIP().toString());
}

void startWiFiAP()
{
  WiFi.softAP(ssid, pass);
  Serial.println("AP started");
  Serial.println("IP address: " + WiFi.softAPIP().toString());
}

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println();

  // Connect to a WiFi network
  startWiFiClient();

  // Or start the ESP as AP
//startWiFiAP();

  // Start the broker
  Serial.println("Starting MQTT broker");
  myBroker.init();
}

void loop()
{   
  // do anything here
  delay(1000);
}

Now connect your ESP8266 development board with your PC. Select Board and Port. Flash this code.

Open Your Serial Monitor, Here you can found a IP address. this IP address is your MQTT Broker address.

If Serial Monitor is not displaying IP address then press RST button of ESP8266 Board.

What is uMQTTBroker ?

This is a MQTT Broker library for ESP8266 Arduino. You can start an MQTT broker in any ESP Arduino project. Just clone (or download the zip-file and extract it) into the libraries directory of your Arduino ESP8266 installation.

The broker does support:

  • MQTT protocoll versions v3.1 and v3.1.1 simultaniously
  • a smaller number of clients (at least 8 have been tested, memory is the issue)
  • retained messages
  • LWT
  • QoS level 0
  • username/password authentication

The broker does not yet support:

  • QoS levels other than 0
  • many TCP(=MQTT) clients
  • non-clear sessions
  • TLS

For API information Visit this: https://github.com/martin-ger/uMQTTBroker


If you are searching for a complete ready-to-run MQTT broker for the ESP8266 with additional features (persistent configuration, scripting support and much more) have a look at https://github.com/martin-ger/esp_mqtt .

esp_uMQTT_broker

This is a MQTT Broker/Client with scripting support on the ESP8266. This program enables the ESP8266 to become the central node in a small distributed IoT system. It implements an MQTT Broker and a simple scripted rule engine with event/action statements that links together the MQTT sensors and actors. It can act as STA, as AP, or as both and it can connect to another MQTT broker (i.e. in the cloud). Here it can also be bridge that forwards and rewrites topics in both directions. Also it can parse JSON structures, send basic HTTP GET requests and do basic I/O: i.e. read and write to local GPIO pins, react on timers and GPIO interrupts, drive GPIO pins with PWM, and read the ADC.


I hope you’ve found this post “ESP8266 as a MQTT Broker″useful. If have any query, Please write in comment box. You can share this post “ESP8266 as a MQTT Broker “.


You may also like:

  • Dynamic WLAN configuration for ESP32 Board | AutoConnect
  • ESP32 BLE on Arduino IDE with UART Test
  • ESP32 Bluetooth Low Energy (BLE) on Arduino IDE
  • ArduinoOTA ESP32: Wi-Fi (OTA) Wireless Update from the Arduino IDE
  • ESP32 with LoRa using Arduino IDE
  • How To Use Grove-LCD RGB Backlight with NodeMCU
  • NodeMcu to DHT Interface in Blynk app
  • How To ON/OFF a bulb by Google voice assistant
  • Arduino IDE | Arduino | Open Source Hardware/Softawre | Arduino Vs RPi
  • WiFi LoRA 32 (V2) ESP32 | Overview | Introduction
  • DHT11 sensor with ESP8266/NodeMCU using Arduino IDE
  • Arduino Support for ESP8266 with simple test code

Harshvardhan Mishra

Hi, I’m Harshvardhan Mishra. Tech enthusiast and IT professional with a B.Tech in IT, PG Diploma in IoT from CDAC, and 6 years of industry experience. Founder of HVM Smart Solutions, blending technology for real-world solutions. As a passionate technical author, I simplify complex concepts for diverse audiences. Let’s connect and explore the tech world together!
If you want to help support me on my journey, consider sharing my articles, or Buy me a Coffee!
Thank you for reading my blog! Happy learning!
Linkedin

ESP8266 Connects to MQTT Broker with Arduino

MQTT is a lightweight and flexible protocol to exchange IoT messages and deliver data. It dedicates to achieving a balance between flexibility and hardware/network resources for the IoT developer.

ESP8266 provides a highly integrated Wi-Fi SoC solution. Its low power, compact design, and high stability can meet user’s requirements. ESP8266 has a complete and self-contained Wi-Fi network function, which can be applied independently or can run as a slave at another host MCU.

In this project, we will implement connecting ESP8266 to free public MQTT broker operated and maintained by EMQX Cloud, and programming ESP8266 by using Arduino IDE. EMQX Cloud is an MQTT IoT cloud service platform with security launched by EMQ. It provides a one-stop operation and maintenance agency and MQTT 5.0 access service with a uniquely isolated environment.

The Required IoT Components

  • ESP8266
  • Arduino IDE
  • MQTTX: Cross-platform MQTT 5.0 client tool
  • The free public MQTT broker
    • Broker: broker.emqx.io
    • TCP Port: 1883
    • Websocket Port: 8083

ESP8266 Pub/Sub

project.png

The code

  1. Firstly, we import libraries ESP8266WiFi and PubSubClient. ESP8266WiFi library can connect ESP8266 to the Wi-Fi network, PubSubClient library can enable ESP8266 to connect to the MQTT broker for publishing messages and subscribing topics.

    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
    
  2. Set Wi-Fi name and password, and connection address and port of MQTT broker

    // WiFi
    const char *ssid = "mousse"; // Enter your WiFi name
    const char *password = "qweqweqwe";  // Enter WiFi password
    
    // MQTT Broker
    const char *mqtt_broker = "broker.emqx.io";
    const char *topic = "esp8266/test";
    const char *mqtt_username = "emqx";
    const char *mqtt_password = "public";
    const int mqtt_port = 1883;
    
  3. Open a serial connection for facilitating to output of the result of the program and connecting to the Wi-Fi network.

    // Set software serial baud to 115200;
    Serial.begin(115200);
    // connecting to a WiFi network
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
    }
    
  4. Set MQTT broker, write the callback function, and print connection information on the serial monitor at the same time.

    client.setServer(mqtt_broker, mqtt_port);
    client.setCallback(callback);
    while (!client.connected()) {
        String client_id = "esp8266-client-";
        client_id += String(WiFi.macAddress());
        Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
        if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
        } else {
            Serial.print("failed with state ");
            Serial.print(client.state());
            delay(2000);
        }
    }
    
    void callback(char *topic, byte *payload, unsigned int length) {
        Serial.print("Message arrived in topic: ");
        Serial.println(topic);
        Serial.print("Message:");
        for (int i = 0; i < length; i++) {
            Serial.print((char) payload[i]);
        }
        Serial.println();
        Serial.println("-----------------------");
    }
    
  5. After successfully connecting to the MQTT broker, ESP8266 will publish messages and subscribe to the MQTT broker.

    // publish and subscribe
    client.publish(topic, "hello emqx");
    client.subscribe(topic);
    
  6. Print the topic name to the serial port and then print every byte of received messages.

    void callback(char *topic, byte *payload, unsigned int length) {
        Serial.print("Message arrived in topic: ");
        Serial.println(topic);
        Serial.print("Message:");
        for (int i = 0; i < length; i++) {
            Serial.print((char) payload[i]);
        }
        Serial.println();
        Serial.println("-----------------------");
    }
    
  7. The full code

    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
    
    // WiFi
    const char *ssid = "mousse"; // Enter your WiFi name
    const char *password = "qweqweqwe";  // Enter WiFi password
    
    // MQTT Broker
    const char *mqtt_broker = "broker.emqx.io";
    const char *topic = "esp8266/test";
    const char *mqtt_username = "emqx";
    const char *mqtt_password = "public";
    const int mqtt_port = 1883;
    
    WiFiClient espClient;
    PubSubClient client(espClient);
    
    void setup() {
      // Set software serial baud to 115200;
      Serial.begin(115200);
      // connecting to a WiFi network
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.println("Connecting to WiFi..");
      }
      Serial.println("Connected to the WiFi network");
      //connecting to a mqtt broker
      client.setServer(mqtt_broker, mqtt_port);
      client.setCallback(callback);
      while (!client.connected()) {
          String client_id = "esp8266-client-";
          client_id += String(WiFi.macAddress());
          Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
          if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
              Serial.println("Public emqx mqtt broker connected");
          } else {
              Serial.print("failed with state ");
              Serial.print(client.state());
              delay(2000);
          }
      }
      // publish and subscribe
      client.publish(topic, "hello emqx");
      client.subscribe(topic);
    }
    
    void callback(char *topic, byte *payload, unsigned int length) {
      Serial.print("Message arrived in topic: ");
      Serial.println(topic);
      Serial.print("Message:");
      for (int i = 0; i < length; i++) {
          Serial.print((char) payload[i]);
      }
      Serial.println();
      Serial.println("-----------------------");
    }
    
    void loop() {
      client.loop();
    }
    

Run and Test

  1. Please use Arduino IDE to upload the complete code to ESP8266 and open the serial monitor

    esp_con.png

  2. Establish the connection between the MQTTX client and the MQTT broker, and send messages to ESP8266

    mqttx_pub.png

  3. View the messages ESP8266 received in the serial monitor

    esp_msg.png

Summary

So far, we have successfully connected ESP8266 to the free public MQTT broker provided by EMQX Cloud. In this project, we connect ESP8266 to the MQTT broker, which is one of the relatively basic capabilities of ESP8266. Besides that, ESP8266 can also connect to various IoT sensors, and report the sensor data to the MQTT broker.

Next, you can check out The Easy-to-understand Guide to MQTT Protocol series of articles provided by EMQ to learn about MQTT protocol features, explore more advanced applications of MQTT, and get started with MQTT application and service development.

Resources

  • MQTT on ESP32: A Beginner’s Guide
  • How to Use MQTT on Raspberry Pi with Paho Python Client
  • MicroPython MQTT Tutorial Based on Raspberry Pi
  • Remote control LED with ESP8266 and MQTT
  • Upload Sensor Data to MQTT Cloud Service via NodeMCU (ESP8266)

Try EMQX Cloud for Free

No credit card required

Get Started →

Добрый день, уважаемый читатель!

Данная статья ориентирована в первую очередь на начинающих программистов, которые только начинают свой творческий путь программирования микроконтроллеров, в данном случае – ESP8266.

Повторив этот проект вы можете создать с помощью микроконтроллера ESP8266, WiFi, MQTT и некоторой доли творчества:

  • Дистанционный контроль и управление вашими устройствам, причем не только в локальной сетке, но и из любой точки планеты, где есть интернет
  • Удаленное управление реле и нагрузкой, например включение и отключение освещения или котла
  • Обратный контроль состояния нагрузки с устройства – получило ли оно вашу команду или нет
  • Удаленный мониторинг логических состояний на входах микроконтроллера, что позволяет создать простенькую охранную систему например
  • Удаленный мониторинг температуры и влажности в помещении
  • Оперативные уведомления о различных событиях в Telegram *
  • Отправка данных на сторонние сервисы (Thing Speak, Народный мониторинг, Open Monitoring) для отслеживания изменений во времени и построения графиков *

При этом я не ставлю Вам “жестких” рамок, у Вас всегда остается свобода для собственного творчества. При творческом подходе не сложно прикрутить управление нагрузкой по автоматическим сценариям, например включение котла по температуре. И все это с дистанционным управлением.

Примечания: функции, отмеченные * и курсивом обсудим в следующих статьях цикла про ESP8266 и Arduino-framework

В данной статье я подробно и по шагам расскажу как:

  1. Создать Arduino – проект для ESP8266 в более продвинутой и удобной среде разработки Visual Studio Code + PlatformIO.
  2. Подключить ESP8266 к вашей сети WiFi.
  3. Подключить необходимые библиотеки к проекту.
  4. Получить точное текущее время с NTP-сервера в интернете.
  5. Подключиться к MQTT-брокеру, в том числе и по TLS/SSL-протоколу
  6. Создать устройство для дистанционного управления реле через MQTT
  7. Опубликовать состояние цифровых входов (например нажатие на кнопку) на MQTT-брокере
  8. Прочитать и опубликовать температуру с датчика температуры и влажности, например DHT22

Вам понадобятся:

  • Микроконтроллер ESP8266 или любая плата на его основе: Node Mcu, ESP01 … ESP-12 и иже с ними
  • WiFi роутер и доступ к сети интернет
  • Любой публичный MQTT брокер (например можно взять любой удобный из списка здесь)
  • VSCode + PlatformIO. Ну или Arduino IDE – в ней в принципе все делается абсолютно также, только не так удобно.

В конце статьи, как обычно, есть ссылка на готовый проект на GitHub (вам останется только изменить данные для подключения на свои), так что если Вам лень читать – листайте в конец статьи. Осторожно – многа букав…


Подготовка среды разработки

Если вы заглянете в демо-проекты kotyara12/arduino, то, наверное, заметите, что в архиве нет никаких файлов .ino, а есть main.cpp и platformio.ini. Это означает, что проекты собраны не в классической Arduino IDE, а в Visual Studio Code + PlatformIO.

<sarcazm>Конечно, вы можете легко перенести код из main.cpp в классическую Arduino IDE. Но я не буду рассказывать, как это сделать, вот такой уж я вредный. Вместо этого я расскажу, как сделать все в ненавистной для многих IDE Visual Studio Code и плагине к ней PlatformIO. А перенести в Arduino IDE вы и без меня смогёте.</sarcazm>

Ну а если серьёзно – то инструкций как создать проект в Arduino IDE в интернете – пруд пруди. Не вижу смысла делать еще одну.

Итак, для начала нам понадобится собственно статья разработки. Как установить эту связку я уже рассказывал на канале и на сайте, повторяться не стоит. Стоит только отметить, что на этапе 8. Устанавливаем платформы… нужно поставить Espressif 8266:

Для этого:

  1. Нажмите “домик” PIO Home на нижней панели VS Code или значок PlatformIO на левой боковой панели, а затем выберите в списке Open.
  2. Перейдите на вкладку “Platforms
  3. В строке поиска введите 8266 и нажмите Enter
  4. Поиск выдаст единственный результат – Espressif 8266, нажмите кнопку Install (у меня это уже Uninstall).
  5. Подождите пару минут…

Создаем проект

Вновь возвращаемся на страницу PIO Home (“домик” PIO Home на нижней панели VS Code или значок PlatformIO на левой боковой панели, а затем выберите в списке Open). Но на этот раз нажмите New Project:

Выбираем название проекта (Name), плату (Board) и Framework Arduino, и нажимаем Finish:

Затем придется немного подождать, пока PlatformIO создаст необходимые файлы и папки…


Каталоги проекта

PlatformIO создаст в выбранном каталоге несколько подкаталогов (подпапок)

  • .pio\ – папка для “служебного пользования” PlatformIO, здесь будут создаваться файлы, здесь можно будет найти скомпилированный бинарник для загрузки в устройство “вручную”.
  • .vscode\ – ещё одна папка для “служебного пользования” PlatformIO, здесь хранятся настройки VSCode. Здесь есть что можно поправить, в некоторых случаях.
  • include\ – этот каталог предназначен для заголовочных файлов проекта. Надеюсь, вы знаете, что это такое 😉.
  • lib\ – сюда можно поместить локальные библиотеки проекта. “Локальные” в данном случае я понимаю как использующиеся только в данном проекте, но не в других. Сюда можно поместить части проекта, отвечающие за ту или иную функциональность проекта. Я, например, помещаю сюда файлы “прикладных” задач проекта, то есть конкретно ту автоматизацию, которую и будет выполнять данное устройство. Если у Вас есть библиотеки, которые используются сразу в нескольких ваших проектах, их лучше поместить в каталог “вне” каталога проекта для совместного использования. Я знаю, есть любители кидать в каждый проектов свои “локальные” копии общих библиотек, но я категорически не поддерживаю подобную практику, так как это приводит к огромным проблемам при дальнейшем обновлении кода.
  • src\ – здесь, собственно, и находится исходники вашего проекта. У меня, обычно, здесь только файл main.c,которые только запускает все нужные задачи и сервисы. Но ничто не мешает накидать сюда прикладных файлов, игнорируя каталог lib (см. выше), но тогда заголовочные файлы прикладных задач вам придется положить в папку include.
  • test\ – здесь будут ваши автоматизированные тесты вашего же кода, когда вы их создадите.

Кроме этого, в каталоге проекта появится и несколько файлов:

  • .gitignore – файл, в котором вы можете указать, какие из файлов не нужно загружать в GitHub.
  • platformio.ini – файл настроек проекта PlatformIO. Именно по этому файлу VSCode “понимает”, что это проект PlatformIO, а не какой-либо ещё. Этот файл будет открыт по умолчанию, давайте его сразу и рассмотрим.

Настройка проекта

platformio.ini – основной файл параметров проекта на PlatformIO в стандартном формате, придуманном ещё во времена Windows 3.1. В нем хранятся все данные о проекте – платы, порты, скорости, фильтры, скрипты и много чего ещё. Таким образом, открывая очередной проект, вам не потребуется заново выбирать плату и её параметры, как это делается в Arduino IDE.

В новом проекте он выглядит просто и незамысловато:

Совет: Если нажать на ссылку https://docs.platformio.org/page/projectconf.html в комментариях к файлу, то вы попадете в справочную систему PlatformIO, где вы сможете узнать обо всех доступных опциях. Здесь я упомяну только некоторые из них, которыми я чаще всего пользуюсь.

Единственная пока секция [env:nodemcuv2] задает параметры компиляции проекта:

  • platform = espressif8266 указывает, что для компиляции проекта будем использовать платформу espressif8266
  • board = nodemcuv2 определяет, что проект будет собран для платы Node MCU v2 (ESP-12F)
  • framework = arduino ну и собственно здесь мы должны указать, какой фреймворк будем использовать

Файл platformio.ini позволяет указать сразу несколько таких секций. Например, вы можете собирать одновременно один и тот же проект сразу для нескольких разных плат одновременно. Примеры смотрите в справочной системе https://docs.platformio.org/page/projectconf.html

Кроме секции [env:nodemcuv2] вы можете создать отдельную секцию [env] (то есть без указания целевой платформы) – в этом случае параметры этой секции будут считаться “общими” для всех указанных целей.

Скорость COM-порта

Что здесь стоит сразу же добавить? Во первых, нужно указать скорость обмена данными через USB / COM-порт в двух режимах: режиме монитора и режиме загрузки прошивки в плату. Номер COM-порта можно не указывать – если вы используете только одно подключение (одну плату), то автовыбор порта делает свою работу замечательно.

По умолчанию для большинства проектов Arduino используется скорость 9600 бод, поэтому в опции monitor_speed ставим цифру 9600. А вот для загрузки прошивки upload_speed можно выбрать скорость и повыше (чтобы снизить время прошивки); ESP8266 прошиваются нормально на скорости 921600 бод.

Фильтры COM-монитора.

Следующее, что можно поправить – настроить фильтры для монитора COM-порта. Доступны такие фильтры (подробнее смотри здесь):

  • default – удалить типичные коды управления терминалом из ввода
  • colorize – применение разных цветов для разного типа сообщений (хм, на самом деле это не работает)
  • debug – выводить и отправленное и полученное
  • direct – пересылать все данные без обработок, нужен для вывода цветных отладочных логов (ошибки – красным, предупреждения – желтым и т.д.)
  • hexlify – печать данных в шестнадцатеричном представлении для каждого символа
  • log2file – записывать данные в файл «platformio-device-monitor-%date%.log», расположенный в текущем рабочем каталоге
  • nocontrol – удалить все контрольные коды, в т.ч. CR+LF
  • printable – показать десятичный код для всех символов, отличных от ASCII, и заменить большинство управляющих кодов
  • time – добавить временную метку с миллисекундами для каждой новой строки (но это будет временная метка компьютера, а не самого устройства)
  • send_on_enter – отправить текст на устройство на ENTER
  • esp8266_exception_decoder – декодер исключений Espressif 8266, удобно, но уж очень медленно, я не использую
  • esp32_exception_decoder – декодер исключений то же самое, но для Espressif 32

Желаемые фильтры можно перечислить либо через запятую, либо в каждой строке, как вам удобнее (мне – в каждой строке, так как в таким случае их очень удобно “комментарить”). Сделать это можно в секции [env:nodemcuv2] для конкретного устройства, либо в секции [env] сразу для всех устройств, сколько бы секций вы не создали.

Я пользуюсь в основном direct и log2file – иногда очень записывать протоколы вывода в файл для последующего анализа.

На этом пока оставим этот файл, но вкладку редактора закрывать ещё рано, он нам ещё понадобится. Не забудьте сохранить изменения с помощью Ctrl+S.


Редактор кода

Ок, теперь можно начинать программировать. Для начала создадим подключение к точке доступа WiFi. Откройте главный файл проекта – main.cpp, он находится в папке src. Как видите, он ничем не отличается от типичного шаблона скетча в Arduino IDE:

Первое, что потребуется сделать – настроить COM-порт для вывода отладочных сообщений:

Цифры должны соответствовать тому, что вы указали ранее в platformio.ini. Пустой Serial.println(); нужен просто для того, чтобы перевести указатель на новую строку, так как при старте MCU в порт часто попадает мусор.


Подключение к WiFi точке доступа

Перед созданием кода, который будет выполнять подключение к точке доступа, необходимо выполнить некоторые подготовительные операции:

  • Добавьте #include <ESP8266WiFi.h> в начало файла, чтобы подключить стандартную библиотеку ESP8266WiFi к проекту.
  • Добавьте пару строк const char*, в которых укажите имя вашей сети (SSID) и пароль подключения к ней (да, да, в открытом виде, но вы же собираетесь публиковать это где попало)

Я настоятельно рекомендую вам расставлять комментарии где это только возможно. Это сильно облегчит вам жизнь, когда вам срочно понадобиться доработать проект спустя пару лет его эксплуатации

Способы подключения к WiFi

Я могу предложить несколько вариантов логики подключения к WiFi. Разумеется, предложенные мной в статье способы не исчерпывают всех возможных вариантов, вы можете найти другие или придумать свои. Рассматривайте это просто как измышления на тему…

1. Можно запихнуть весь код подключения к WiFi в функцию setup(). Так часто делается в примерах для esp8266:

На первый взгляд, всё это очень просто и хорошо.

Можно заподозрить, что подключение к WiFi осуществляется только один раз. То есть при любом отключении или перезагрузке роутера устройство не сможет вновь подключиться к сети. На самом деле это не так. Дело в том, что класс WiFi (с которым мы работаем) имеет “свойство” AutoReconnect (на самом деле физически его нет, но так проще для понимания) и оно по умолчанию включено. Управлять этим “свойством” можно с помощью методов getAutoReconnect() и setAutoReconnect(bool). То есть наше устройство должно автоматически попытаться восстановить подключение при его потере.

Но как мы узнаем о том, что подключение было потеряно и вновь установлено? Ведь после переподключения нам потребуется вновь подключиться к MQTT брокеру и т.д. и т.п. Для того, что бы отловить изменения состояния WiFi подключения можно предложить как минимум два способа:

  • правильный способ – создать и зарегистрировать функции обратного вызова (callbacks) для событий onStationModeDisconnected (соединение потеряно) и onStationModeGotIP (получен IP-адрес, это финальная стадия подключения). Но функции обратного вызова вызывают затруднение у новичков, поэтому мы пока не будем рассматривать этот способ (если будет необходимо – пишите в комментариях)
  • простой способ – просто проверять состояние в каждой итерации главного цикла, чтобы предпринять необходимые действия. Например так:

И это действительно работает, хотя и не очень надёжно. Почему-то этот алгоритм “пропускает” некоторые отключения и восстановления от WiFi (и дело тут не в большой задержке). Зато это очень просто.

Но если вдуматься – такой подход имеет очень серьезный изъян. Если на момент запуска подключение невозможно установить по любой причине, то устройство никогда не выйдет на главный цикл и “зависнет” на ожидании подключения. И даже принудительный выход из цикла ожидания ничего толкового не дает – ведь подключение так и не было установлено. Лично для меня это категорически неприемлемо. И я никому не посоветую так делать. Так что же делать?

2. Перенесем подключение к сети в цикл loop(). Для этого просто каждый раз проверяем состояние подключения, и если оно отсутствует, “вручную” попытаемся восстановить его.

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

Уже гораздо лучше. Но здесь есть большие грабли с очень крепкой дубовой ручкой, которой обязательно прилетит вам в лоб в самый неожиданный момент. Найдете сами? Ладно, даю подсказку:

Догадались? Нет? Дело в том, что если нет подключения к WiFi, ваша программа никогда не выйдет из цикла, обведенного красным. А, следовательно, программа не выполнит что-то ещё, пока нет подключения к сети. Другими словами, температура не будет измерена, реле не будет выключено и т.д. Допустим в процессе работы вы включили насос, а затем… сгорел роутер, досадно, обидно, но… насос останется работать, пока вы не выключите устройство вместе с насосом.

Это очень опасный момент, когда вы доверяете своему устройству управление потенциально опасными устройствами – котлом, поливом и т.д.

Что же делать, как же быть? Есть два пути решения этой проблемы.

3. Принудительно ограничить время работы цикла ожидания подключения.

Всё тоже самое, но цикл ожидания немного изменим.

Вуаля, теперь ожидание не будет превышать 30 секунд. А за 30 секунд, надеюсь, ничего страшного не произойдет. Хотя это и “костыль”, но задача решена.

4. Переделать всю работу с WiFi на систему по событиям. Самый “правильный” вариант. В этом случае вам потребуется создать кучку функций обратного вызова (callbacks), которые будут асинхронно вызываться в нужные вам моменты времени: при установке соединения и при потере оного. И вы сможете сделать всё, что требуется в нужный момент времени без каких-либо циклов ожидания. В своих проектах я использую эту технику. Но в виду некоторой сложности данного подхода для начинающих (а эта графомания всё-таки для начинающих ардуинщиков), пока не будем рассматривать этот вариант. А если у вас есть некоторый опыт, вы сможете соорудить такое и без моей помощи.

Функция проверки подключения к WiFi

Теперь уже таки можно написать достаточно простую функцию подключения к AP. Лично я избегаю включать “чистый” код в setup() и loop(), а выношу все специфичные операции в отдельные функции, так зачастую удобнее. Например так может выглядеть функция, которая проверяет и восстанавливает подключение:

Тогда основные функции setup() и loop() будут выглядеть так:

Компилируем build, загружаем в плату upload. Плата должна корректно отрабатывать все отключения от WiFi сети.

В первый раз подключение успешно установлено за ~4сек, затем была перезагрузка роутера, вначале за 30 секунд установить соединение не удалось, был выход из цикла ожидания, затем удалось


Для начала давайте чуть-чуть об теории MQTT протокола. MQTT — это протокол обмена сообщениями по шаблону издатель-подписчик (pub/sub). Первоначальную версию в 1999 году опубликовали Энди Стэнфорд-Кларк из IBM и Арлен Ниппер из Cirrus Link. Они рассматривали MQTT как способ поддержания связи между машинами в сетях с ограниченной пропускной способностью или непредсказуемой связью.

Система связи, построенная на MQTT, состоит из клиентов-издателей publisher, сервера-брокера broker и одного или нескольких клиентов-подписчиков subsriber. В обычных условиях клиенты не могут общаться напрямую друг с другом, и весь обмен данными происходит только через какого-либо брокера. Издатель и подписчик ничего не знают друг о друге, но должны знать о том, по какому адресу / каналу topic передавать или ждать данные. Одно и то же устройство может быть одновременно и издателем и подписчиком (но на разные топики). Это сильно облегчает задачу передачи данных из-за NAT-а (то есть из обычных локальных сетей).

При этом, асинхронность протокола MQTT предусматривает, что издатель и подписчик могут быть онлайн в разное время, терять пакеты, и быть недоступны. Брокер в случае необходимости позаботится о том, чтобы сохранить в памяти последние данные, полученные от издателя, и обеспечить их доставку заинтересованным подписчикам.

Кратенько рассмотрим термины, которые нам просто необходимо знать для работы с MQTT протоколом.

Broker

Брокер — это центральный узел MQTT, обеспечивающий взаимодействие клиентов. Обмен данными между клиентами происходит только через брокера. В его задачи входит получение данных от клиентов-издателей, обработка и сохранение, доставка полученных данных подписчикам, а так же контроль за доставкой сообщений в случае необходимости. Брокеров может быть несколько, в том числе связанных между собой так называемыми “мостами”.

Message

Сообщения (message) содержат в себе информацию, которую один участник сети на базе протокола MQTT (издатель) хочет передать другим (своим подписчикам). В качестве сообщения может быть всё, что угодно – текст, значения температуры, состояние датчиков и т.д. и т.п. И даже двоичные данные.

Publish

Это процесс передачи сообщения брокеру. То есть простым языком, я подошел к брокеру и сказал “кнопка нажата“. Брокер теоретически должен услышать это сообщение, записать (при необходимости) и передать дальше подписчикам. Почему теоретически? Потому что есть особенности протокола (QoS), которые мы разберем чуть ниже. Пока берем за данность, что я сказал что-то брокеру используя механизм publish и он это услышал и обработал как положено.

Subscribe

Сообщение было отправлено брокеру, но как его получить клиенту? Правильно – подписаться. Тогда сервер передаст вам все поступающие сообщения на интересующую вас тему. Чтобы определить на какую тему мы хотим получать эти сообщения, используется механизм Topic

Topic

Топик (его ещё иногда называют темой или каналом) – это своего рода адрес для передачи тех или иных данных. Для того, чтобы клиент-подписчик смог получить опубликованные данные, он должен заранее знать, в каком топике (по сути по какому адресу) их будет отправлять издатель. По аналогии с обычными газетами и почтой:

Издатель печатает несколько газет (топиков) – “Аргументы и факты“, “Ведомости” и “Гудок“. Подписчик может подписаться на один из указанных топиков или несколько. А может подписаться на журнал “Новости адруинщика” (почему нет?). Почтальон (брокер) принесет подписчику только те газеты (сообщения), которые напечатал (отправил) издатель, и на которые подписался подписчик. То есть вы должны заранее знать, на что подписываться.

Топик может быть простым (например temperature) и состоящим из нескольких отдельных частей, разделенных слешем “/” (например home/kitchen/temperature). Для чего нужны эти “/“? А для того, дабы выстроить определенную иерархию данных. По аналогии с приведенным выше примером с почтой это могут быть топики “Газеты/Аргументы и факты” и “Журналы/Мурзилка“. Чем то это очень похоже на структуру каталогов и файлов на дисках вашего контупера.

Во-первых строках письма это даёт более простое понимание множества данных:

Но самое главное – это сильно облегчает подписку на данные путем использования подстановочных знаков wildcards. MQTT протокол предусматривает два типа wildcards при подписках на топики:

  • # (твой дом тюрьма решетка) позволяет элегантно подписаться на все субтопики одном махом
  • + (плюсик) позволяет подписаться на все топики одного уровня

Ну например: у нас есть в кухне и в спальне по два выключателя и один в гараже. Для этого мы формируем на выключателях в топики в виде:

В гостиной:

home/kitchen/switch1
home/kitchen/switch2

В спальне:

home/bedroom/switch1
home/bedroom/switch2

В гараже:

garage/switch1

Допустим мы хотим управлять всеми выключателями в доме, но нам абсолютно не интересен гараж. В обычном режиме нам пришлось бы подписаться на все топики отдельно:

mqttClient.subscribe("home/kitchen/switch1");
mqttClient.subscribe("home/kitchen/switch2");
mqttClient.subscribe("home/bedroom/switch1");
mqttClient.subscribe("home/bedroom/switch2");

Геморой? Не то слово! Гораздо проще и надежнее сделать это так:

mqttClient.subscribe("home/#");

Бонусом мы автоматически получаем подписку на все еще заранее неизвестные топики в доме (впрочем иногда это лишнее).

Хорошо, а если нас интересует только выключатель 1, но не важно в какой комнате. Тогда напишем так:

mqttClient.subscribe("home/+/switch1");

Но чтобы пользоваться этими возможностями, нужно заранее продумывать структуру топиков для своих устройств, а не сочинять их с бухты-барахты.

<вредный совет>Таки если вы желаете сделать себе нервы и выесть моск, создавайте топики максимально простыми и случайным образом. Это очень поможет вам в дальнейшем. Тормоза придумали трусы, а иерархию – ботаники.</вредный совет>

Служебные сообщения

В принципе есть несколько типов служебных сообщений MQTT протокола:

  • Birth Message – которое сообщает миру что “я родился и живой”
  • Last Will and Testament (LWT) которое сообщает что после этого сообщения считать меня мертвым
  • Keep Alive – которые сообщают брокеру что “я все еще живой” и стандартно посылаются каждые 60 секунд. Если брокер не получил это сообщение от клиента, то он принудительно пингует его чтобы выяснить жив ли тот, и если выясняется что он неживой, то брокер публикует за клиента LWT сообщение, чтобы все узнали что тот скончался.

Соответственно получение брокером Birth Message от устройства, переводит устройство в режим ONLINE, а после того как брокер получает от устройства LWT сообщение, либо когда сам принимает решение что тот скончался (проверив устройство на доступность), то переводит статус устройства в режим OFFLINE.

На практике нам понадобится только LWT, все остальные служебные сообщения отправляются библиотекой самостоятельно и без нашего ведома. Как создать LWT и как допилить его под удобную индикацию статуса устройства будет рассказано чуть ниже.

Retain или Retained

Протокол MQTT никоим образом не предназначен для накопления данных на сервере с последующим отображением в виде графиков. Максимум что может храниться на сервере – последнее опубликованное издателем сообщение, если оно было отправлено с флагом retain или retained (в разных версиях может называться по разному, но суть одна и та же). Это позволяет клиенту-подписчику при подключении к брокеру сразу же получить последние интересующие его данные, а не ждать когда их отправит издатель в очередной раз. Однако использование этого флага требует известной аккуратности, неверное его использование может привести к невразумительным проблемам.

QoS

QoS расшифровывается как Quality Of Service, то есть качество предоставляемой услуги. Для MQTT этот показатель отвечает за вероятность прохождения пакета между двумя точками сети. Флаг QoS может принимать следующие значения, основанные на надежности передачи сообщения:

  • 0 = не более одного раза: отправитель пересылает сообщение получателю и забывает об этом. Сообщения могут быть потеряны в канале связи или продублированы (если отправитель посчитал что пакет потерян и отправил его повторно, но первый пакет таки дошёл до получателя).
  • 1 = по крайней мере один раз: получатель подтверждает доставку сообщения. Если подтверждение не было получено, отправитель должен отправить его еще раз и так до получения подтверждения о получении. Сообщения могут дублироваться, но доставка гарантирована
  • 2 = ровно один раз: сервер обеспечивает гарантированную доставку. Сообщения поступают точно один раз без потери или дублирования. Самый медленный и машинотрудозатратный вариант, так как отправитель и получатель дополнительно обмениваются подтверждениями.

На этом с теорией закончим, переходим непосредственно к программированию. Но для этого вначале необходимо подключить библиотеку MQTT клиента к нашему проекту.


Подключаем сторонние библиотеки

Для работы с MQTT протоколом нам понадобится сторонняя библиотека, например PubSubClient. Существует две популярные версии данной библиотеки (хотя может быть и больше):

  • основная версия от knolleary, именно она доступна через менеджер библиотек Arduino IDE
  • альтернативная версия от lmroy, которая является ответвлением от основной версии

Чем они отличаются? В основной версии значение QoS можно указать только при подписке. А при публикации – нет! Я считаю, что это не есть хорошо (к слову, разработчики MQTT клиента для ESP-IDF считают так же, поскольку в ESP32 реализован “по второму типу”).

Лично я предпочитаю пользоваться версией от Imroy. Но в данном примере я буду использовать основную ветку. Просто потому что во 99.9999999% примеров в сети используется именно она.

Если вы работали с Arduino IDE, то, наверное, знаете, что там библиотеки можно достаточно легко и просто скачать и установить с помощью встроенного менеджера библиотек. В PlatformIO всё на первый взгляд сложнее, но на самом деле всё не так страшно, да и возможностей гораздо больше. Я настоятельно рекомендую ознакомиться с документацией по менеджеру библиотек, но для начала достаточно усвоить самые простые способы. Итак, если очень кратенько, существует несколько способов подключить сторонние библиотеки:

  • Локальные библиотеки проекта. Для этого потребуется скачать архив библиотеки с GitHub и распаковать его содержимое в каталог \lib вашего проекта. В этом случае PIO автоматически “подхватит” эти библиотеки и ничего нигде настраивать не нужно. Но я настоятельно не рекомендую так делать. Почему? Потому что вам придется хранить отдельную копию библиотек для каждого из своих проектов. Это занимает дополнительное место на дисках, но самое главное – если необходимо обновить библиотеки, вам придется сделать это в каждом из своих проектах. Ручками. Как всегда – за свою лень в начале мы заплатим многократным трудом впоследствии, чудес не бывает.
  • Общие локальные библиотеки. Этот способ очень удобно использовать, когда одни и те же библиотеки используется сразу в нескольких проектах. Допустим, все общие библиотеки мы будем складывать в папку C:\PlatformIO\libs. Создаем такой каталог, вручную скачиваем архив с GitHub, и вручную распаковываем содержимое в только что созданный каталог. Всё как и в предыдущем случае, только целевая папка изменилась. Теперь нам нужно “подключить” каталог C:\PlatformIO\libs к нашему проекту через параметр lib_extra_dirs. Для этого потребуется указать только каталог lib_extra_dirs = C:\PlatformIO\libs, все вложенные библиотеки не более одного уровня вложенности “подхватятся” автоматически. Открываем файл platformio.ini (помните, я вас предупреждал не закрывать его) и добавляем такие строчки:

Этот способ идеален для “своих” общих библиотек, но для “чужих” лучше использовать следующий

  • Публичные библиотеки. Я настолько ленив, что мне даже лень скачивать и распаковывать библиотеки вручную. Да ещё потом и обновлять их придется в случае чего. Данунафиг. PlatformIO предоставляет очень удобный способ подключения публичных библиотек напрямую с GitHub или из каталога библиотек PlatfortmIO. Просто укажите прямые ссылки на них в параметре lib_deps – и вам не придется следить за скачиванием и обновлением этих библиотек – PlatformIO всё возьмет на себя:

Вот так гораздо лучше

Просто? Очень! Нужно только знать, где найти эту самую нужную библиотеку. На гитхабе конечно! Ну да гуголь вам в помощь.

Теперь можно добавить библиотеку в исходный код нашего проекта: #include <PubSubClient.h> и начинать писать код подключения к брокеру.


Подключение к MQTT-серверу без шифрования

Для начала давайте попробуем подключиться к брокеру в открытом виде, без TLS-шифрования. Я использую такой вариант только для подключения к своему локальному брокеру, который находится в моей локальной сети, относительно защищенной от интернета NAT-ом. Но для примера вполне сойдет.

Для подключения необходимо предварительно запастить следующими данными:

  • адрес сервера в сети
  • порт сервера (обычно 1883, но вполне может быть и другой)
  • имя пользователя
  • пароль пользователя

Все это вы должны заранее узнать на том сервере, к которому вы собираетесь подключиться. Я достаточно давно уже пользуюсь wqtt.ru (он платный, но стоит относительно недорого и без существенных ограничений на текущий момент !!!не реклама!!!). В данном примере нам понадобятся:

Порт берем пока самый простой, первый по списку. Не перепутайте, иначе ничего не выйдет. Заведем их в программу в виде констант:

Не забудьте подставить свои значения

Далее, нам потребуется завести две глобальные переменные:

Первая – это экземпляр WiFi клиента, который требуется для работы MQTT-клиента. Вторая – MQTT-клиент собственной персоной.

Далее пишем такую функцию:

По аналогии с предыдущим случаем, здесь мы проверяем, есть ли подключение к брокеру; и если нет – указываем параметры сервера и подключаемся. Всё предельно просто.

Во многих примерах ClientID генерируется “на лету” из части MAC-адреса устройства, но я не вижу необходимости тратить на это свободную память кучи. Ибо нефиг. Только не забывайте менять его от проекта к проекту (он должен быть уникальным).

Затем дополняем основной цикл loop() следующими строками:

Если соединение с брокером есть, в каждой итерации loop() обязательно вызываем mqttClient.loop(), дабы отправлять сообщения на сервер и получать входящие сообщения от сервера.

В результате, если всё сделано правильно, мы должны получить примерно следующее:

Прелэстно, прелэстно… К MQTT брокеру мы подключились, но пока мы не научили наше устройство что-либо отправлять и получать с него.


Добавляем LWT и статус устройства

Добавим топик, который позволит нам отслеживать состояние устройства – в сети оно или нет. Для этого воспользуемся функционалом, предоставляемым нам MQTT протоколом, который называется LWT (Last Will and Testament, «последняя воля и завещание») для уведомления заинтересованных сторон об отключении клиента.

  • Пусть для примера топик статуса будет “demo/status” (хотя на практике тут должно бы быть что-то вроде “home/boiler/status” или “garage/status“).
  • В рабочем состоянии в этом топике должно быть “online“, когда устройство выключено или связи нет, то “offline” (хотя вполне можно использовать и просто “1” и “0“).
  • Для такого типа информации оптимальнее всего использовать Qos = 1 (так как повторное получение никому не помешает), а вот retain лучше поставить 1 или true.

Определим константы:

Совет: Я всегда стараюсь использовать константы, а не прописываю постоянные значения прямо “в коде”. Ибо прямое написание ведет к многократным потерям в производительности труда при модификациях кода и многочисленным ошибкам. Надо ли объяснять почему так? Хотя для компилятора, конечно же, всё равно. Это очень плохая практика, для меня это практически табу. Если вы будете так делать, то вы сами себе злобный Буратино.

Осталось немного модифицировать код подключения к брокеру:

То есть сразу же при подключении мы отправляем на сервер параметры LWT сообщения. Но сразу после подключения в этом топике будет пусто, так как “offline” там появится только после того, как устройство будет отключено. Дабы исправить это недоразумение, мы сразу же публикуем в этот же самый топик состояние “online“. Вот и всё, что требовалось.


Добавим SSL / TLS

Подключаться к публичному облачному брокеру в открытом виде – плохой вариант. В этом случае все ваши данные, в том числе логины и пароли, передаются в открытом виде. И более-менее продвинутый кулхацкер сможет перехватить их. Способов изобретено множество – от аппаратных до программных. Например можно создать “подставной” промежуточный сервер брокер или внедрить в вашу сеть сниффер (вопрос только зачем ему это? ну так зачем у нас молодняк дорожные знаки и остановки курочит?). Не будем облегчать кулхацкерам задачу, ну и заодно и себе тоже.

К чему это я? Давайте модифицируем подключение к брокеру с использованием SSL или TLS шифрования. Это дает не только полное шифрование всех передаваемых данных, но и гарантирует, что вы подключаетесь к настоящему серверу, а не подставному, созданному специально для перехвата (хотя вряд ли кто-то когда либо будет создавать сервер-перехватчик специально для вас, если только вы не подпольный миллионер на пенсии).

Я не буду углубляться в теорию TLS-соединений. В сети найдется немало материалов на эту тему, а я не являюсь специалистом в криптографии. Одно я знаю наверняка – для того чтобы установить зашифрованное TLS-соединение, вашему устройству как минимум понадобится сертификат сервера (впрочем не самого сервера, но об этом ниже). Сертификат сервера несет в себе несколько функций:

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

Отсюда вывод, что без сертификата сервера шифрованное соединение установить не получится. В принципе, сертификат сервера скачает библиотека TLS-соединения самостоятельно, при обращении к серверу. Нам требуется только его проверить – но как это сделать?

Все сертификаты сайтов выданы и подписаны какими-либо центрами сертификации, которые так же имеют свой сертификат. Центр сертификации не обязательно должен быть один, их может быть несколько в цепочке, подписанных один за другим. Например: сертификат для сайта wqtt.ru был выдан ЦС R3, а тому, в свою очередь, выдал сертификат ISRG Root X1.

Первый сертификат в списке называется “корневым”. Если корневому сертификату мы доверяем целиком и полностью, то остальные “вложенные” сертификаты мы сможем проверить “по цепочке”. Поэтому для проверки сертификата любого сайта мы должны иметь “всего лишь” список доверенных корневых сертификатов, которым мы доверяем. Это намного меньше, чем хранить сертификаты всех сайтов, но всё равно это внушительный общем информации, который просто не влезет в память микроконтроллера (впрочем в ESP-IDF имеется возможность подключить к проекту такой список, который называется tls bundle, но речь сейчас не о нём). Поэтому на Arduino обычно ограничиваются подключением с проекту одного или нескольких корневых сертификатов, в зависимости от того, к каким сайтам требуется доступ. Например для подключения к брокеру wqtt.ru нам потребуется подключить сертификат ISRG Root X1.

Но у всех сертификатов (и корневых и не только) имеется встроенная головная боль для ардуино-программистов, и называется она “срок действия сертификата”. После заранее определенного в сертификате срока он считается “испорченным”. Кроме того, сертификат может быть отозван досрочно, если есть подозрения на его компрометацию. И тогда таким “порченным” корневым сертификатом ничего проверить уже будет нельзя. И нам потребуется оперативно заменить его в прошивке. Поэтому для критичных устройств необходимо предусмотреть вариант резервного варианта подключения в открытом виде, дабы не потерять контроль над устройством. Обычно для корневых доверенных сертификатов срок действия достаточно велик, чтобы не очень беспокоиться по этому поводу, но событие в календарик добавить всё-таки стоит.

Как получить файл корневого сертификата

Итак, нам нужен файл корневого сертификата. Самое простое в windows – использовать обычный браузер, например хром. Если у вас установлен антивирус, придется его отключить на время, так как антивирусные программы подменяют сертификаты ЦС своими собственными и это ни к чему хорошему не приведет. Затем откройте нужный вам сайт и найдите замочек в адресной строке, затем кликните на этот замочек:

Затем кликните на строку “Безопасное подключение”, а затем на “Действительный сертификат”:

Откроется окошечко просмотра сертификата, где мы должны перейти на вкладку “Подробнее”, выделить в иерархии верхний сертификат и нажать “Экспорт”:

Затем просто указываем, где бы мы хотели сохранить файл и нажимаем ОК. В итоге у вас в выбранной папке должен нарисоваться новый файлик с вот таким примерно содержанием:

Это и есть то, что нам нужно!

Добавим к нашему проекту константу static const char ISRG_Root_x1[] PROGMEM = R”EOF()EOF”; а затем скопируйте содержимое сертификата и вставьте между круглых скобок. У вас должно получиться нечто вроде этого:

Но это ещё не все. Не забудьте скопировать другой номер порта в настройках MQTT, его мы забьем в отдельную константу mqttPortTLS (хотя вполне можно и в старой переменной изменить значение):

Но и это ещё не всё! Вспомните про срок действия сертификата – нам нужно время! Причем в прямом смысле слова. Если к вашему устройству подключены аппаратные часы реального времени, то можно получить время с них. Иначе нам придется получить время с SNTP-сервера. Как это сделать, я уже писал на этом сайте ранее, повторяться не буду. Здесь приведу лишь готовую функцию получения актуального времени, я добавил этот блок в wifiConnected() сразу после подключения:

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

После этого уже можно смело добавить корневой сертификат в список доверенных:

Вот теперь всё готово к TLS-соединению!

Необходимо только не забыть заменить порт подключения в параметрах сервера, иначе при подключении будет возвращена ошибка:

Ну вот и всё, этого достаточно, можно пробовать:

Как видите, это совсем не сложно. А страху-то шо было! Крип-то-гра-фия! О как!


Дистанционное управление реле

У нас всё готово для решения практических задач. Вначале давайте сделаем так называемую “умную розетку” или “умную лампочку“, а по сути “тупой пульт дистанционного управления с телефона“, гы… Хотя что нам одна лампочка или розетка. Давайте сразу три или четыре. Пощёлкаем орешки релюшками “по полной программе”.

Перво-наперво нужно определить выводы, к которым подключены наши реле, например так:

И не забыть настроить эти GPIO на режим “на выход”:

Затем определим топики, через которые будем подавать команды. Пусть это будут такие топики:

Я не зря добавил в конце каждого топика /control – не спешите обрезать, он нам ещё пригодится. И определим текстовые команды для этих топиков. Я обозначил здесь аж сразу два варианта – можно будет отправить в топик “1” или “on” и результат будет одинаков.

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

Подписаться то мы подписались, а как мы узнаем, что с сервера пришла команда на включение или выключение реле? Правильно – нужно таки создать функцию-обработчик, используя прототип std::function<void(char*, uint8_t*, unsigned int)>

Я написал такую функцию:

Вначале нам необходимо выделить полезную информацию из входящего потока байт. Для пущей надежности я добавил функции обрезки “лишних” пробелов из текстовых строк и приведение их к нижнему регистру.

Затем можно сравнить топик и данные с заранее определенными и решить как поступить в данном случае:

Не забудьте зарегистрировать этот обработчик в любом удобном месте, например так:

Прошиваем контроллер, проверяем работу.


Добавим обратную связь на управление реле

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

Давайте добавим функцию обратной связи, которая будет точно гарантировать, что наше устройство точно выполненное нашу команду. Кроме того, перенесём фактическое управление реле из обработчика входящих команд в другую функцию, а обработчик просто будет переключать нужные переменные.

Добавим топики для публикации фактического состояния реле, они будут немного отличаться от топиков управления, например так:

Затем добавим глобальные переменные для хранения текущих состояний реле и для хранения полученных “команд”:

После этого модифицируем наш обработчик следующим образом:

Отлично. Осталось написать код, который будет сравнивать “старое” и “новое” состояние реле и в случае необходимости щёлкать ими:

Если значение relayCommandX и relayStatusX отличаются друг от друга, то переключаем выход, к которому подключено реле и публикуем новое состояние реле в “ответный” топик.

Но это ещё не всё. Хорошо бы при подключении к MQTT серверу опубликовать текущие состояния реле, так как во время временного отключения от сервера состояния реле могло и измениться (например если у вас будет какой-либо автоматический сценарий). Это просто:

Ну и не забудьте добавить эту функцию в основной цикл:

Ещё раз всё компилируем:

А на брокере в это время:

С чем вас и поздравляю! Вы только что сделали умную розетку, да ещё и с обратной связью. Думаю, что теперь вы сможете придумать, как управлять реле не по команде, а в автоматическом режиме.


Добавим публикацию состояния цифрового входа

А что, если нам нужно периодически считывать состояние входа и публиковать его состояние при изменении? Давайте попробуем…

Конечно, оптимальнее было бы использовать прерывания, но не будем пока о них. Сделаем “по простому”, выжмем из процессора все соки…

Для этого нам понадобится ещё одна переменная inputStatus1 – для хранения последнего считанного значения. Иначе нам пришлось бы публиковать состояние входа в каждом цикле, а это лишняя и абсолютно бесполезная нагрузка на процессор, сеть и брокер:

Я специально оставил её с номером, дабы было понятно, что таких входов вы можете сделать столько, сколько позволят свободные выводы ESP.

Ну и константы, топики и прочее, куда же без них:

Сама функция чтения не сложнее предыдущих:

Осталось вызывать её из главного цикла:

И таки да, не забудьте настроить используемый вывод:

В результат вы должны прочить следующее:

и на брокере:


Измеряем температуру и влажность в помещении

Теперь давайте попробуем подключить какой-нибудь датчик и прочитать с него данные. Для примера я возьму вот такой AM2302, так как на нем уже есть резистор подтяжки шины single bus:

Его я подключил к выводу D1 или GPIO5 (кстати, отличный справочник по выводам ESP8266).

Для работы с данным сенсоров так же потребуется подключить сторонние библиотеки, например от Adafruit:

#include <Adafruit_Sensor.h>
#include <DHT.h>

Но перед этим добавим ссылки на них в файл platformio.ini

Ну а дальше просто копипастим код из примера к драйверу DHT22. Ну и добавляем код для публикации на брокере:

  • Создадим глобальную переменную для DHT22:

  • Определим необходимые топики:

  • Проинициализируем сенсор в функции setup():

  • И можно, наконец, прочитать и опубликовать данные:

  • Но вот вызывать эту функцию каждую итерацию цикла loop() не следует, поэтому добавим простейший псевдотаймер на millis():

Если вы все сделали правильно, то должны получить примерно такой результат:

А на сервере в это же самое время можно увидеть следующее:


Ссылки

Как всегда, пример можно скачать в готовом виде с GitHub: github.com/kotyara12/arduino/tree/master/arduino_eps8266_dzen

На этом пока всё, до встречи на сайте и на telegram-канале!. Если Вам понравилась статья – кликните на любое рекламное объявление, этого будет вполне достаточно для поддержки автора.

🔶 Архив статей, упорядоченный по категориям 🔶

The rising number of small Internet of Things (IoT) devices is driving the development of highly integrated, cost and energy-efficient microcontrollers (µC) or systems on a chip (SoC). The Chinese manufacturer, Espressif, offers the ESP-Series as SoC which is very popular for IoT applications. Numerous suppliers provide ready-to-use applications or development boards. For instance, the ESP8266 NodeMCU is one possible module to use the ESP SoC. The board includes a Wi-Fi antenna and USB connection to power and flash the SoC. In addition, a Wi-Fi module with support for the 802.11 b/g/n standards is part of the highly integrated SoC.

Setup overview; Connection of an ESP8266 node_mcu board with a MQTT broker

Figure 1. Overview of ESP8266 connection to the Mosquitto MQTT broker

With digital inputs, outputs, and digital bus interfaces, smart IoT applications with their web interfaces are possible. You can find a possible application in the project here. As you can see, the ESP8266 grabs actual power values from solar microinverters and publishes them on MQTT topics for subsequent analysis, visualization, or control via home automation systems.

Software needed to use MQTT on ESP8266

In principle, for µC and SoC, there is no operating system like Windows or Linux where you can run and use, for example, the Paho client libraries to connect to MQTT brokers. Instead, you must create a firmware that the device will flash and then realize the application. The ESP8266 SoC was released in 2015, and for software development, the manufacturer offers the Espressif IoT Development Framework (esp-idf).

However, for beginners, coding with this framework might not be straightforward. Alternatively, one can use the popular Arduino framework, which consists of software libraries and an integrated development environment (IDE). Moreover, it includes support for ESP8266. Lastly, one can also use the VSCode IDE from Microsoft with the platformIO extension. See the following table as a reference:

Name SDK / Libraries IDE
ESP-IDF Espressif Systems
https://github.com/espressif/esp-idf 
Eclipse, VSCode, Common CMake IDEs
Arduino Arduino
https://github.com/arduino/library-registry
Arduino 2.0
(main file extension *.ino)
PlatformIO Same as for Arduino VSCode + PlatformIO Extention

For this tutorial, we use the last one because this option combines the advantages of simple and beginner-friendly Arduino libraries and the powerful VSCode IDE, which can run as a desktop or browser-based application.

In addition, you can use the prepared and ready-to-code environment provided here and the sample code in your internet browser (free GitHub account needed). To use and test the application on an ESP8266 module, you need to adjust the code with your credentials, build the firmware with the command pio run in the IDE, and finally flash the created firmware onto the physical device. You can find more details in the code repository.

Example Application for MQTT on ESP8266

Altogether, the following sections explain a basic program enabling the ESP8266 to connect securely against the Pro Mosquitto to publish and subscribe to topics.

The sample application will have a simple functionality. In brief, every time a publisher posts a message on a specific time, the ESP8266 will post the actual time in synchronization via NTP on another topic.

Requirements for the MQTT Broker

To make use of this functionality, you will need the following:

  • A running MQTT broker and the address (ipv4 or DNS name).
  • Credentials (username/password) to publish and subscribe to topics.
  • The X509 certificate of the broker (essential if the connection is over public networks and I recommend to secure it by TLS transport).

Pro Edition for Eclipse Mosquitto can easily fulfill all the above requirements. Also, see the tutorial here on how to set it up. Sign up for a 14-day free trial and, within a few minutes, get a free version of a professional and secure Pro Mosquitto with an intuitive WebUI setup.

Configure the C++ Application

You can find the sample code in the public GitHub repository here. In the src folder, you can find all the code in one main.cpp file. In the first part, you need to configure some variables. All in all, the credentials and other settings are hard-coded in this basic sample application.

 1| //#define MQTT_TLS 
 2| //#define MQTT_TLS_VERIFY
 3| const char* ssid = "YOUR-WIFI";
 4| const char* password = "YOUR-WIFI-PSK";
 5| const char* mqtt_server = "BROKER";
 6| const uint16_t mqtt_server_port = 1883; 
 7| const char* mqttUser = "user";
 8| const char* mqttPassword = "pass";
 9| const char* mqttTopicIn = "esp-8266-in";
10| const char* mqttTopicOut = "esp-8266-out";

The defines in lines 1 and 2 that you can see in the code snippet above will be part of the later section, Connect via TLS. The network connection of the ESP8266 module uses the built-in Wi-Fi. Therefore, you need to configure the station id (line 3) and the pre-shared key (line 4) of the Wi-Fi, which the ESP8266 shall use.

The variables in lines 5 to 8 define the access to the MQTT broker. The value for mqtt_server can either be an ipv4 address or a DNS name. The port (line 6) is, in most cases, should be 1883 for unencrypted MQTT protocol transport and 8883 for encrypted. Note: The provided Adruino MQTT libraries do not support transport via WebSockets.

Of course, you can choose the definition for the topics (lines 9, 10). However, to avoid issues, I recommend picking different ones.

ESP8266 MQTT Code Structure and Functions

Using the Arduino framework and libraries will require at least two functions – setup and loop in the main code file. And, as the names state, the setup is executed after startup once. The loop function is called periodically every time the last loop call finishes.

Also, you will need a few global variables:

  • Includes
#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "PubSubClient.h"
#include "NTPClient.h"
#include "WiFiUdp.h"
#include "certificate.h"
  • Global variables
11| WiFiClient wifiClient;
12| WiFiUDP ntpUDP;
13| NTPClient timeClient(ntpUDP);
14| PubSubClient mqttClient(wifiClient);
  • Setup function
15| void setup() {
16|   Serial.begin(115200);
17|   setup_wifi();
18|   mqttClient.setServer(mqtt_server, mqtt_server_port);
19|   mqttClient.setCallback(callback);
20| }
  • Loop function
21| void loop() {
22|   if (!mqttClient.connected()) {
23|     connect();
24|   }
25|   mqttClient.loop();
26|   timeClient.update();
27| }

In the setup function that you see above, the major function calls are the connection setup for the MQTT broker (line 18): mqttClient.setServer(mqtt_server, mqtt_server_port) and the definition of the callback function (line 19): mqttClient.setCallback(callback)

In this case, the latter defines the function, which is called every time the client receives a new message on a subscribed topic from the broker.

In the loop function, the function call mqttClient.loop() (line 25) proceeds the MQTT client communication with the MQTT broker. Thus, to ensure that the local time on ESP8266 is in sync, the function call on line 26 runs to check and correct possible time drifts between the ESP8266 module and NTP servers. You can also check out our article on how to set up a Paho MQTT Python client securely, connect it to an MQTT broker, publish messages on topics and subscribe to them.

To ensure there is an active connection between the client and the MQTT broker, in lines 22, 23 the connection state is checked in every loop. Therefore, if the connection to the MQTT broker is lost or not yet established, the function connect() is called.

You can see the example of the connect() function below:

27| void connect() {
28|   while (!mqttClient.connected()) {
29|     Serial.print("Attempting MQTT connection...");
30|     String mqttClientId = "";
31|     if (mqttClient.connect(mqttClientId.c_str(), mqttUser, mqttPassword)) {
32|       Serial.println("connected");
33|       mqttClient.subscribe(mqttTopicIn);
34|     } else {
35|       Serial.print("failed, rc=");
36|       Serial.print(mqttClient.state());
37|       Serial.println(" will try again in 5 seconds");
38|       delay(5000);
39|     }
40|   }
41| }

As a result, the logic that I implemented in the connect function ensures that connection attempts happen every five seconds if no connection is possible.

The MQTT Callback Function on ESP8266

In the sample application below, you can see the callback function that handles the MQTT communication events and implements the main functionality:

42| void callback(char* topic, byte* payload, unsigned int length) {
43|   Serial.print("Message arrived on topic: '");
44|   Serial.print(topic);
45|   Serial.print("' with payload: ");
46|   for (unsigned int i = 0; i < length; i++) {
47|     Serial.print((char)payload[i]);
48|   }
49|   Serial.println();
50|   String myCurrentTime = timeClient.getFormattedTime();
51|   mqttClient.publish(mqttTopicOut,("Time: " + myCurrentTime).c_str());
52| }

During the connect procedure, the ESP8266 subscribes to the topic ‘esp-8266-in’ (see lines 33 and 9). Now every time an MQTT client publishes a message on this topic, the broker sends the message to the ESP8266, and then the callback function is called.

As you can see in lines 43 to 48 above, the content of the received message is sent out on the serial interface just as information.

As a demonstration of functionality in line 51, the current time on the ESP8266 module is published on the topic ‘eps-8266-out’ (topic name definition, see line 10). You can find the code here as a complete reference.

Configure the Application to use TLS on ESP8266 for MQTT

In the previous sections, I configured the application to not use an encrypted transport for the MQTT payloads. To enable encrypted transport via TLS, you need to uncomment at least line 1 to create a definition named MQTT_TLS. Leaving line 2 commented means that no certificate verification is going to happen. That is why, any MQTT broker identity can be accepted.

 1| #define MQTT_TLS 
 2| //#define MQTT_TLS_VERIFY

As a result, the change in the code will do two small actions. Firstly, the global variable wifiClient is replaced by the secured version WiFiClientSecure wifiClient, ensuring that every transport is now encrypted using TLS.

The second action lies in line 69 in the setup_wifi function (see below). With the method called wifiClient.setInsecure(), we force the client to accept every certificate provided by the broker (server) during the connection parameter negotiation. The name sounds confusing but, in the end, TLS encrypts the transport with the only drawback that every identity, e.g., invalid or self-signed X509 certificates, is accepted.

53| void setup_wifi() {
54|   delay(10);
55|   Serial.println();
56|   Serial.print("Connecting to ");
57|   Serial.println(ssid);
58|   WiFi.begin(ssid, password);
59|   while (WiFi.status() != WL_CONNECTED) {
60|     delay(500);
61|     Serial.print(".");
62|   }
63|   timeClient.begin();
64| #ifdef MQTT_TLS
65|   #ifdef MQTT_TLS_VERIFY
66|     X509List *cert = new X509List(CERT);
67|     wifiClient.setTrustAnchors(cert);
68|   #else
69|     wifiClient.setInsecure();
70|   #endif
71| #endif
72|   Serial.println("WiFi connected");
73| }

Enable Certificate Verification on ESP8266 for MQTT

To begin with, to secure the configuration for the application of the ESP8266 module with the MQTT broker, one should enable the verification of the broker identity. To enable this uncomment, line 2 in the configuration part of the code looks like the following:

 1| #define MQTT_TLS 
 2| #define MQTT_TLS_VERIFY

If the define MQTT_TLS_VERIFY exists in the code, then the certificate’s validity for TLS encryption is checked. You can see in the setup_wifi function above, in lines 66 and 67, that trusted anchors in that case are set for the wifiClient.

In PC- based environments, there are root certificates, which are – as the name states – the roots of certificate trust paths. Therefore, by default, every communication which uses valid certificates from the root certificates is trusted. The following figure shows an example trust path for the website www.cedalo.com.

Principal of certificate trust chain shown as an example

Figure 2: Example of a certificate trust path with ISRG Root X1 root certificate

In the ESP8266, we need to store the public information of the trusted certificates so that the identity of the MQTT broker can be verified. In PC-based environments, storing hundreds of root certificates is no issue, but in an ESP8266 one, the storage (flash) has its limited. Consequently, you need to choose specific certificates to limit the need for storage.

Thus, the easiest option is to store the MQTT broker certificate or the certificate of the issuing CA. If you use the recommended trial setup for Pro edition for Eclipse Mosquitto, the corresponding certificate to trust is the Let’s Encrypt R3 intermediate certificate. At the same time, the sample application stores and provides it by default.

To check or change the correct certificate, which is used as a trust anchor in the ESP8266, view or edit the content in the include/certificate.h file, in the project folder. Also, be careful when changing the lines between BEGIN CERTIFICATE and END CERTIFICATE.

// (re)place the trusted X509 certificate for the tls connection below
// default below: Let's Encrypt R3
const char mqtt_broker_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
…
nLRbwHOoq7hHwg==
-----END CERTIFICATE-----
)EOF";

After any change in the main.cpp or certificate.h project files, start a recompilation and the creation of the firmware by using the command pio run in the terminal of the browser-based IDE or by clicking ‘build’ (if you use a local VSCode installation).

Possible Issues and Troubleshooting

Finally, it can be challenging to realize and debug applications created for SoC or µC successfully. That’s because for debugging, in most cases, you might need additional hardware, and access to, e.g., logs files or similar helpful things, which is limited or not possible due to a missing operating system environment on the ESP8266. The following table provides support and can help if any issues occur. Also, refer to the readme section in the sample code repository here, which shows how to monitor the serial output of the ESP8266.

Output / Behavior Possible reason / Fix
The code compilation fails. (IDE output “build failed”) Check the compiler’s error messages, which show line numbers and files where the error occurs. Try to fix the code.
The creation of the firmware fails. (IDE output “build failed”) The most common is here missing libraries or wrong paths. Here in the sample application, this error will be improbable.
In the serial output of the ESP8266, the Wi-Fi connection failed Check the PSK, Wi-Fi SSID and if the network is reachable and has sufficient signal strength (refer to the config section in the main code)
In the serial output of the ESP8266, the MQTT connection failed Check the username and password (if needed and set it on the MQTT broker). Is the address correct? Can the local (Wi-Fi) network reach the broker on the defined port?
Also, try first to connect w/o using TLS.
MQTT connection works only w/o using TLS Have you set the port correctly (1883 vs. 8883)?
Are the ports reachable (firewall settings in local network)?
Does the broker support TLS? (check with PC-based clients)
If TLS verification is enabled, check that the trusted certificate corresponds to the MQTT broker trust path. In case of doubts, use the broker certificate itself in the file certificate.h.
About the author

Dr. Andreas Schiffler is a research professor at the Technical University of Wuerzburg-Schweinfurt in the field of production and data technology in mechanical engineering. In addition to research topics related to 3D metal printing, Dr. Schiffler developed a Kubernetes cluster for the practice-oriented basics of IoT and Industry 4.0 as part of the student training. Before joining the university, he worked in different product development-related positions for Siemens AG and Schaeffler AG.

His hobbies and private activities are mixed to share practical knowledge on topics like home automation driven by MQTT protocol or using open-source CNC controllers for machine tools.

MQTT is the machine-to-machine connectivity protocol. It is an ideal IoT platform to connect multiple devices. In this project, we will connect an ESP8266 with MQTT broker. We will use cloud MQTT as our broker platform and Arduino IDE to program our ESP8266.

Like MQTT there are many other platforms available. But, cloud MQTT has a free plan option, so we can just create an account and use it. Using MQTT platform we can send a message to the device and can receive a message from the device.

What is MQTT?

MQTT stands for Message Queuing Telemetry Transport. It’s a system where we can publish and subscribe messages as a client. By using MQTT you can send commands to control outputs, read and publish data from sensors and much more. Therefore, by using MQTT you can establish communication between multiple devices. Using MQTT you can send a command with a client to control output or you can read data from a sensor and publish it to a client. There are two main terms in MQTT i.e. Client and Broker. Let’s discuss what actually a MQTT client and MQTT broker is:

MQTT Client: An MQTT client runs a MQTT library and connects to an MQTT broker over a network. Both publisher and subscriber are MQTT clients. The publisher and subscriber refer that whether the client is publishing messages or subscribing to messages.

MQTT Broker: The broker receives all messages, filter the messages, determine who is subscribed to each message, and send the message to these subscribed clients.

Components Required

  • NodeMCU
  • Cloud MQTT

Cloud MQTT Account Setup

To set up an account on Cloud MQTT navigate to its official website (www.cloudmqtt.com) and sign up using your email.

MQTT Account Setup for ESP8266

After login, click on ‘+ Create New Instance’ to create a new instance.

Create New Instance on MQTT Account for ESP8266

Now enter your instance name and select ‘Cute Cat’ in plan option.

Select Plan for MQTT Account

In new tab select region and click on ‘Review’.

Review MQTT Account Setup for ESP8266

Your instance is created and you can view your details like user and password.

Login to MQTT Account for ESP8266

Code Explanation

The complete code for Connecting ESP8266 with MQTT broker is given at the end. Here, we are using Arduino IDE to program ESP8266. First, install ESP8266WiFi and PubSubClient library.

PubSubClient library allows us to publish/subscribe messages in topics.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

Now declare some global variables for our WiFi and MQTT connections. Enter your WiFi and MQTT details in below variables:

const char* ssid = "WiFi Name"; // Enter your WiFi name
const char* password =  "WiFi Password"; // Enter WiFi password
const char* mqttServer = "m16.cloudmqtt.com";
const int mqttPort = 37181;
const char* mqttUser = "otfxknod";
const char* mqttPassword = "nSuUc1dDLygF";

In the setup function, it will check the WiFi, whether it is connected to network or not and print it on the serial monitor.

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
​​​​​    delay(500);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");

In the below, while loop function, it will connect to the MQTT server and will print it on the serial monitor. This process will run in a loop until it gets connected.

 while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
    if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
      Serial.println("connected"); 
    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

Now to check the setup function it will it will publish and subscribe a message on topic and for that it will use publish and subscribe method.

  client.publish("esp/test", "hello"); //Topic name
  client.subscribe("esp/test");

Now we will specify a call back function and in this function, we will first print the topic name and then received message.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);

  Serial.print("Message:");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);

Testing MQTT with ESP8266

Now to test the code upload this code into ESP8266 using Arduino IDE and open the serial monitor.

Receiving Message on MQTT using ESP8266

To subscribe and publish to MQTT topics, a Google Chrome application MQTTlens will be used. You can download the app from here.

Launch this app and set up a connection with MQTT broker. To setup, connection click on ‘connections’ and in next window enter your connection details from Cloud MQTT account.

Launch MQTTlens for Connecting with ESP8266

Save this connection, and  now you can subscribe and publish a message on your MQTT broker using ESP8266.

To subscribe or publish a message enter your topic name in subscribe and publish option and enter the default message. Your message will be shown on serial monitor as shown in the above image of the serial monitor.

Setup Account on MQTTlens

Hence, we have successfully connected the MQTT broker with ESP8266. Stay Tuned with us for more amazing IoT projects.

Code

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

 
const char* ssid = «WiFi Name»; // Enter your WiFi name
const char* password =  «WiFi Password»; // Enter WiFi password
const char* mqttServer = «m16.cloudmqtt.com»;
const int mqttPort = 37181;
const char* mqttUser = «otfxknod»;
const char* mqttPassword = «nSuUc1dDLygF»;

 
WiFiClient espClient;
PubSubClient client(espClient);

 
void setup() {

 
  Serial.begin(115200);

 
  WiFi.begin(ssid, password);

 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println(«Connecting to WiFi..»);
  }
  Serial.println(«Connected to the WiFi network»);

 
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);

 
  while (!client.connected()) {
    Serial.println(«Connecting to MQTT…»);

 
    if (client.connect(«ESP8266Client», mqttUser, mqttPassword )) {

 
      Serial.println(«connected»);  

 
    } else {

 
      Serial.print(«failed with state «);
      Serial.print(client.state());
      delay(2000);

 
    }
  }

 
  client.publish(«esp/test», «hello»); //Topic name
  client.subscribe(«esp/test»);

 
}

 
void callback(char* topic, byte* payload, unsigned int length) {

 
  Serial.print(«Message arrived in topic: «);
  Serial.println(topic);

 
  Serial.print(«Message:»);
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }

 
  Serial.println();
  Serial.println(«————————«);

 
}

 
void loop() {
  client.loop();
}

Понравилась статья? Поделить с друзьями:
  • Mr muscle для прочистки сливных труб инструкция
  • Mr hhop таблетки инструкция по применению
  • Mr fix 9h керамика инструкция по применению
  • Mr bruno капли для собак инструкция
  • Mr 5972 loctite инструкция по применению