JustPaste.it

Хакер - JavaScript для умного дома. Arduino устарел, да здравствует ESP32!

https://t.me/hacker_frei

Интерес к интернету вещей растет с каждым днем, свои курсы по технологии IoT запустили и Cisco, и Samsung. Но большинство этих курсов базируются на собственном железе компаний, довольно дорогом, в то время как практически все то же самое можно сделать на гораздо более дешевом железе самостоятельно, получив при этом массу удовольствия и полезных навыков.
 

Какую плату выбрать?

Когда неофит от IoT полезет в интернет, одним из первых модулей, которые он найдет, будет ESP8266. И действительно, он обладает массой достоинств: дешевый, много различных плат на его основе, позволяющих использовать его как самостоятельное устройство и подключать к сложным Arduino-based проектам. Но ESP8266, выпущенный в 2014 году, довольно быстро перестал удовлетворять запросы пользователей, и в 2015 году компания-разработчик Espressif выпускает новый микроконтроллер — ESP32.

Различия между ESP8266 и ESP32 Различия между ESP8266 и ESP32

Точно так же, как и в случае с ESP8266, разработчики создали довольно много плат, базирующихся на новом микроконтроллере. В данной статье все примеры тестировались и проверялись на плате MH-ET LIVE ESP32 DevKit. Плата для обзора была любезно предоставлена интернет-магазином Amperkot.

 

Pinoutmap платы Pinoutmap платы

Сколько процессорных ядер у ESP32?

  • Одно, зачем ему больше?
  • Два, меньше уже не делают
  • ESP32 — это серия из четырех чипов с одним и двумя ядрами
 

Начинаем программирование

