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

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

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


Всем привет! В этой статье будет подробно рассказано и показано как буквально за 20 минут свободного времени настроить дистанционное управление модулем esp8266 с помощью приложения на Android по протоколу MQTT.

Идея дистанционного управления и мониторинга всегда будоражила умы увлеченных в электронике и программировании людей. Ведь возможность в любой момент времени получить или отправить нужные данные, не зависимо от своего местоположения, дает широкие возможности. В своих прошлых статьях ( Статья 1 и Статья 2) я пытался рассмотреть несколько доступных и относительно простых вариантах реализации дистанционного управления микроконтроллерами через интернет. Однако время и весь мир не стоит на месте – прогресс продолжает свое неумолимое движение вперед. За это небольшое время приобрел широкую популярность модуль esp8266 который благодаря низкой цене и встроенному wi-fi стал одним из основных составляющих «Умного дома».

На данный момент MQTT является передовым и наиболее популярным протоколом передачи данных между отдельными устройствами в рамках систем «Умного дома». Он обладает рядом преимуществ по отношению к другим протоколам:
— низкое потребление трафика;
— соединение между клиентом и сервером всегда открыто;
— не нагружает интернет канал;
— отсутствие задержек в передаче данных;
— удобная система подписок на топики;
Всё это дает возможность мониторинга и управления в режиме реального времени. Однако MQTT требует наличие своего собственного сервера, который выполняет роль посредника между клиентами сети. Тут есть два выхода либо создавать свой сервер либо использовать сторонние сервисы.

Описываемая система управления состоит из двух основных частей: сервера MQTT (он как правило один) и клиентов, которых может быть довольно много. В нашем случае в качестве клиентов будут выступать приложение на Android и сам модуль esp8266.

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

MQTT сервер.

В нашем случае мы будем использовать крайне удобный сервис www.cloudmqtt.com у которого есть бесплатный тарифный план (Cute Cat), который полностью покроет потребности для реализации небольшой собственной системы «умного дома».

Пройдём регистрацию на сайте и получаем необходимые данные для доступа к серверу. При настройке клиентов необходимо использовать обычный Порт ( без SSL и TLS).

Приложение на Android.

Наше приложение будет выступать в качестве пульта управления для микроконтроллера, а так же будет принимать и отображать всю получаемую информацию от esp8266.

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

Esp8266.

Модуль прошивается в среде программирования Arduino, однако хочу заметить что у модуля проблемы с прошивкой в последних версиях Arduino, поэтому рекомендую использовать версию 1.6.4.
Для примера к esp8266 подключены светодиод (5 пин) и датчик температуры ds18b20 (2 пин).
Так как для управления светодиода необходимо получать данные, то esp после подключения должно оформить подписку на соответствующий топик «test/led» иначе все отправленные данные пройдут мимо нашего микроконтроллера.
Для отправки данных температуры подписка не нужно, но при передаче значений температуры необходимо указывать топик в который эти данные пойдут.

Ниже приведен скетч с подробными комментариями.

Скетч Esp8266_mqtt.ino

// Светодиод подлкючен к 5 пину
// Датчик температуры ds18b20 к 2 пину

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

#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

const char *ssid = "AIRPORT"; // Имя вайфай точки доступа
const char *pass = "PASSWORD"; // Пароль от точки доступа

const char *mqtt_server = "server"; // Имя сервера MQTT
const int mqtt_port = 11140; // Порт для подключения к серверу MQTT
const char *mqtt_user = "Login"; // Логи от сервер
const char *mqtt_pass = "Pass"; // Пароль от сервера

#define BUFFER_SIZE 100

bool LedState = false;
int tm=300;
float temp=0;

// Функция получения данных от сервера

void callback(const MQTT::Publish& pub)
{
Serial.print(pub.topic()); // выводим в сериал порт название топика
Serial.print(" => ");
Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных

String payload = pub.payload_string();

if(String(pub.topic()) == "test/led") // проверяем из нужного ли нам топика пришли данные
{
int stled = payload.toInt(); // преобразуем полученные данные в тип integer
digitalWrite(5,stled); // включаем или выключаем светодиод в зависимоти от полученных значений данных
}
}

WiFiClient wclient;
PubSubClient client(wclient, mqtt_server, mqtt_port);

void setup() {

sensors.begin();
Serial.begin(115200);
delay(10);
Serial.println();
Serial.println();
pinMode(5, OUTPUT);
}

void loop() {
// подключаемся к wi-fi
if (WiFi.status() != WL_CONNECTED) {
Serial.print("Connecting to ");
Serial.print(ssid);
Serial.println("...");
WiFi.begin(ssid, pass);

if (WiFi.waitForConnectResult() != WL_CONNECTED)
return;
Serial.println("WiFi connected");
}

// подключаемся к MQTT серверу
if (WiFi.status() == WL_CONNECTED) {
if (!client.connected()) {
Serial.println("Connecting to MQTT server");
if (client.connect(MQTT::Connect("arduinoClient2")
.set_auth(mqtt_user, mqtt_pass))) {
Serial.println("Connected to MQTT server");
client.set_callback(callback);
client.subscribe("test/led"); // подписывааемся по топик с данными для светодиода
} else {
Serial.println("Could not connect to MQTT server");
}
}

if (client.connected()){
client.loop();
TempSend();
}

}
} // конец основного цикла

// Функция отправки показаний с термодатчика
void TempSend(){
if (tm==0)
{
sensors.requestTemperatures(); // от датчика получаем значение температуры
float temp = sensors.getTempCByIndex(0);
client.publish("test/temp",String(temp)); // отправляем в топик для термодатчика значение температуры
Serial.println(temp);
tm = 300; // пауза меду отправками значений температуры коло 3 секунд
}
tm--;
delay(10);
}

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

Видео с демонстрацией работы системы управления

Подробная видеоинструкция по настройке системы

Один из вариантов применения управления esp8266 через MQTT протокол

Управление светодиодной лентой через интернет

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

В архиве находятся скетч и все необходимые библиотеки для прошивки микроконтроллера скетчем из примера.
Обращаю ваше внимание, что библиотека ESP8266WiFi.h не входит в данный архив, она устанавливается через Boards manager в среде Arduino.

АРХИВ

MQTT сервер — www.cloudmqtt.com

