0
Обложка: Как создать самодельные устройства на Raspberry Pi, ESP32 и Node-RED

Как создать самодельные устройства на Raspberry Pi, ESP32 и Node-RED

Купили или давно хотите купить Raspberry Pi, но не знаете, что конкретно с ним делать? Разбираемся, как использовать одноплатный компьютер для DIY-проектов в связке с «компаньонами» — ESP32 и Node-RED.

Максим Шепелев
Максим Шепелев
Преподаватель Школы программистов МШП по робототехнике, тренер команды победителей WRO 2019, тренер сборной России World Robot Olympiad

Меня зовут Максим Шепелев, я тренер команды победителей Международной робототехнической олимпиады WRO 2019, тренер сборной России и преподаватель робототехники в Школе программистов МШП. С учениками мы создаем образовательные проекты, строим роботов для соревнований на базе конструкторов LEGO Mindstorms EV3, микроконтроллеров Arduino, ESP, STM и даже одноплатных компьютеров — таких, как Raspberry Pi. О последних и пойдет речь в этой статье.

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

Самодельные устройства

Начнем с того, что именно вы хотите сделать: систему автополива для вечно засыхающих комнатных растений, умную кормушку для домашних животных, метеостанцию или монитор качества воздуха, а может, домашнюю сигнализацию? Или как я, «подружить» умную лампу Philips HUE с дверью кладовой. Сделать так, чтобы свет автоматически включался при открытии дверцы.

Та самая кладовая. Сверху видны закрепленные датчики открытия двери.

И в этом месте вынужден вас разочаровать – использовать Raspberry Pi в качестве контроллера в большинстве подобных проектов скорее всего будет избыточно. Разберемся, почему.

О Raspberry Pi

Raspberry Pi — не микроконтроллер, а полноценный компьютер в одноплатном исполнении, длиной и шириной чуть больше пластиковой карты. Многие не знают, но изначальный, и до сих пор сохраняющийся посыл Raspberry Pi Foundation – ультрадешевые компьютеры для создания компьютерных классов и обучения детей информатике.

Если не вдаваться в детали, то смартфон — это тоже компьютер, просто в очень компактном корпусе с минимумом внешних разъемов, где все включено: монитор, колонки, тачскрин. А Raspberry Pi это фактически смартфон наоборот – процессор с тем же ядром, что и у многих смартфонов (ARM Cortex), и с кучей наружных разъемов.

Если посмотреть на эти разъемы, то у них есть все необходимое, чтобы стать полноценным настольным компьютером: HDMI-порт для подключения монитора (даже два в 4-й версии), USB-разъемы для подключения клавиатуры, мыши или жесткого диска, сеть через Ethernet или Wi-Fi (начиная с 3-й версии), Jack 3.5 для звука, ну и Bluetooth, правда тоже только с 3-й версии. В качестве операционной системы выступает Linux (например, родной дистрибутив Raspberry Pi OS) или даже Windows 10 IoT для процессоров ARM.

Итого: если говорить о самой последней Raspberry Pi 4B, то это: 4 ядра, 1.5 GHz, от 1 до 8 GB оперативной памяти, гигабитный Ethernet. И все это великолепие по официальным ценам обойдется от 25$ до 90$ в зависимости от объема оперативной памяти.

Для чего хорошо подходит Raspberry Pi

Так где же место для Raspberry Pi? Он отлично показывает себя в проектах, в которых нужно реализовать вывод информации на монитор и взаимодействовать с ним, как с компьютером.

Например: информационный стенд наподобие тех, что мы видим в метро, на улице или в выставочном зале, в качестве мозга фотобудки, которая напечатает ваше фото из Instagram (организация, запрещённая в России), в качестве компьютера для кассового аппарата или экрана с ценами, как на кассе в Макдональдсе.

Если нужно подключить полноценный монитор или принтер, Raspberry Pi — идеальный выбор. Часто в таких проектах используют небольшие компьютеры «неттопы», и замена их на «одноплатники» вроде Raspberry Pi — очень логичное решение.