Как и у любой платы, основанной на ESP32, у MH-ET LIVE ESP32 DevKit есть достаточно большой набор языков программирования. Во-первых, это Arduino C, во-вторых, Lua, а в-третьих и в-четвертых — MicroPython и Espruino. Про Espruino — сборку JS для программирования микроконтроллеров — уже рассказывалось в ][, но в той статье разбиралась работа только на плате Espruino Pico, заточенной под Espruino.

fdb73b523b8cdc061cc7d2fa3c835436.jpg

INFO

К сожалению, портирование Espruino на ESP32 еще не до конца завершено. Часть возможностей, например обновление по воздуху и Bluetooth, недоступна. Но так как Espruino — open source проект, любой может добавить свою функциональность.

 

Установка

  1. Скачиваем на официальном сайте свежую сборку Espruino. А если не доверяешь готовым сборкам, то можно собрать прошивку самостоятельно:

    # Get the Espruino source code git clone https://github.com/espruino/Espruino.git cd Espruino # Download and set up the toolchain ('source' is important here) source scripts/provision.sh ESP32 # Clean and rebuild make clean && BOARD=ESP32 make
  2. Несмотря на то что мы будем программировать на JS, для установки все равно нужен Python, а конкретно esptool.py. Повторяя свою предыдущую статью, скажу, что для его установки, при условии, что Python уже установлен, достаточно набрать в консоли/терминале: pip install esptool.

  3. В терминале перейти в папку с прошивкой. Кроме самого файла Espruino, здесь лежат файлы bootloader.bin и partitions_espruino.bin. Это необходимые компоненты, но в некоторых сборках их может не быть, тогда их придется скачать отсюда.
  4. Запускаем процесс прошивки, не забыв изменить порт, указанный в данном примере, на свой, а также при необходимости указать другое имя прошивки. Здесь она называется espruino_esp32.bin.

    esptool.py \ --chip esp32 \ --port /dev/ttyUSB0 \ --baud 921600 \ --after hard_reset write_flash \ -z \ --flash_mode dio \ --flash_freq 40m \ --flash_size detect \ 0x1000 bootloader.bin \ 0x8000 partitions_espruino.bin \ 0x10000 espruino_esp32.bin
Процесс прошивки Процесс прошивки
 

IDE

Разработчики Espruino создали свою IDE, Espruino Web IDE. Эта программа распространяется через Chrome Web Store, также существуют нативные приложения для Windows (32 и 64).

Espruino Web IDE Espruino Web IDE

Перед первым запуском нужно залезть в настройки, вкладка COMMUNICATIONS, и убедиться, что скорость общения выставлена на 115200, а также изменить поле Save on Send с No на Yes, иначе все программы после перезапуска слетят.

Теперь достаточно запустить IDE, подключиться к плате и набрать в консоли 1+2: если ты получил 3, значит, все настроено правильно и можно начинать полноценную работу.

Какую платформу для разработки прошивок ESP32 рекомендуют использовать Espressif, AWS IoT и Google Cloud IoT?

  • Ubuntu LTS
  • Mongoose OS
  • Kolibri OS
 

Hello world

Во всех языках программирования, предназначенных или модифицированных для программирования микроконтроллеров, самая простая программа — так называемый Blink, мигание встроенным светодиодом. Но это как-то скучно. Поэтому нашей первой программой станет программа для управления светодиодом с помощью веб-страницы. И действительно, JS — это же язык веба.

var wifi = require("Wifi"); wifi.startAP('EspruinoAP', { password: '0123456789', authMode: 'wpa2' },function() { console.log(`AP started`); }); function onPageRequest(req, res) { var a = url.parse(req.url, true); if (a.pathname=="/") { res.writeHead(200, {'Content-Type': 'text/html'}); res.end("<H1><center>Hello, ][aker!</center></H1>"); } else if (a.pathname=="/on") { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end("Enable"); digitalWrite(D2, false); } else if (a.pathname=="/off") { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end("Disable"); D2.write(true); } else { res.writeHead(404, {'Content-Type': 'text/plain'}); res.end("404: Page "+a.pathname+" not found"); } } require("http").createServer(onPageRequest).listen(80);

Можно заметить, что синтаксис практически ничем не отличается от обычного JS. Давай разбираться, что же происходит в этой программе.

  • var wifi = require("Wifi") — для начала мы подгрузили необходимый нам модуль для работы с Wi-Fi. Логично будет задаться вопросом: а откуда мы его взяли? Допустим, есть встроенные в прошивку модули. А если нам нужно загрузить с какого-нибудь внешнего сайта? Функция require поддерживает синтаксис вида require("https://github.com/espruino/EspruinoDocs/blob/master/devices/PCD8544.js");, а WebIDE для поиска модулей онлайн, по умолчанию используется https://www.espruino.com/modules.
  • Следующий блок кода отвечает за поднятие точки доступа с именем EspruinoAP и паролем 0123456789. В случае успешного запуска в консоль выводится соответствующее сообщение.
  • Функция onPageRequest — собственно сам веб-сервер. В этой функции разбирается адрес и проверяется, что нужно сделать, в зависимости от запроса:
    • если загружается первая страница — /, то вернуть 200-й заголовок и сообщение типа text/html «Hello, ][aker!», в обрамлении HTML-тегов;
    • если загружается страница включения — /on, то вернуть 200-й заголовок и сообщение Enable, а также включить светодиод. Заметим, что используется привычная Arduin’щикам функция digitalWrite(pin, value);
    • небольшое отличие в случае страницы выключения — /off, для выключения светодиода используется не функция digitalWrite(pin, value), а метод write(value);
    • во всех остальных случаях возвращаем ошибку «404 — Page Not Found».
  • А последняя строка собственно поднимает сервер, с внутренней функцией onPageRequest, на 80-м порте.

Важно заметить, что мы можем возвращать различный контент: обычный текст, HTML, XML и так далее.

 

RGB-лампочка, управляемая по MQTT

Очень часто создание своего умного дома начинается именно с подсветки. Но просто включать/выключать светодиодную лампу — это банально. Для освещения небольших помещений, а также для украшения и создания праздничной атмосферы нередко используются адресные RGB-светодиоды. Воспользуемся ими и мы. В качестве MQTT-брокера и клиента возьмем Adafruit IO.

Ты уже делал свои проекты с Arduino?

  • Еще нет
  • Только помигал светодиодами
  • Делал, и теперь замахнулся на большее

Из стандартных виджетов нам понадобятся всего два: Toggle и Color Picker.

Adafruit IO Dashboard Adafruit IO Dashboardvar ssid = 'SSID'; var password = 'PASSW'; var count = 16; var LedPIN = D23; var wifi = require('Wifi'); function colorall(color,count,pin) { Color_Array = new Uint8ClampedArray(count*3); for (var i = 0;i < Color_Array.length; i+=3) { Color_Array[i ] = color[0]; Color_Array[i+1] = color[1]; Color_Array[i+2] =color[2]; } require("neopixel").write(pin, Color_Array); } function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16); } function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16); } function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16); } function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7) : h; } wifi.connect(ssid, {password: password}, function() { console.log('Connected to Wifi. IP address is:', wifi.getIP().ip); }); var mqtt = require("MQTT").connect({ host: "io.adafruit.com", username: "<LOGIN>", password: "<SECRET-KEY>" }); mqtt.on('connected', function() { mqtt.subscribe("<LOGIN>/feeds/exampledashboard.enable"); mqtt.subscribe("<LOGIN>/feeds/exampledashboard.colorlamp"); console.log("Connect"); }); mqtt.on('publish', function (pub) { console.log("topic: "+pub.topic); console.log("message: "+pub.message ); if (pub.topic == "<LOGIN>/feeds/exampledashboard.enable") { if (pub.message=="OFF") { colorall([0,0,0], count, LedPIN); } else { colorall([128,128,128], count, LedPIN); } } else if (pub.topic == "<LOGIN>/feeds/exampledashboard.colorlamp") { var hex_color = pub.message; var rgb_color = [hexToG(hex_color),hexToR(hex_color), hexToB(hex_color)] ; colorall(rgb_color, count, LedPIN); } }); mqtt.connect();