Ссылка на приложение IoT MQTT Dashboard — play.google.com/store/apps/details?id=com.thn.iotmqttdashboard&hl=ru

Всем спасибо за внимание.

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

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

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

  • Дистанционный контроль и управление вашими устройствам, причем не только в локальной сетке, но и из любой точки планеты, где есть интернет
  • Удаленное управление реле и нагрузкой, например включение и отключение освещения или котла
  • Обратный контроль состояния нагрузки с устройства – получило ли оно вашу команду или нет
  • Удаленный мониторинг логических состояний на входах микроконтроллера, что позволяет создать простенькую охранную систему например
  • Удаленный мониторинг температуры и влажности

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

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

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

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

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

Осторожно – многа букав…

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


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

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

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


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

  • Добавьте #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 протокола. 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:PlatformIOlibs. Создаем такой каталог, вручную скачиваем архив с GitHub, и вручную распаковываем содержимое в только что созданный каталог. Всё как и в предыдущем случае, только целевая папка изменилась. Теперь нам нужно “подключить” каталог C:PlatformIOlibs к нашему проекту через параметр lib_extra_dirs. Для этого потребуется указать только каталог lib_extra_dirs = C:PlatformIOlibs, все вложенные библиотеки не более одного уровня вложенности “подхватятся” автоматически. Открываем файл 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

На этом пока всё, до встречи на сайте и на dzen-канале!

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

Платы ESP8266 стали очень популярны из-за своей низкой цены и совместимостью с Arduino IDE. Для решения задач устройств «Умного дома» они просто идеальны. ESP требует только подключения питания, а сбор и отправку данных она может осуществлять по Wi-Fi через домашний роутер.

Одним из популярных открытых протоколов связи для Умного дома является MQTT. Его основа — обычные http(s) сокет соединение. Протокол по сути дела описывает лишь язык, а не способ доставки данных. MQTT требует наличие сервера — брокера, который объединяет подключенные устройства в сеть. Сами же устройства при подключении подписываются на топики в которых отсылаются данные и брокер отсылает только те топики устройству, которые ему нужны.

ESP + MQTT как основа умного дома

Получить к возможность подключиться к брокер серверу можно двумя способами: воспользоваться бесплатными MGTT брокерами или поднять свой собственный сервер (путь самурая).

Первый вариант самый простой. Из бесплатных я бы рекомендовал cloudmqtt.com. Там есть ограничения по количеству устройств и запросов, но для домашнего использования этого более чем достаточно. При регистрации выдается логин, пароль, сервер к которому нужно делать коннект, тип соединения (с/без ssl).

Свой брокер поднять не на много сложнее. Дольше уйдет время на настройку окружения, чем на поднятие брокера. Сделать это можно на nodeJs с npm пакетом mqtt. Примеры можно посмотреть на сайте расширения. Но это уже выходит за рамки данной статейки.

Вернемся к нашей ESP. Из этих устройств мы соберем периферию по сбору данных. Для реализации устройств удобно использовать модуль ESP8266 ESP-12. Он имеет встроенный стабилизатор на 3.2 вольта и множество свободных GPIO для подключения периферии. Цена так себе, если паяльник не вызывает страха, то можно замутить на 01/07 модулях. На али такие меньше чем за 2$ за штуку можно отхватить.

ESP + MQTT как основа умного дома

Настройка Arduino IDE

Для прошивки ESP будем использовать Arduino IDE. Просто так взять и залить скетч нельзя. Для начала нужно подготовить настроить IDE для работы с платой ESP.

Запускаем наше IDE и идем в Файл — Настройки.

ESP + MQTT как основа умного дома

Прописываем ссылку на менеджер плат http://arduino.esp8266.com/stable/package_esp8266com_index.json
Теперь выбираем Инструменты — Плата — Менеджер плат. В конце списка мы увидим esp8266 by esp8266 Community.

ESP + MQTT как основа умного дома

Выбираем последнюю версию и жмем Установить.

Esp прошивает на другой скорости чем чипы Atmega и по тому нам нужно в первую очередь изменить скорость uart. Инструменты — Upload Speed:-115200:

ESP + MQTT как основа умного дома

Не забываем задать тип платы: Инструменты — Generic ESP8266 Module.

ESP + MQTT как основа умного дома

Ну и все, наше IDE готово загружать скетч в ESP. Если вы счастливый обладатель ESP8266 ESP-12 — переключаем в режим программирования, тыкаем usb, выбираем COM порт и погнали. Если плата попроще (ESP8266-01), не беда. Подключаем GPIO0 на землю, USB-UART «свисток», подаем стабильные 3.2 вольт и наша дешевая плата тоже готова принять скетч. Распиновка подключения для 01:

ESP + MQTT как основа умного дома

Скетч для MQTT

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

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

const char *ssid = "xxxxxx"; // Имя роутера
const char *pass = "xxxxxx"; // Пароль роутера

const char *mqtt_server = "m13.cloudmqtt.com"; // Имя сервера MQTT
const int mqtt_port = 14483; // Порт для подключения к серверу MQTT
const char *mqtt_user = "xxxxxx"; // Логи для подключения к серверу MQTT
const char *mqtt_pass = "xxxxxx"; // Пароль для подключения к серверу MQTT

const int led = 5; // диод на плате

#define BUFFER_SIZE 100

int tm = 300;
float temp = 0;

WiFiClient wclient; 
PubSubClient client(wclient, mqtt_server, mqtt_port);

void setup() {
  Serial.begin(115200);
  delay(10);

  Serial.println();
  Serial.println();

  pinMode(led, OUTPUT);
}

// Функция отправки показаний
void refreshData() {
  if (tm == 0) {
    time = millis();
    client.publish("test/1", time);
    tm = 3000; // пауза меду отправками 3 секунды
  }
  tm--;
  
  delay(1); 
}

// Функция получения данных от сервера
void callback(const MQTT::Publish& pub)
{
  String payload = pub.payload_string();
  String topic = pub.topic();
  
  Serial.print(pub.topic()); // выводим в сериал порт название топика
  Serial.print(" => ");
  Serial.println(payload); // выводим в сериал порт значение полученных данных

  // проверяем из нужного ли нам топика пришли данные 
  if(topic == "test/2")
  {
     Serial.println("test/2 OK"); // выводим в сериал порт подтверждение, что мы получили топик test/2
  }
}