Дома у типичного программиста

Дома у типичного программиста Raspberry Pi отлично займет место в качестве маленького домашнего медиа-(или не очень)-сервера.

Написали телеграм-бота – отправляем его на Raspberry Pi, аккуратненько лежащий на полке рядом с роутером. Задумали новый веб-проект? Опять же — отправляем на Raspberry, Docker на нем прекрасно работает. Нужно поднять сервер Minecraft? Тоже без проблем! Но тут рекомендую 4-ю версию платы с расширенной до хотя бы 4GB оперативной памятью.

Моя особая рекомендация — это медиа-серверы Plex или Kodi, которые в комплекте с USB и жестким диском позволят поднять у вас дома свой собственный небольшой Netflix с библиотекой любимых произведений. Причем мой опыт показал, что для стриминга даже 4к контента вполне хватит 3-й модели. Отправлять медиафайлы на Raspberry можно по сети через SMB или сразу скачивать их напрямую на самой Raspberry через Torrent-трекер Transmission с Web-интерфейсом.

Отдельное внимание заслуживает использование Raspberry Pi в качестве хаба для IoT и умного дома, о чем мы поговорим ниже.

Что же подойдет лучше?

Подытожу: выбор Raspberry Pi в качестве основы для электронного DIY-проекта очень часто оказывается избыточным. Исключение составляют проекты, где нужно реализовать компьютерное зрение. Тогда можно напрямую подключить матрицу камеры и без проблем использовать библиотеку OpenCV.

Тут следует оговориться, что бывают разные Raspberry Pi, например: модели, помеченные литерой «A». Они миниатюрнее, у них меньше памяти (512 MB), отсутствует Ethernet и присутствует лишь 1 USB. Или модель «Zero»: значительно меньшая в размерах c micro USB и mini HDMI. Они обе окажутся менее избыточными, чем стандартная модель с литерой «B». Но это все еще полноценные компьютеры с OS на борту.

Что же подойдет лучше для самодельных устройств? Ответ прост: любой микроконтроллер.

Микроконтроллеры

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

Для домашних DIY-проектов самое то, особенно при условии, что научиться с ними работать может каждый. В МШП мы учим детей работать с Arduino с 13-14 лет, многие учат и с гораздо более младшего возраста.

Помимо уже набившей всем оскомину Arduino, существуют огромное количество других, в том числе совместимых (программируемых через Arduino IDE) микроконтроллеров. Приводить этот внушительный список не вижу смысла, ведь существует кандидат, который я люблю назвать «Raspberry Pi среди микроконтроллеров» — ESP32.

Если сказать просто, то это та же самая Arduino, только с Wi-Fi и Bluetooth на борту. В то же время мощности и различных современных фишек у неё ощутимо больше.

Поддерживает мои аргументы про нерациональное использование Raspberry Pi для домашних проектов и тот факт, что у Raspberry Pi Foundation недавно появилась своя собственная Arduino — Raspberry Pi Pico. Это отличный конкурент для Arduino, и я уверен, в будущем и для ESP32. Но пока последняя выигрывает из-за наличия Wi-Fi, который бесконечно прокачивает домашние проекты и позволяет создавать отличную связку Raspberry Pi в качестве IoT-хаба и ESP32 как базу для самих устройств.

Так мы и поступим: используем Raspberry Pi как хаб умного дома, а также подключим к нему самодельный датчик открытия двери на ESP32.

Подготавливаем Raspberry Pi

Итак, нам потребуется: Raspberry Pi (в моем случае модель 3B+), которую я обернул в китайский алюминиевый корпус-радиатор.

Такого пассивного охлаждения для моей домашний Raspberry Pi всегда хватало, несмотря на то, что она работает на постоянной основе и поддерживает не только мой IoT-хаб, но и пару телеграм-ботов на Java, файловое хранилище с внешним жестким диском и медиасервер Plex, с которого я регулярно стримлю на Apple TV видео в 4K.