Есть ли у ESP32 встроенная флеш-память?

  • Нет, она не нужна
  • Да, как же без нее?
  • Есть только в модификации D2WD

Приступим к разбору программы.

  • Для начала объявляем переменные, необходимые для подключения к Wi-Fi, а также количество светодиодов и пин, к которому они подключены.
  • Функция colorall(color,count,pin) отвечает за одновременное окрашивание всех светодиодов в один цвет. Для этого следует создать массив, в который count раз записать по очереди три составляющих цвета. То есть для окрашивания двух светодиодов в синий цвет массив должен быть такой: [0,0,255,0,0,255]. Как можно заметить, в этой функции подключается предзагруженная библиотека neopixel. И еще один интересный факт: здесь перепутан порядок цветов — не RGB, а GRB. Это очень странно, но так есть.
  • Следующие четыре функции нужны для перевода цвета из шестнадцатеричной записи в RGB. Они нам понадобятся, ведь Color Picker отправляет цвет как строку вида #RRGGBB.
  • Подключаемся к Wi-Fi, в случае успешного подключения в лог выведется сообщение.
  • Теперь необходимо подключиться к MQTT-брокеру. В первый раз, когда попробуешь запустить, интерпретатор может выдать ошибку, что такая библиотека не найдена. На самом устройстве ее действительно нет, она подгружается из интернета, поэтому, если подключение к интернету не удалось, она не сможет скачаться. Подожди, пока установится стабильное подключение, и перезагрузи устройство.
  • Теперь надо описать функциональность клиента. У MQTT-клиента есть различные события, на которые можно (и нужно) повесить обработчики.
    • Когда соединение установлено (connected), надо подписаться (mqtt.subscribe(topic)) на необходимые топики: один соответствует переключателю, другой — Color Picker’у. И для удобства выведем в консоль сообщение об успешном подключении.
    • Теперь надо прописать, что необходимо делать при появлении в том или ином топике какого-либо сообщения (publish). Для начала выведем имя топика и текст сообщения.
    • Переключатель может возвращать всего два сообщения: OFF или ON. Логично, что при получении первого сообщения необходимо выключить все светодиоды, а вот что делать при включении — остается на выбор программиста. Я решил зажечь все светодиоды белым цветом, с 50%-й яркостью.
    • Если же пользователь изменяет цвет, то мы переводим цвет в RGB, точнее в GRB-запись и записываем этот цвет во все светодиоды.
  • И разумеется, необходимо инициировать подключение к MQTT-брокеру.
 

MQTT-сервисы

Кроме Adafruit IO, есть и другие MQTT-сервисы, с похожей функциональностью. Если говорить про полностью «ручное» управление — первым на ум приходит Eclipse Mosquitto. Этот брокер можно установить на домашний компьютер или на Raspberry Pi и при помощи встроенных утилит mosquitto_sub и mosquitto_sub вручную (или используя Python) создавать топики, подписываться на них, отправлять сообщения.

В Arduino-кругах очень популярен сервис Blynk. У этого сервиса есть библиотеки для Arduino, клиенты под iOS и Android, а также его сервер распространяется через GitHub и может быть поднят на любом компьютере. Есть небольшой нюанс: каждый виджет, добавляемый на панель приложения, «стоит» определенное количество внутренних единиц. Изначального баланса хватит на большинство приложений, но если тебе захочется сделать полноценную программу и выложить ее в App Store / Play Market (а Blynk и такое позволяет), то придется раскошелиться.