void loop() {
  // подключаемся к wi-fi
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);
    
    if (WiFi.waitForConnectResult() != WL_CONNECTED) return;
    Serial.println("WiFi connected");
  }
  
  // подключаемся к MQTT серверу
  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      Serial.print("Connecting to MQTT server ");
      Serial.print(mqtt_server);
      Serial.println("...");
      if (client.connect(MQTT::Connect("arduinoClient2").set_auth(mqtt_user, mqtt_pass))) {
        Serial.println("Connected to MQTT server ");
        client.set_callback(callback);
        // подписываемся под топики
        client.subscribe("test/1");
        client.subscribe("test/2");
      } else {
        Serial.println("Could not connect to MQTT server"); 
      }
    }
    
    if (client.connected()){
      client.loop();
      refreshData();
    }
  
  }
}

Код выполняет соединение к Wi-Fi точке доступа в квартире, через интернет соединяется к брокер серверу. Подписывается на топики test/1 и test/2. Отсылает раз в 3 секунды значение системного счетчика. В общем, ничего лишнего.

Брокер сервер работает таким образом, что на устройство будут отправлены только те топики на которое он подписан. Таким образом, мы не перегружаем сеть лишними данными.

Настройка клиента на телефоне

Скачиваем приложение в маркетплейсе Android/iPhone — IoT MQTT Dashboard или любое аналогичное. Они все работают одинаково.

В запущенном приложении нужно задать хост, логин, пароль, порт брокер-сервера.

ESP + MQTT как основа умного дома

Далее мы попадаем на страницу подписок. Задаем наши два топика «test/1» и «test/2» — теперь мы всегда будем видеть последние присланные значения этих топиков. Это может быть температура воздуха или влажность земли в теплице. Есть поддержка передачи изображения в base64, но это уже совсем другая история.

На втором экране мы можем создать управляемые контролы: кнопки, переключатели, выбор цвета, мультиселек, поле ввода текста. Добавляем переключатели и вбиваем в них наши топики «test/1» и «test/2». Запускаем и видим как переключение топиков сразу же вываливает в консоль UART микроконтроллера ответы. Колдунство!

ESP + MQTT как основа умного дома

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

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.

Вы уже поигрались с ESP8266 и теперь вам хочется большего? В этой статье я покажу основные приемы передачи данных куда только возможно. Построим надежную домашнюю WiFi сеть, в которой куча ESP8266 не будет мешать вашим высокоскоростным гаджетам. Мы соединим ESP8266 используя прошивку, сделанную в Arduino IDE, c MQTT брокером mosquitto, будем посылать электронную почту с ESP8266, передадим данные на ThingSpeak, CloudMQTT, будем получать PUSH уведомления на смартфон, ESP8266 будет дергать своими GPIO по команде со смартфона без HTTP серверов и проброски портов. ESP8266 будет отчитываться о действиях в собственном твиттер-аккаунте. Интересно? Если да то, как принято говорить на хабре, добро пожаловать под кат — там вас ждет громадное количество кликабельных скриншотов, полезных ссылок, видео и самый минимум линуксовых команд в терминале под OpenWRT, с которыми справятся даже люди абсолютно не знакомые с linux.

Содержание

Делаем отдельную WiFi сеть для IoT

Настраиваем MQTT брокер mosquitto

Настройка MQTT-Spy

Пишем прошивку в Arduino IDE, подключаем ESP8266 к mosquitto

Устанавливаем и настраиваем mqttwarn

Передаем данные с ESP8266 на ThingSpeak

Передаем данные c ESP8266 по EMAIL

Передаем с ESP8266 на смартфон PUSH уведомления

Управляем ESP8266 GPIO со смартфона

ESP8266 публикует в Twitter состояние GPIO

Поднимаем Dynamic DNS и делаем bridge с CloudMQTT

Делаем отдельную WiFi сеть для IoT

Вы, наверное, уже заметили, что даже один или два модуля ESP8266 с кривым софтом на борту могут уронить вашу домашнюю WiFi сеть и ваши домашние будут ругать провайдера за неповоротливый интернет, пока вы нервно курите в сторонке. Что уж там говорить, если вы собираетесь половину ваших электрических розеток перевести на WiFi управление. Также существует неудобство и в том, что для взаимодействия с ESP8266 вам периодически приходится поднимать на своем рабочем компе то HTTP сервер, то еще что-нибудь. Вот эти две проблемы мы и постараемся решить за один раз (просьба не упоминать про зайцев). Подключим дополнительную WiFi точку доступа на отдельном радио канале специально для наших экспериментов сейчас и для будущей домашней IoT сети в ближайшем будущем.

Мы будем использовать не обычную WiFi точку доступа из ближайшего магазина и не народный MR3020, а для того, чтобы решение получилось максимально доступно для широкого круга умельцев, а не только для линуксоидов, которые не признают ничего, кроме командной строки в терминале, мы возьмем, практически за те же деньги, роутер от китайского стартапа Gl.iNET, созданный специально для DIY. Вот наша партнерская ссылка для покупки этого устройства на Aliexpress для тех, кто готов поддержать наш сайт одновременно экономя на покупках с нашим партнером Aliexpress.

Я не буду здесь описывать все преимущества этого роутера, распаковывать его из коробки у вас на глазах — для этого уже давно есть неплохие обзоры (вот на муське и еще один).  Этот роутер подходит лучше других для нашей задачи потому, что имеет на борту 64Мб оперативки, а нагрузить мы его хотим по полной программе :) Еще приятная новость в том, что на нем предустановлена прошивка OpenWRT, что уменьшает вероятность танцев с бубном для тех, кто не знаком с линуксом вообще.

Для тех, кто побаивается линуксов вообще и OpenWRT в частности, сообщаю, что мы будем работать c OpenWRT в русифицированном WEB интерфейсе. Сам я не обладаю большим опытом работы в linux и фанатом командной строки не являюсь, поэтому и вам постараюсь показать простые приемы, которые, возможно, и не блещут изяществом.

Русифицированный интерфейс OpenWRT

Русифицированный интерфейс OpenWRT

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

Свободная и занятая память при работе всех нужных нам приложений

Свободная и занятая память при работе всех нужных нам приложений

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

Обратите внимание, что у Gl.iNET есть две модели роутеров: 6408A и 6416A, которые имеют на борту 8 и 16 Мб флеш памяти соответственно. Сейчас разницы в цене у них практически нет, так что постарайтесь взять 16-ти мегабайтную модель. Если вы будете повторять все, что будет описано в данной статье, то все равно придется подключать USB флешку для раcширения overlay раздела, потому что размер всех установленных пакетов у меня уже перевалил за 50 Мбайт.

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

Однако в этом замечательном роутере есть и ложка дегтя. При отличной схемотехнике и продуманно скомпонованном железе, китайцы собрали наполовину китайскую OpenWRT, которая обращается к репозитарию пакетов на сайте производителя с битыми ссылками и устаревшими сборками. Кроме того, буквально пару недель назад, вышла новая версия OpenWRT — Chaos Calmer 15.05-rc1, которая включает последнюю версию 1.4.2 MQTT брокера mosquitto в которой исправлены баги именно в тех функциях, которые мы будем активно использовать.

Поэтому, особо не парясь, через веб интерфейс будем заливать новую прошивку. Сначала определите модель (по объему флеш памяти) и скачайте с официального сайта OpenWRT либо openwrt-15.05-rc1-ar71xx-generic-gl-inet-6408A-v1-squashfs-sysupgrade.bin либо openwrt-15.05-rc1-ar71xx-generic-gl-inet-6416A-v1-squashfs-sysupgrade.bin и обновитесь. Процесс обновления прошивки я описывать не буду — это легко гуглится, да и эта статья об ESP8266, а не про OpenWRT. Для тех, кто вообще не знаком с OpenWRT, скажу, что нужно искать описание обновления прошивки с OpenWRT на OpenWRT через веб интерфейс самой OpenWRT без сохранения настроек. Во как.

Если что-то пойдет не так — не отчаивайтесь! Ищите в инете инструкцию по прошивке через консоль. Разбираете роутер, подключаете USB-TTL, питание берете внешнее, подключаетесь к роутеру витой парой, поднимаете у себя на компе tftp сервер. Процедура простая и быстрая, дольше будете tftp искать и настраивать. Кстати, тоже самое придется сделать, если в дальнейшем не примонтируете флешку для увеличения доступного места и наустанавливаете кучу пакетов, которые займут все свободное место — OpenWRT в таком случае может и не стартануть. Сам попался как-то раз на такую удочку :)

Есть одно неудобство — после установки чистая OpenWRT имеет IP адрес 192.168.1.1, который в нашем случае (установка второго домашнего WiFi роутера) уже обычно бывает занят старым роутером, который нам раздает интернет. Поэтому, для первоначальной настройки, придется физически отключиться от вашей локальной сети и подключиться проводом к порту LAN нового маршрутизатора.

Далее мы будем строить такую сеть:

IoT Home Network

ESP8266 IoT Home Network

Как видите, мы не будем вообще использовать функции маршрутизации IP пакетов, наш роутер будет работать в качестве Ethernet моста в той же подсети, что и остальные устройства. Это позволит нормально функционировать протоколу mDNS без пробрасывания UDP портов, отменит необходимость прописывать маршруты из локальной сети в сеть IoT, и при этом мы будем использовать DHCP сервер вашего основного маршрутизатора. Однако, самое главное, что мы получим в результате: две независимые WiFi сети. Это позволит нам переводить ESP8266 в режим 802.11b или 802.11g для снижения энергопотребления в случаях, когда не требуется высокая скорость подключения без ущерба в скорости для остальных WiFi устройств, требовательных к скорости подключения к интернет.

Обсуждение вопросов настройки OpenWRT на нашем формуме

В итоге должно получиться что-то вроде этого (кстати, приколитесь в каком радиовакууме я живу)

WiFi

WiFi

Gl.iNET+OpenWRT

Gl.iNET+OpenWRT

Настраиваем OpenWRT

Этот раздел я писал по памяти, за точность и правильную последовательность действий не ручаюсь. В ваших интернетах полно статей как это сделать. Если вы обнаружили неточность или ошибку то, пожалуйста, сообщите мне об этом, я поправлю статью.

Перед отключением от локальной сети и интернета (напоминаю, что наш OpenWRT роутер будет иметь адрес 192.168.1.1), я рекомендую приготовить следующие программы:

Любой SSH клиент, мне наиболее симпатичен putty. Желательно погуглить про SSH, putty и ключи и сгенерировать собственный ключ — это существенно упростит вам жизнь, но можно обойтись и без этого. Если вы пользуетесь хостингом или уже имеете свой домашний выделенный linux сервер, то такой ключ у вас, наверняка, уже есть.

Любой SFTP клиент, мне больше нравится Far Manager — мы будем редактировать файлы на OpenWRT не через редактор vi, который встроен в OpenWRT, но абсолютно неудобен для обычных людей. Хотя, наверное, линукс гуру со мной не согласятся.

Мне было проще подключиться к роутеру через USB-TTL и все настроить в терминале

Первым делом установим соединение с интернетом:

ifconfig brlan 192.168.1.100

route add default gw 192.168.1.1 brlan

echo «nameserver 8.8.8.8» &gt;&gt; /etc/resolv.conf

 Проверяем интернет

Если яндекс пингуется, то жмем CTRL+C

Задаем пароль root

Подключаемся по SSH к 192.168.1.100, попадаем в командную строку терминала. При возникновении проблем — гуглим.

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

Ждем пока все подгрузится, затем

opkg install luci

/etc/init.d/uhttpd start

Люся — наша лучшая подруга! Запускаем браузер, заходим на 192.168.1.100 и видим приглашение OpenWRT. Отлично, теперь установим русскоязычный интерфейс.

Идем по меню System — Software — Filtr вводим -ru жмем поиск. Переключаем вкладку на доступные пакеты и ищем luci-i18n-base-ru — вот его и устанавливаем. Обновите страницу после установки (не торопитесь — требуется некоторое время для скачивания и установки пакета), всё — русификация завершена — можете обновить страницу.

Сейчас нужно, чтобы люся сама загружалась при старте роутера — идем в Система — Загрузка и ищем uhttpd — если на кнопке красный крестик и надпись Отключено, то жмем по нему — всё, автозапуск включен.

Дальше я рекомендую настроить Far Manager, а точнее его встроенный плагин NetBox.

far netbox

far netbox

Для того, чтобы мы могли передавать/принимать файлы с OpenWRT через sftp устанавливаем пакет

Фаром подключаетесь к OpenWRT, идете в /etc/config/firewall и в политиках зон все REJECT заменяете на ACCEPT, потому что LAN и WAN у этого маршрутизатора находятся в нашей домашней сети, которой мы доверяем.

Дальше все просто: с помощью русскоязычного меню настраиваете WiFi, проверяете настройки br-lan интерфейса (остальные лучше не трогать, но только если вы действительно знаете что делаете). Можете прописать DNS сервера вашего провайдера в качестве вторичных и указать в качестве первичного DNS адрес вашего главного маршрутизатора 192.168.1.1

Перегрузите через меню OpenWRT, убедитесь что все работает, интернет есть и т.п. Подключитесь с ноутбука или смартфона к вашей сети IoT по WiFi, проверьте инет.

Новичкам, которые еще не знают что им может понадобится, лучше сразу увеличить размер файловой системы с помощью USB флешки — лучше взять современную (=быструю) любого размера. Подключение флешки к OpenWRT легко гуглится, так что вы без проблем с этим вполне справитесь. Для облегчения задачи флешку лучше отформатировать у друга на linux машине. Если у вас нет такого друга и возникнут проблемы при разбитии флешки на разделы через консоль в OpenWRT, то можете установить VirtualBox и Extension Pack к нему, запустить linux в виртуальной машине и там в графической оболочке с помощью gparted разбить флешку на разделы. Такая виртуальная машина с линуксом на борту вполне потом может вам сгодится для экспериментов в linux, сборки собственной прошивки для OpenWRT из исходников — я так делал на виртуальной машине с одним гигом памяти — компилировалось всю ночь :)

После того, как примонтируете флешку на overlay жмите

Просто убедимся, что места у нас полно. Вот у меня для примера свободно более 500 мегов.

root@OpenWrt:~# df -h

Filesystem                Size      Used Available Use% Mounted on

rootfs                  609.0M     51.1M    513.4M   9% /

/dev/root                 2.3M      2.3M         0 100% /rom

tmpfs                    29.8M      1.2M     28.6M   4% /tmp

/dev/sda3               609.0M     51.1M    513.4M   9% /overlay

overlayfs:/overlay      609.0M     51.1M    513.4M   9% /

tmpfs                   512.0K         0    512.0K   0% /dev

root@OpenWrt:~#

Сейчас можно не скупиться и поставить все, что потребуется.

Идем в Система — Программное обеспечение, фильтруем mc, устанавливаем замечательный файловый менеджер, чтобы потом не делать файловые операции из командной строки.

Еще можно установить htop — отличная утилита, интерактивно показывающая загрузку системы и использование памяти

Да хоть и mysql-server, если вам требуется запись в БД ваших данных. В общем, тут уже все индивидуально.

На этом первоначальная настройка OpenWRT завершена.

Настраиваем MQTT брокер mosquitto

Немного расскажу по-простому о протоколе MQTT. Представьте интернет-форум вроде нашего. В нем есть темы (топики). Если вас интересует какой-то топик, то вы на него подписываетесь и вам приходят уведомления об изменениях. Также вы можете публиковать свои посты в топиках, такие уведомления придут и тем, кто подписан на топик, в котором вы опубликовали пост. Топики многоуровневые. Точно также и в MQTT — топики, подписка, публикация. Если вы публикуете в топик, которого не существует, то он создается и становится точно таким-же по свойствам, что и другие. Все это справедливо, если у вас есть права на чтение и/или запись конкретного топика или всех.

Устанавливаем mosquitto через Система — Программное обеспечение, включаем автозапуск. Можно установить все пакеты, у которых в названии есть mosquitto и нет nossl.

Через FarManager или vi редактируем файл /etc/mosquitto/mosquitto.conf

Ищем раздел, где log_dest и добавляем ниже строку

Аналогично делаем

log_facility 5

log_type debug

log_type error

log_type warning

log_type notice

log_type information

Позаботимся о безопасности даже если вам это кажется не нужным (в примерах далее будут прописаны пользователи и пароли и не будут использованы анонимные подключения)

password_file /overlay/mosquitto/users.list

acl_file /overlay/mosquitto/mosquitto.acl

Сохраняем mosquitto.conf

Теперь создадим необходимые каталоги с помощью mc или командной строки

cd /overlay

mkdir mosquitto

cd mosquitto

Для создания пользователей и генерации паролей необходимо установить пакет mosquitto-client. После установки используйте утилиту mosquitto-passwd. Или можете применить грязный хак. Скачиваем win версию mosquitto к себе на комп и с помощью mosquitto_passwd.exe создаем пользователей. Я эту работу сделал за вас, поэтому просто скопируйте эту строчку в пустой файл /overlay/mosquitto/users.list

test:$6$5Prq6fKi/BKhXVd+$SK2AYMVcMUKP94nzkZF3YIy6SXQhA5HBjDM/5n0X07YbIVPJP8Mnl4YGlRDkyWxSWs1mnxhP+CEzw9xvtV6F/Q==

В одну строку без переносов. Это мы определили пароль test пользователю test. Еще создаем файл /overlay/mosquitto/mosquitt.acl следующего содержания

Это мы даем права на чтение и запись юзеру test на все топики. Подробнее о всех командах файла конфигурации и настройке прав смотрите в документации.

Полный файл конфигурации mosquitto.conf

Все готово к запуску mosquitto — включаем его в автозагрузке и запускаем. Теперь надо проверить как он работает.

Обсуждение процесса настройки mosquitto на нашем форуме

Настройка MQTT-Spy

Для общения с любым mqtt брокером есть отличная программа mqtt-spy единственным недостатком которой можно назвать лишь то, что она требует наличия установленной Java 8.20 и выше. Программа mqtt-spy на потребуется только на период отладки и в рабочей системе будет уже не нужна. JAR файл mqtt-spy просто скачиваем на рабочий стол в пустую папку и запускаем обычным двойным кликом. По умолчанию mqtt-spay автоматически подключается к тестовому серверу iot.eclipse.org, можете поэкспериментировать и с ним, но лучше сразу подключимся к нашему mosquitto. В меню Connections выбираем New connection. Connection Name уже заполнено — можно оставить как есть, но я предпочту исправить на OpenWRT. Ниже на вкладке Connectivity в поле Server URI(s) вводим IP адрес нашего маршрутизатора и порт mosquitto по умолчанию, т.е. 192.168.1.100:1883 Ниже сгенерировался Client ID — можно оставить как есть, или ввести что-то свое. Следует заметить, что стандарт MQTT требует уникальный ClientID у каждого подключенного клиента. Рекомендую так же отметить галочкой Reconnect on failure. На вкладке Security вводим логин и пароль test и test. Жмем Apply и Open Connection. Если все прошло гладко, то вы увидите, что появилась зеленая вкладка с названием нашего соединения OpenWRT. Цвет вкладки означает состояние соединения: красный — отключено, желтый — соединяемся, зеленый — подключено. Забегая вперед скажу, что после отключения/подключения не забывайте переподписываться на топики. Переключаемся на нашу новую вкладку OpenWRT. Далее мы видим 4 группы пока еще пустых полей:

  1. Publish message — для публикации топиков
  2. Define new subscribtion — подписка на топики
  3. Вкладка All в которой мы увидим топики, на которые подпишемся
  4. Ниже увидим сообщения из топиков, на которые мы подписались.

Для начала подпишемся на все топики. В поле Define new subscribtion вводим единственный символ # и жмем Subscribe. Должна появиться вкладка #. Итак мы подписаны на все топики, теперь попробуем что-либо опубликовать. В верхнее поле Publish message — Topic вводим название нашего топика, например esp8266, а в поле Data вводим Hello world! и жмем Publish. Если все сделали правильно, то внизу, там где мы видим топики, на которые подписаны мы должны увидеть продублированное наше сообщение, как на скриншоте

mqtt-spy hello world

mqtt-spy hello world

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

Обсуждение mqtt-spy на нашем форуме

Пишем прошивку в Arduino IDE, подключаем ESP8266 к mosquitto

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

После установки Arduino IDE подключите библиотеку PubSubClient и залейте мой тестовый скетч mqtt.ino, откройте его в Arduino IDE, поправьте SSID и пароль WiFi сети, настроенной ранее на OpenWRT и заливайте в модуль. Если у вас все получилось, то в mqtt-spy вы увидите приходящие пакеты с ESP8266

esp8266 передает данные mosquitto

esp8266 передает данные mosquitto

Скетч отправляет пакет каждые 10 секунд — это удобно для отладки — не надо долго ждать. Если его настойчивость вас раздражает, то можете сами все поправить. Скетч предназначен только для демонстрации: его код я слепил из примера Ивана Грохоткова (igrr, автор Arduino IDE для ESP8266) и контрибьютера библиотеки PubSubClient — Imroy. Скетч тестировался мной сутками на Arduino IDE 1.6.4-758-ga194024 и PubSubClient версии 1.9, проявив завидную стабильность и надежность. Оставьте модуль ESP8266 включенным — пускай шлет данные в mosquitto — нам они скоро понадобятся.

Для отладки скетчей я использую свой ESPlorer даже не потому, что я его сам написал и поэтому очень люблю, а так совпало, что у него в терминальном окне подсветка синтаксиса в стиле LUA, так что простой текстовый вывод в терминале красиво подсвечивается. Мне, по крайней мере, он нравится много больше встроенного в Arduino IDE терминала.

esplorer mqtt

esplorer mqtt

Вообще, эту статью я начал писать еще пару месяцев назад, но столкнулся с проблемами нестабильности в ранних версиях, библиотека активно развивалась и я бросил это дело до лучших времен, которые вот сейчас и настали.

Точно такого же клиента, в принципе, можно слепить и на NodeMCU, но памяти останется меньше и придется делать на какой-то старой версии, потому что в актуальной прошивке mqtt клиент сломан при подписке более чем на один топик.

Все отлично, идем дальше.

Устанавливаем и настраиваем mqttwarn

Сейчас мы установим прекрасный пакет mqttwarn, который позволяет передавать данные c любого mqtt брокера практически куда угодно. Кроме того, что было анонсировано в начале этой статьи он еще умеет передавать данные в Google Docs, Asterics, FreeSwitch, pastebin — список просто огромен и может быть дополнен, если написать плагин для нового сервиса.

Для начала необходимо установить python и модули к нему. Помните — никакой командной строки — идем в меню люси Система — Программное обеспечение, фильтруем python и устанавливаем следующие пакеты:

python

pythondistutils

pythonemail

pythonlogging

pythonncurses

pythonopenssl

pythonpip

и дополнительно

Скачиваем с гитхаба mqttwarn к себе на компьютер, распаковываем и с помощью Far Manager заливаем в каталог /overlay/mosquitto файл mqttwarn.py и полностью папку с плагинами services.

В mqttwarn не оказалось стартового скрипта для OpenWRT — мне пришлось написать его самому и сделать pull request, так что теперь он есть.

Копируем файл с локального компьютера /etc/OpenWRT.init на маршрутизатор под именем mqttwarn в каталог /etc/init затем через mc делаем File — ChMod и отмечаем галочками три пункта execute/search так чтобы справа получилось число 100755. В люси Система — Загрузка и включаем автозагрузку mqttwarn. Запускать этот сервис пока не нужно.

OpenWRT init

OpenWRT init

Далее создаем в /overlay/mosquitto файл mqttwarn.ini следующего содержания:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

[defaults]

hostname     = ‘localhost’

port         = 1883

username     = test

password     = test

clientid     = ‘mqttwarn’

lwt      = ‘clients/mqttwarn’

skipretained = False

cleansession = True

# MQTTv31 = 3   (default)

# MQTTv311 = 4

protocol     = 3

; logging

logformat = ‘%(asctime)-15s %(levelname)-5s [%(module)s] %(message)s’

logfile   = ‘mqttwarn.log’

; one of: CRITICAL, DEBUG, ERROR, INFO, WARN

loglevel     = DEBUG

; name the service providers you will be using.

launch = file, log, instapush, smtp, http, twitter

[config:file]

append_newline = True

targets = {

    ‘data’      : [‘/overlay/mosquitto/mqtt-data.log’],

    ‘mqttwarn’  : [‘/overlay/mosquitto/mqttwarn.err’],

    }

[config:log]

targets = {

    ‘info’   : [ ‘info’ ],

    ‘warn’   : [ ‘warn’ ],

    ‘crit’   : [ ‘crit’ ],

    ‘error’  : [ ‘error’ ]

  }

; special config for ‘failover’ events

[failover]

targets = log:error, file:mqttwarn

Предварительная настройка mqttwarn готова, теперь конфигурируем сервисы.

Обсуждение mqttwarn на нашем форуме

Передаем данные с ESP8266 на ThingSpeak

Если у вас еще нет аккаунта регистрируемся на thingspeak.com, создаем канал с произвольным именем, в канале задаем произвольные названия для Field1 и Field2. Тут же получаем Write API Key. Добавляем в /overlay/mosquitto/mqttwarn.init

[config:http]

timeout = 60

targets = {

                #method     #URL               # query params or None          # list auth

  ‘thingspeak’ : [ «get», «http://api.thingspeak.com/update?key=ВАШ API KEY&amp;field1={micros}&amp;field2={counter}», None, None ]

  }

[/ESP8266/DATA]

targets = http:thingspeak

Не забудьте вставить ваш Write API Key.

Теперь запускаем через люси Система — Загрузка — mqttwarn Запустить и смотрим графики на ThingSpeak. Через некоторое время там начнут появляться наши данные.

ESP8266+Mosquitto+mqttwarn+ThingSpeak

ESP8266+Mosquitto+mqttwarn+ThingSpeak

Если данных нет, то смотрите /overlay/mosquitto/mqttwarn.log и /overlay/mosquitto/mqttwarn.err и проверяйте настройки еще раз.

Передача данных через HTTP GET и POST запросы — это наиболее универсальное средство подключения к удаленным сервисам для передачи данных с ESP8266. Аналогичным образом вы можете настроить передачу на narodmon и любые другие сервисы. Делитесь своими успехами в специальной теме mqttwarn

Передаем данные c ESP8266 по EMAIL

Идем на mail.ru, регистрируем новую почту. Мне повезло — адрес esp8266@mail.ru оказался еще свободным :)

Добавляем в mqttwarn.ini

[config:smtp]

server    =  ‘smtp.mail.ru:25’

sender    =  «MQTTwarn «

username  =  esp8266@mail.ru

password  =  xxxxxxxxxxxxxxxx

starttls  =  True

targets = {

    ‘notify’     : [ ‘4refr0nt@gmail.com’ ]

    }

Подправляем секцию [/ESP8266/DATA]

[/ESP8266/DATA]

targets = http:thingspeak, smtp:notify

Перезагружаем mqttwarn и получаем каждые 10 секунд по письму :)

Передаем с ESP8266 на смартфон PUSH уведомления

Регистрируемся на сервисе instapush, делаем все по этой инструкции, кроме пункта 4. В пункте 2 Application Title — ESP8266, Domain — например, esp8266.ru В пункте 3 указываем в поле Event Title: alerts, в поле Trackers сначала вводим object и, не нажимая Enter, жмем на клаве TAB, затем сюда же вводим action и снова TAB, в поле Push Message вводим {object} — {action} далее кликаем Add Event. Идем Dashboards — Apps, кликаем по нашему приложению, жмем +Add Events, добавляем в Event Title — gpio, Trackers — status и жмем TAB, в Push Message вводим Status {status} далее кликаем Add Event. В итоге должно получиться вот так

instapush

instapush

Из вкладки Basic Info копируем AppID и AppSecret и в mqttwarn.ini добавляем

[config:instapush]

appid = ‘xxxxxxxxxxxxxxxxxxxxxx’

appsecret = ‘yyyyyyyyyyyyyyyyyyyyyyyyyyyyy’

targets = {

             # event   # tracker

  ‘alerts’ : [ ‘alerts’, {«object»:«counter», «action»:‘{counter}’}],

  ‘gpio’   : [ ‘gpio’  , {«status»:‘{status}’}]

  }

Подправляем секцию [/ESP8266/DATA]

[/ESP8266/DATA]

targets = http:thingspeak, smtp:notify, instapush:alerts

На смартфон устанавливаем мобильное приложение

AppStore     AndroidStore

Залогиниваемся в мобильном приложении, перезагружаем mqttwarn и наслаждаемся уведомлениями, которые прилетают каждые 10 секунд :)

Adroid Instapush

Adroid Instapush

Управляем ESP8266 GPIO со смартфона

Идем на молодой «идиотский» стартап www.dioty.co регистрируемся, жмем Get Started и получаем данные облачного MQTT брокера

DIoTY.co

DIoTY.co

Построим бридж с нашего mosquitto на облачный MQTT DIoTY.

Добавляем в /etc/mosquitto/mosquitto.conf (префиксы меняете на свои)

connection dioty

address mqtt.dioty.co:1883

topic ESP8266/CONTROL/# in 0 / /4refr0nt@gmail.com/

topic ESP8266/STATUS/# out 0 / /4refr0nt@gmail.com/

bridge_attempt_unsubscribe true

notifications false

start_type automatic

remote_username ваш логин на DIoTY

remote_password ваш пароль, который пришел в письме

Перезапускаем mosquitto, идем в люси Статус — Системный журнал и ищем в логах что-то вроде этого

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Bridge local.OpenWrt.dioty doing local SUBSCRIBE on topic /ESP8266/STATUS/#

Wed Jun  3 09:04:26 2015 local5.notice mosquitto[19498]: Connecting bridge dioty (mqtt.dioty.co:1883)

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Bridge OpenWrt.dioty sending CONNECT

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Received CONNACK on connection local.OpenWrt.dioty.

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Bridge local.OpenWrt.dioty sending SUBSCRIBE (Mid: 1, Topic: /4refr0nt@gmail.com/ESP8266/CONTROL/#, QoS: 0)

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Bridge local.OpenWrt.dioty sending UNSUBSCRIBE (Mid: 2, Topic: /4refr0nt@gmail.com/ESP8266/STATUS/#)

Wed Jun  3 09:04:26 2015 local5.debug mosquitto[19498]: Received SUBACK from local.OpenWrt.dioty

Если у вас все так же — поздравляю, вы построили MQTT Bridge. Коннектимся mqtt-spy к облачному брокеру DIoTY и подписывемся на топик, на который у нас есть права

Проверяем мост. Нашему mosquitto через mqtt-spy публикуем топик

В поле Data пишем — false, жмем Publish, переключаемся на вкладку с соединением DIoTY и убеждаемся, что то же самое false попало в облако в топик

/4refr0nt@gmail.com/ESP8266/STATUS/GPIO/4

Если да, то отлично, уже почти готово. Еще проверим, управляется ли ESP8266 GPIO4 по MQTT.

С помощью mqtt-spy на mosquitto публикуем топик /ESP8266/CONTROL/GPIO/4 c Data  true — светодиод на GPIO4 должен загореться и в ответ должен прилететь топик /ESP8266/STATUS/GPIO/4 с Data {«status»:»LOW»}.

Пробуем потушить: /ESP8266/CONTROL/GPIO/4 false, светодиод тухнет и прилетает /ESP8266/STATUS/GPIO/4 с Data {«status»:»HIGH»}

В логах тоже все отображается:

esplorer dioty.co

esplorer dioty.co

Теперь то же самое будем делать намного проще и со смартфона.

Скачиваем мобильное приложение DIoTY

AppStore     AndroidStore

В мобильном приложении логинимся, жмем Menu — Add. Name заполняем gpio4 CONTROL, Type выбираем on-off switch в поле Topic пишем /4refr0nt@gmail.com/ESP8266/CONTROL/GPIO/4 жмем Save. Снова жмем Menu — Add, Namegpio4 status, Type выбираем readonly value, Topic /4refr0nt@gmail.com/ESP8266/STATUS/GPIO/4 и жмем Save. Вот инструкция с картинками.

Правим секцию [/ESP8266/STATUS/GPIO/4]

[/ESP8266/STATUS/GPIO/4]

targets = instapush:gpio

Перезапускаем mqttwarn. Все. Теперь у вас должно получиться все точно так же, как на видео в начале статьи.

ESP8266 публикует в Twitter состояние GPIO

Сначала из консоли устанавливаем python-twitter

pip install pythontwitter

Регистрируем новый аккаунт в твиттере, привязваем его к номеру телефона (без этого нам не дадут зарегистрировать приложение). Дальше идем на apps.twitter.com, добавляем приложение. Обязательно к заполнению название, описание и сайт приложения. Можно заполнять хоть что — это ни на что не влияет. Далее идем на вкладку Keys And Access Tokens и копируем оттуда ключи для конфигурационного файла.

В /overlay/mosquitto/mqttwarn.ini добавляем

[config:twitter]

targets = {

  ‘tweet’ : [ ‘aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa’,  # consumer_key

              ‘bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb’,  # consumer_secret

              ‘ccccccccccccccccccccccccccccccccc’,  # access_token_key

              ‘ddddddddddddddddddddddddddddddddd’   # access_token_secret

            ]

   }

Правим секцию [/ESP8266/STATUS/GPIO/4]

[/ESP8266/STATUS/GPIO/4]

targets = instapush:gpio, twitter:tweet

Перезапускаем mqttwarn, дергаем GPIO с телефона и смотрим твиты

ESP8266 Twitter

ESP8266 Twitter

Это далеко не единственный способ публиковать твиты — еще можете использовать возможности приложений ThingSpeak для получения аналогичного результата.

Поднимаем Dynamic DNS и делаем bridge с cloudmqtt

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

Если провайдер вам выдает динамический IP адрес, то вам поможет сервис Dynamic DNS. В люси устанавливаем пакеты

ddnsscripts

luciappddns

lucii18nddnsru

Регистрируемся на сайте noip.com — это один из немногих DDNS сервисов, который предоставляет услуги пока бесплатно, требуется лишь ежемесячно заходить в свой аккаунт продлевать бесплатную подписку. Полученные данные (имя хоста, например esp8266.ddns.net, имя пользователя и пароль) забиваем в новый пункт меню в люси — Сервисы — Динамический DNS. Тут единственная тонкость в том, что нужно в расширенных настройках IP address source выбрать URL, а ниже вписать http://checkip.dyndns.com иначе сервису DDNS будет передаваться ваш приватный адрес 192.168.1.100, а не внешний, присвоенный провайдером.

Сейчас ваш домашний роутер, который смотрит в интернет, вы (да и любой другой) смогут найти в сети по имени esp8266.ddns.net. Чтобы попасть на mosquitto из внешнего мира потребуется пробросить порт 1883 с роутера IoT на роутер, подключенный напрямую к интернету. Эта настройка зависит от модели роутера — у меня Asus. Захожу в Дополнительные настройки — Виртуальный сервер 

Virtual Server

Virtual Server

Теперь соединения инициированные из интернета к esp8266.ddns.net:1883 будут автоматически пробрасываться на ваш роутер с mosquitto.

Теперь регистрируемся на CloudMQTT, заходим в консоль и в разделе Manage Bridges Connection URL вводим mqtt://test:test@esp8266.ddns.net:1883, Direction Both, а префиксы можно не указывать.

Сейчас вы можете посмотреть логи mosquitto на предмет входящих подключений, подключиться к CloudMQTT через mqtt-spy и погонять топики туда-сюда.

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

Более предпочтительным и простым способом подключения к CloudMQTT является создание моста на стороне mosquitto — просто делаете ниже в mosquitto.conf еще одно соединение по аналогии с DIoTY.

Если вы найдете мобильное, десктопное или веб приложение, способное подключаться к CloudMQTT (точнее к любому MQTT брокеру) и интуитивно просто дергать за GPIO как в DIoTY, только с большим количеством возможностей — сообщите мне и я добавлю информацию в эту статью.

Важные замечания.

В этой статье приведены примеры, указаны направления, а не даны законченные решения. В статье и скетче не предусмотрено сохранение состояния GPIO в случае ребута (ждем когда в Arduino IDE будет реализована работа с файловой системой). Не затронуты вопросы повышения безопасности путем использования SSL. Не реализованы режимы сна для снижения энергопотребления в автономных устройствах. Однако, все описанное в этой статье реально работает и вполне может быть использовано в домашней автоматизации.

Купить эту желтенькую отладочную плату с ESP-12

Обсуждение этой статьи у нас на форуме

Обсуждение mqttwarn

Обсуждение Arduino IDE

Обсуждение домашних IoT серверов

Обсуждение облачных IoT сервисов

Понравилась статья? Поделить с друзьями:
  • Витамины rront инструкция для мужчин отзывы
  • Тандер к222 электрошокер инструкция по применению
  • Руководство по установке плагинов
  • Оксихом инструкция по применению для томатов
  • Бифиформ жевательные таблетки детям инструкция по применению