Чтобы снизить энергопотребление Raspberry Pi, я отключил в конфигурации то, что не использую: Wi-fi и Bluetooth, а также HDMI, так как хранится она в моем случае на верхней полке стеллажа вместе с Wi-Fi роутером и подключена по Ethernet.

Все управление в таком случае происходит только через SSH, который нужно не забыть предварительно включить. Для этого достаточно зайти в конфигурационную утилиту Raspberry Pi. В терминале вводим: sudo raspi-config, после чего открываем меню Interfacing Options, выбираем пункт SSH и включаем его. Далее можно отключить от Raspberry Pi все, кроме провода питания и Ethernet, и продолжить работу с удаленного компьютера по SSH.

Затем снижаем энергопотребление. Первым делом отключаем HDMI. Это сэкономит нам около 30mA. Немного, но приятно. В файл /etc/rc.local перед строкой exit 0 добавляем следующую строчку:

/opt/vc/bin/tvservice -o

Затем отключаем Wi-Fi и Bluetooth. Это сэкономит еще 40 mA. В файле /boot/config.txt ****добавляем следующие две строки:

dtoverlay=disable-wifi
dtoverlay=disable-bt

Отключать USB мы не можем, так как это параллельно отключит Ethernet на модели 3B+, а отключать светодиоды я не хочу, так как иногда все же проверяю работоспособность с их помощью. Да и большого снижения энергопотребления от этого ждать не стоит.

Самого большого снижения энергопотребления можно добиться, уменьшив частоту работы процессора и количество активных ядер, так называемый «Underclocking». Однако это нужно делать только в том случае, если это не противоречит вашим задачам. Так как я использую медиасервер Plex для стриминга тяжелых медиа файлов, то эту процедуру пропускаю.

Установка Node-RED

Следующий шаг в создании собственной сети устройств — установка на Raspberry Pi программного обеспечения, которое поможет «подружить» между собой любые устройства. Например, проприетарные умные лампы Philips HUE и наш самодельный датчик открытия двери.

Отличный пример такого софта — Node-RED, минималистичная среда от разработчиков из IBM, позволяющая удобно создавать сценарии взаимодействия различных устройств в нодовом редакторе.

Чтобы установить Node-RED на Raspberry Pi, достаточно всего лишь прописать следующую команду в терминал:

bash <(curl -sL <https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered>)

Она автоматически установит все необходимое (Node.js, npm) и саму по себе среду Node-RED. Далее поместим сервис Node-RED в автозагрузку, выполнив следующую команду:

sudo systemctl enable nodered.service

После этого можно перезагрузить Raspberry-Pi и подключиться к веб-интерфейсу Node-Red через браузер на своем основном компьютере. Он будет находится на порту 1880 вашей Raspberry Pi: http://<hostname>:1880.

Как подружить ESP32 и Node-RED

Теперь нам предстоит собрать свое устройство на ESP32, но уже возникает вопрос, как микроконтроллер подключится к Raspberry Pi и передаст команду в Node-RED? Есть простой ответ — протокол MQTT.

Протокол MQTT (Message Queuing Telemetry Transport) устроен достаточно просто: есть «Брокер» – устройство-посредник (сервер), на нем создается «Топик» – канал, куда устройство-отправитель может «Публиковать» сообщения, устройства-получатели могут «Подписаться» на топик, и когда отправитель опубликует туда новое сообщение, Брокер перешлет его подписанным получателям.

Этот протокол очень хорошо подходит для устройств IoT и умного дома. В нашем случае Raspberry Pi выступит «Брокером», ESP32 — Отправителем, а Node-Red (установленный на Raspberry Pi) — Виртуальным получателем.

Чтобы Raspberry Pi стал Брокером, программу Брокера нужно установить. В нашем случае это будет брокер Mosquitto. Выполняем в терминале команду:

sudo apt install -y mosquitto mosquitto-clients

После чего добавляем брокер Mosquitto в автозагрузку

sudo systemctl enable mosquitto.service

Устройство на ESP32

Из всего огромного многообразия плат на основе ESP32 моя любимая — Lolin32. В свое время я купил 10 штук.

Чем хороша Lolin32? Она встает на макетную плату так, что с каждой стороны остается по 1 дорожке контактов (это немного редкость для плат на основе ESP32). А еще у нее на борту есть контроллер заряда Li-ion-аккумулятора и небольшой коннектор. Это позволяет делать автономные устройства с аккумулятором, вообще не используя дополнительных деталей. И без мороки с зарядкой, например, 18650 аккумулятора. Всё на одной копеечной плате.

Схема подключения проста до безобразия. Я просто подключаю датчик открытия двери (небольшой геркон в пластиковом корпусе) напрямую к двум ножкам Lolin32 – GPIO32 и GND. 

Ножку GPIO32 настраиваю в режим INPUT_PULLUP. Получаю простую схему, пока геркон сомкнут (дверь закрыта), на ножке сигнал GND. Как только геркон размыкается (дверь открыта), на ножку поступает напряжение подтяжки со встроенного в микроконтроллер PULLUP-резистора.

Так как мне нужна мгновенная реакция лампы на открытие дверцы, и секунда- другая задержки мне не кажется чем-то страшным, в отличие от высокого потребления платы на постоянной основе подключенной к Wi-Fi, я буду отправлять микроконтроллер в глубокий сон и пробуждать по внешнему прерыванию (изменению состояния ножки) на ножке GPIO32. В режиме глубокого сна ESP32 потребляет всего 0.15 mA, то есть буквально ничего, если вы питаете её от сети через обыкновенный USB-зарядник.

Код для ESP32

Программировать ESP32 будем через Arduino IDE. Для этого подключаем внешний менеджер плат, жмем File > Preferences, и в пункте Additional Board Manager URLs помещаем:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

Затем устанавливаем поддержку микроконтроллеров ESP32. Жмем:

Tools > Board > Boards Manager

находим в списке esp32 и жмем Install.

Далее выбираем вашу конкретную плату из списка Tools > Board (в моем случае это WEMOS LOLIN32).

Следующий шаг: устанавливаем библиотеку EspMQTTClient, идем:

в Tools > Manage Libraries

ищем библиотеку EspMQTTClient и устанавливаем её.

Библиотека EspMQTTClient облегчает создание таких устройств буквально до смешного. Подключаем библиотеку, делаем настройки MQTT клиента и Wi-FI.

#include "EspMQTTClient.h"

EspMQTTClient client(
  "Hello World", // Имя Wi-Fi сети
  "12345678", // Пароль от Wi-Fi
  "192.168.0.101", // IP адресс Raspberry Pi
  "DoorLight" // Любое имя для вашего MQTT клиента
);

Так как устройство лишь отправляет сообщения, потребуются только функция client.loop() (которую нужно на постоянной основе вызывать в главном цикле нашей программы), а также функция client.publish(), в которую подаются два аргумента: имя MQTT-топика и передаваемое значение. Оба параметра строковые. Например, чтобы сообщить, что дверь закрыта, я буду вызывать функцию со следующими параметрами: client.publish(«sensors/door», «0») .

Тут важно пояснить, имя MQTT-топика — это структура, за счет которой можно будет следить за всеми сенсорами в каталоге, если подписаться на sensors/# или за конкретным — sensors/door. 

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

Теперь немного про режим глубокого сна ESP32. Для того, чтобы в него войти, сперва нужно настроить способ пробуждения. В нашем случае —  по вектору прерывания ext1 на ножке GPIO32, когда появится сигнал HIGH. А затем непосредственно заснуть.

esp_sleep_enable_ext1_wakeup(GPIO_NUM_32, ESP_EXT1_WAKEUP_ANY_HIGH);
esp_deep_sleep_start();

При выходе из глубокого сна код продолжается не с той точки, на которой мы в сон вошли. А с самого начала — с функции setup(). При этом некоторую информацию в памяти сохранить можно, но в случае с нашей примитивной задачей в этом нет необходимости, ведь если мы проснулись – дверь была открыта. Больше нам ничего знать не надо, отправляем сообщение и снова засыпаем. Код будет выглядеть следующим образом:

void setup() {
  // Инициализируем ножку геркона
  pinMode(32, INPUT_PULLUP);
  // Если дверца закрыта, засыпаем
  if (digitalRead(32) == LOW) {
    esp_sleep_enable_ext1_wakeup(GPIO_NUM_32, ESP_EXT1_WAKEUP_ANY_HIGH);
    esp_deep_sleep_start();
  }
}

// Функция которую необходимо определить для библиотеки
// Но в рамках данного упрощенного примера можно оставить пустой
void onConnectionEstablished() {}

// В главный цикл таким образом мы попадем только если дверь открыта
void loop() {
  // Ждем подключения, библиотека инициализирует Wi-Fi (займет до пары секунд)
  while (!client.isMqttConnected()) {
    client.loop();
  }
  // Если дверь все еще открыта
  if (digitalRead(32) == HIGH) {
    // Отправлем сообщение о том что дверь открыта
    client.publish("sensors/door", "1");
    // Ждем пока дверь не закроют
    while (digitalRead(32) == HIGH) {
      client.loop();
    }
    // Отправлем сообщение о том что дверь закрыта
    client.publish("sensors/door", "0");
    // Ждем 2 секнуды что бы убедиться что сообщение отправлено
    unsigned long timer_publish = millis();
    while (millis() - timer_publish < 2000) {
      client.loop();
    }
  }
  // Засыпаем обратно
  esp_sleep_enable_ext1_wakeup(GPIO_NUM_32, ESP_EXT1_WAKEUP_ANY_HIGH);
  esp_deep_sleep_start();
}

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

Создаем сценарий в Node-RED

Последнее, что осталось сделать — составить сценарий в Node-RED, который объединит умный свет с датчиком на ESP32.

Для этого достаточно достать из бокового меню ноду mqtt in и поместить ее на наш пустой поток. Создать MQTT-сервер с адресом localhost и портом по умолчанию 1883. В качестве топика необходимо указать наш sensors/door, далее с помощью ноды необходимо привести получаемое нами сообщение в пригодный вид, и вуаля!

Прикладываю JSON для импорта. Нода с лампой Philips HUE в данном примере заменена на простой Debug для универсальности.

[{"id":"88246ee6.3c3bc8","type":"mqtt in","z":"5c4b60b4.689b6","name":"","topic":"sensors/door","qos":"2","datatype":"auto","broker":"fd3a7307.a2a868","nl":false,"rap":false,"rh":"0","inputs":0,"x":190,"y":1980,"wires":[["f4e4306e.67a59"]]},{"id":"f4e4306e.67a59","type":"change","z":"5c4b60b4.689b6","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"0","fromt":"str","to":"false","tot":"bool"},{"t":"change","p":"payload","pt":"msg","from":"1","fromt":"str","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":1980,"wires":[["76e49127.ea5e5"]]},{"id":"76e49127.ea5e5","type":"change","z":"5c4b60b4.689b6","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.on","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":1980,"wires":[["f2fa3d694f7c313c"]]},{"id":"f2fa3d694f7c313c","type":"debug","z":"5c4b60b4.689b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":830,"y":1980,"wires":[]},{"id":"fd3a7307.a2a868","type":"mqtt-broker","name":"Mosquitto","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":4,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":"","credentials":{}}]

Заключение

Связка Raspberry Pi, Node-RED, MQTT и ESP32 крайне универсальна и удобна для проектов умного дома и интернета вещей. Пример в статье — база, которую можно продолжить бесчисленным количеством небольших устройств на ESP32 при единственной, неизменной Raspberry Pi в качестве хаба.