Кроме этого, и в App Store, и в Play Market наберется достаточно много клиентских приложений, а в интернете есть масса MQTT-брокеров. Например, CloudMQTT. У него доступен бесплатный тариф — самое то для начала.

 

Система контроля состояния комнаты

Представим, что у нас есть комната, в ней ряд датчиков и нам нужно следить, все ли там в порядке. Постоянно смотреть за показателями надоест довольно быстро, поэтому нам требуется, чтобы в определенных случаях включался свет, причем не какой-то светодиод, а полноценная лампа. А всю информацию будем отправлять опять же на Adafruit IO.

Датчики у нас следующие:

  • датчик уровня воды — аналоговый;
  • датчик температуры и влажности DHT11 — цифровой;
  • датчик звука — цифровой.

Кроме этого, для управления светом нам понадобится реле.

Схема подключения Схема подключенияvar ssid = 'SSID'; var password = 'PASSW'; var TempRTSensorPin = D27; var WaterSensorPin = D26; // Аналоговый пин var SoundPin = D14; // Аналоговый пин var RelayPin = D12; const SoundLevel = 3.8; const Waterlevel = 30; var wifi = require('Wifi'); wifi.connect(ssid, {password: password}, function() { console.log('Connected to Wifi. IP address is:', wifi.getIP().ip); mqtt.connect(); }); var dht = require("DHT11").connect(TempRTSensorPin); var mqtt = require("MQTT").connect({ host: "io.adafruit.com", username: "<LOGIN>", password: "<SECRET-KEY>" }); mqtt.on('connected', function() { console.log("Connect"); }); function EnableLight() { digitalWrite(RelayPin,true); } setInterval(function() { if (analogRead(SoundPin)*100>SoundLevel) || (analogRead(WaterSensorPin) * 100 > Waterlevel) { D2.write(false); EnableLight(); } }, 100); setInterval(function() { dht.read(function (a) {console.log("Temp is "+a.temp.toString()+" and RH is "+a.rh.toString()); mqtt.publish("<LOGIN>/feeds/smartroom.rh", a.rh.toString()); mqtt.publish("<LOGIN>/feeds/smartroom.temperature", a.temp.toString()); mqtt.publish("<LOGIN>/feeds/smartroom.waterlevel",""+analogRead(WaterSensorPin)); },5000);

В данной программе нам опять понадобится подключение к Wi-Fi и MQTT-брокеру. Они аналогичны первой программе, единственное отличие — MQTT-клиент при подключении не подписывается ни на какие топики.

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

Для датчика температуры и влажности существует собственная библиотека, которую необходимо подключить: require("DHT11").

Реле управляется обычным изменением данных на цифровом пине. 0 — реле выключено, 1 — включено. Таким образом, подключая лампы, удлинители и прочие устройства через реле, ими можно управлять через интернет. Это один из самых частых IoT-приемов.

Но самое интересное — это, конечно, функция setInterval(function,time). Всем, кто писал на Arduino C, известна основная функция void Loop(){} — это функция, которая постоянно вызывается после загрузки программ. Так вот, setInterval гораздо круче. Во-первых, можно (и нужно) задать время повтора в миллисекундах, а во-вторых, можно задавать вызовы нескольких функций, причем с разной частотой.

Еще из интересных нюансов у меня есть переменные SoundLevel и Waterlevel, поскольку и датчик уровня воды, и датчик звука — аналоговые, показания на разных платах могут различаться и необходимо провести калибровку. На датчике звука установлен потенциометр, для регулировки чувствительности.

Кроме этого, в данном скрипте появился вызов функции mqtt.publish(field,data), он отправляет значение поля data в заданный канал на MQTT-брокере.

SmartRoom Dashboard SmartRoom Dashboard

Какая плата полностью совместима с Espressif ESP32-DevKitC?

  • Таких нет, но подобных много
  • Watterott ESP-WROOM32-Breakout
  • Goouuu Tech ESP-32F
 

Заключение

Примеры, разобранные в данной статье, призваны продемонстрировать, что в создании собственных IoT-девайсов нет ничего сложного. Действительно, JS, на котором базируется Espruino, довольно несложный ЯП, а количество уроков по нему в интернете зашкаливает. В начале статьи я писал, что самостоятельная разработка дешевле, чем покупное устройство. В качестве примера, подтверждающего это, скажу, что одна розетка, управляемая по Wi-Fi, стоит в среднем примерно в два раза больше платы, используемой в обзоре, и в 10–20 раз больше, чем реле, необходимое для управления обычной розеткой. Выводы делай сам. 

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei