Представим ситуацию: вам вдруг захотелось вечерком/на выходных сделать устройство умного дома (условимся, что это Arduino подобное устройство). Причины и цели не так важны: хотелка, необходимость, спортивный интерес, да что угодно. Вы начинаете искать информацию о популярных платах, способах взаимодействия с устройством, хранении данных и т. д. Есть множество статей по данным темам с примерами, но вам не хочется погружаться в код, а хочется только описать логику устройства и сразу им пользоваться. Что же делать? Для такого случая был создан SmartThing
— это проект нацеленный на упрощение и ускорение разработки законченного устройства умного дома (или же IOT устройства). Проект SmartThing
состоит из нескольких основных частей:
SmartThingLib
— библиотека для ускорения разработки IOT устройств;SmartThingGateway
— приложение маршрутизатора для упрощения взаимодействия с устройствами на базе библиотекиSmartThingLib
;SmartThingCloud
— приложение облачного сервиса для доступа к маршрутизаторам из глобальной сети.
SmartThingLib
позволяет быстро создать желаемое устройство, а SmartThingGateway
и SmartThingCloud
обеспечивают упрощенный доступ к устройствам для пользователя. Устройства на базе SmartThingLib
можно так же добавить в систему умного дома Home Assistant
в виду наличия REST Api
для управления.

Репозиторий проекта с ссылками на все компоненты системы.
Если вас заинтересовало - прошу в подробный разбор компонентов системы ниже.
Что такое библиотека SmartThingLib и как с ней работать
Что в основном должны уметь устройства умного дома? Работать по беспроводной сети, выполнять разработанные действия, отображать показатели датчиков и уметь не терять свои настройки при перезапуске. Эти требования были взяты за основу библиотеки SmartThingLib
. Она реализует в себе базовую логику для построения IOT устройства с требуемыми функциями. На данный момент поддерживаются две платформы - esp32
и esp8266
. Репозиторий библиотеки.
Для создания нового устройства разработчику, с помощью методов библиотеки, достаточно лишь указать тип устройства, набор действий, которые устройство может выполнить, добавить различные датчики и возможные настройки/конфигурацию устройства - и все, можно запускать компиляцию и загружать прошивку на поддерживаемую платформу. Работа с WiFi
и памятью EEPROM
, REST Api
и веб интерфейс - все это уже реализовано в библиотеке. По умолчанию в библиотеке так же включена поддержка обновлений по воздуху Arduino OTA
.
Упомянутая ранее конфигурация устройства - набор пар ключ-значение. Ключ указывает разработчик, а значение задает пользователь в настройках устройства. Значения конфигурации сохраняются в памяти устройства, которые в дальнейшем может использовать разработчик.
Для датчиков были реализованы хуки - некая логика, которая должна быть исполнена при выполнении определенных условий. Например, если датчик температуры превысил указанное значение или если показатель снесора стал равен конкретному значению. Пока что реализовано три вида хуков:
хук действия - выполняет указанное действие устройства;
http хук - выполняет указанные запрос;
хук уведомления - отправляет уведомление на указанный в конфигурации маршрутизатор.
Пока что поддерживаются только две платформы - esp32
и esp8266
. Они доступны, достаточно производительны и имеют обширную фанбазу. В качестве беспроводного интерфейса был выбран WiFi
, но так же в планах добавдение поддержки взаимодействия посредством BLE
. Неиспользуемый функционал библиотеки можно отключить и убрать на этапе компиляции, что позволит уменьшить размер финальной прошивки. Для удобства отладки по сети был реализован простой сетевой логгер на базе tcp
, но есть и обычный serial
. Также есть свой механизим обнаружения в сети на базе udp multicast
сокета, в данный момент ведутся работы по переводу на mDNS
.
Репозиторий библиотеки и ее фронтенда.
Все это конечно прекрасно, но можно ли примеров кода?
Для описания будущего устройства есть несколько основных глобальных объектов:
ActionsManager
- настройка действий устройства;SensorsManager
- добавление сенсоров;ConfigManager
- работа с конфигурацией;SmartThing
- самый главный, нужен для инициализации устройства и работы всех внутренних систем. Перед инициализацией необходимо произвести все настройки: добавление действий, датчиков и возможных конфигураций устройства. Например вот так мы можем добавить действия нашему устройству:
/* При добавлении действия необходимо указать: - его системное название - текст для отображения в UI - лямбду с логикой действия, которая возвращает true или false
*/
ActionsManager.add("led_on", "Turn led on", []() {
digitalWrite(LED_PIN, LOW); return true;
});
У устройства должны быть какие-то сенсоры? Не вопрос, добавим пару стандартых сенсоров:
// Метод добавляет сенсор с указанным названием, настраивает пин и читает его значение с помощью digitalRead
SensorsManager.addDigital"button", 12);
// А этот читает значение с пина с помощью analogRead
SensorsManager.addAnalog("analog", 14);
Так же можно добавить сенсоры с кастомной логикой, например если взаимодействие с сенсором происходит через вспомогательную библиотеку. Есть два вида кастомных сенсоров, которые различаются по типу возвращаемых данных - числовой (int
) и текстовый (String
).
// Числовой сенсор по умолчанию хранит в себе long
// Добавление числового сенсора с кастомной логикой вычисления значения
SensorsManager.add("sensor", []() {
return tempSensor.readData();
});
// Текстовый сенсор по умолчанию хранит в себе String
// Добавление текстового сенсора
SensorsManager.add("led", []() { // Пример возможной логики вычисления значения
return digitalRead(LED_PIN) == HIGH ? "on" : "off";
});
А если мы хотим дать пользователю возможность настраивать устройство? Для этого можем добавить информацию о возможной конфигурации:
// Для добавления конфигурации необходимо указать уникальное название ключа
ConfigManager.add("test-value");
// Получить его значение в коде, по ключу
ConfigManager.get("test-value");
// Можно добавить слушатель на обновление конфигурации устройства
ConfigManager.onConfigUpdate([]() {
st_log_debug("main", "Config updated!");
});
Значения конфигурации хранятся в виде строк. Значения хранятся в EEPROM
памяти устройства и доступны после перезагрузки устройства.
После всех произведенных настроек можно инциализировать устройство:
// Необходимо указать тип устройства
if (!SmartThing.init("lamp")) { // Не удалось инциализировать устройство
st_log_error("main", "Failed to init SmartThing!");
while(true) {
delay(1000);
}
}
При инциализации необходимо указать тип устройства. Тип устройства может быть любой, тут уже полет фантазии разработчика.
Если используется esp8266
как платформа, то необходимо в главном методе loop указать вызвов метода SmartThing.loop()
:
void loop() {
SmartThing.loop();
delay(250);
}
В случае esp32
этого делать не надо, loop метод будет вызываться в отдельной асинхронной таске.
Встроенные фичи
Вы могли обратить внимание на странные методы st_log_error
и st_log_debug
в примерх - это макросы для логирования. Кроме них есть еще st_log_info
и st_log_warning
. Их название соотвествует уровню логов. По умолчанию используется стандартный сериал, но в настройках устройства можно будет указать tcp
сервер для получения логов. После подключения к серверу устройство будет слать все сообщения туда обычным текстом. В маркосах первый параметр - тег, второй - шаблон сообщения. Далее идут возможные параметры для шаблона.
Из дополнительных настроек прошивки - вы можете отключить неиспользуемый функционал с помощью так называемых фича флагов. Такое отключение на этапе сборки поможет уменьшить размер финальной прошивки, а в некторых случаях - значительно. Например у вашего устройства нет никаких действий и вам не нужнен функционал конфигурации. Тогда в параметрах сборки необходимо указать два параметра (пример из platformio.ini
):
build_flags =
'-DENABLE_ACTIONS=0'
'-DENABLE_CONFIG=0'
Это отключит весь связанный с действиями и конфигурацией функционал. Список доступных фича флагов описан тут.
И это в принципе все, что необходимо сделать для создания вашего устройства. Далее прошивку можно загружать на устройство. Пример прошивки можно подсмотреть в тестовом репозитории.
Для ещё большего упрощения начала разработки устройства был сделан простой конструктор прошивки SmartThingBuilder
. Он позволит создать каркас будущего устройства, где разработчику надо будет только точечно добавить свою логику в нужных местах.

Для сборки и загрузки прошивки используйте свою любимую IDE, но я бы рекомендовал platformio. Инструкций на эту тему в интернете уже множество, поэтому опущу этот момент.
А что получим?
Что же мы получим, после произведенных манипуляций? При первом запуске устройство создаст точку доступа с названием st-device
. Подключаемся к ней и переходим по адресу http://192.168.1.4/
в браузере - откроется панель управления устройством. Она позволяет настраивать устройство, вызывать его действия, просматривать показания сенсоров и управлять их хуками, а так же менять значения конфигурации. Есть также вкладка с некоторыми метриками и вкладка для опасных действий, но давайте обо всем по порядку.
Первая вкладка - информация об устройстве (Information
). Здесь отображается основная информация об устройстве. Можно поменять имя устройства, т.к. по умолчанию будет указано st-device
.

Следующая вкладка - настройки WiFi
. Тут расположились базовые настройки WiFi устройства.

На данный момент есть три режима работы WiFi:
Подключение к существующей точке доступа;
Создать свою точку доступа с указанными параметрами;
Создать точку доступа, если не удалось подключиться к указанной.
После сохранения настроек WiFi устройство необходимо перезагрузить. Есть планы по добавлению сканера WiFi сети и тестового подключения к точке доступа.
Третья вкладка Actions
позволяет выполнять действия устройства, а так же настроить переодичность их вызова (иконка таймера).

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

Что такое хук? Если очень грубо говоря - некая логика, которая будет вызвана при соблюдении определенных условий. В данном случае условие - это изменение значения сенсора. Можно указать триггерное значение, для числовых сенсоров можно так же указать порог срабатывания.

На данный момент реализовано три хука:
action - вызовет указанное действие устройства;
http - отправит http запрос согласно параметрам;
notification - отправит уведомление на маршрутизатор
SmartThingGateway
, про который расскажу чуть позже. Адрес маршрутизатора берется из конфигурации устройства.
У хуков http и notification поддерживаются плейсхолдеры в текстовых полях для текущего значения сенсора ({v}
) и значений из конфигурации ({ключ}
). Например, нам необходимо отправлять запрос со значением сенсора на некий сервер. В конфигурацию можно добавить поле server_address
, на которое мы будем потом ссылаться через {server_address}
. Конфигурация http
хука в таком случае будет выглядеть следующим образом.

Пусть значение сенсора button = 1, а server_address = "192.168.1.2" при вызове хука, тогда payload
преобразуется в {"value": "1"}
, а url
в http://192.168.1.2/api
. Возможно это не самый лучший пример, но тут скорее цель продемонстрировать возможности.
Для проверки хука можно сделать его тестовый вызов нажатием на пробирку.

Следующая на очереди вкладка Configuration
- конфигурация устройства. Тут все достаточно просто - название настройки и поле для ввода.

Есть два системных значения:
laddr - адрес сервера для получения логов устройства;
gtw - адрес маршрутизатора
SmartThingGateway
, используется для уведомлений;
Предпоследняя вкладка Metrics
содержит в себе значения параметров системы и потребляемых ресурсов.

И последняя вкладка Danger zone
. Тут спрятаны опасные действия - перезагрузка устройства и сброс системы до заводских настроек.

В зависимости от включенности фича флагов может меняться набор доступного функционала в панели управления (как и в коде). Например, при отключении функционала действий (ENABLE_ACTIONS = 0
), пропадет не только вкладка действий, но и так же хук action
.
Если отключить полную версию веб страницы через фича флаг (ENABLE_WEB_PAGE = 0
), то пользователю будет доступна только урезанная версия панели управления. В ней доступен функционал с вкладок Information
, WiFi
и Danger zone
из полной версии.

Минимальная версия веб страницы по умолчанию включена для esp8266
, так как данная платформа имеет небольшой объем памяти.
И как мне управлять этим зоопарком?
Когда у вас только пара - тройка таких устройства, то в целом можно пользоваться только их веб интерфейсом и не знать проблем. Но если их больше? Да и как быстро находить их в сети, если вдруг сменился их IP? Для упрощения поиска и настройки устройств на базе обозреваемой библиотеки было так же разработано приложение локального маршрутизатора-оркестратора - SmartThingGateway
.
В маршрутизаторе реализовано несколько основных фич:
поиск устройств в локальной сети или добавление по IP;
управление найденными устройствами;
просмотр логов с подключенных устройств;
выгрузка и загрузка дампов памяти устройств;
обновление устройств через
Arduino OTA
;подключение к облачному сервису
SmartThingCloud
для доступа извне (про него будет рассказано чуть позже).
Так же устройства могут отправлять уведомления на маршрутизатор для пользователя с помощью ранее упомянутых хуков. Для этого необходимо в конфигурации устройства указать в параметре gtw
указать адрес маршрутизатора в формате адрес:порт
. По умолчанию порт 8080
, он совпадает с основным веб портом.
Репозиторий маршрутизатора и репозиторий вебинтерфейса.
Запуск
Приложение маршрутизатора собрано в виде jar файла, который запускается на любом устройстве, поддерживающем jvm, в локальной сети. Версия java - 17. В репозитории есть так же конфигурация docker compose и шаблон сервиса systemctl для удобства. Через переменную окружения port
можно указать порт для взаимодействия с интерфейсом и api: java -Dport=80 -jar gateway.jar
. По умолчанию порт 8080
.
Управление устройствами
В панели управления отображется два списка устойств:
найденные устройства в локальной сети;
добавленные пользователем вручную.
Поиск устройств реализован на базе UDP mutlicast
сокете. В планах реализовать поддержку mDNS
. Если по каким то причинам устройство не ищется - можно попробовать добавить вручную, указав IP адрес устройства. После выбора любого устройства из списка откроется его панель управления. Её функционал совпадает с функционалом панели управления в веб интерфейсе устройства, поэтому повторно разбирать все вкладки не будем.

Просмотр логов устройств
У устройства в конфигурации можно указать адрес сервера для получения логов (параметр laddr
) в формате адрес:порт
. По умолчанию порт для подключения 7779
. При сохранении конфигурации устройство попытается подключиться по указанному адресу и в случае успеха будет слать туда все логи.
Для удобства просмотра логов устройств была добавлена соотвествующий раздел в интерфейсе SmartThingGateway
. На ней можно просматривать сообщения с подключенных устройств, есть несколько простых фильтров. Для удобства сообщения разных устройств подкрашиваются разным цветом.

Пока что отображаемые логи хранятся в памяти и не подгружаются при перезапуске маршрутизатора. Однако все они пишутся в отдельный файл логов.
Выгрузка дампов памяти EEPROM
В SmartThingGateway
так же был добавлен фукнционал для выгрузки, сохранения, управления и загрузки дампов памяти устройств с их настройками. В данном дампе есть настройки имени, wifi, значения конфигурации и настройки хуков. Этот функционал может быть полезен для переноса настроек с одного устройства на другое, для быстрой настройки нового устройства или для бекапа.

Обновление прошивки устройства
SmartThingGateway
так же имеет простой менеджер прошивок. Можно добавлять и загружать на устройства заранее скопилированные прошивки устройств. Для загрузки на устройство используется протокол Arduino OTA
. При добавлении прошивки необходимо указать платформу, тип устройства, которое реализует прошивка, и версию.

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

А как мне получить доступ снаружи?
Любой нормальный умный дом не считается до конца умным, пока к нему нету доступа из глобального интернета. Ествественно в данном проекте реализована такая фича в виде еще одного приложения - SmartThingCloud
. Оно запускается где-то в глобальной сети (на VPS например), после чего к нему можно подключать маршрутизаторы с помощью специальных токенов. Репозиторий проекта можно найти тут. Для запуска рекомендуется использовать docker.
Пользователи указываются в конфигурации, они будут созданы при запуске приложения. Для подключения локального маршрутизатора к облаку пользователь сначала добавляет в облаке описание маршрутизатора, после чего генерирует токен для его подключения.

Далее в интерфейсе маршрутизатора этот токен используется для подключения к облаку. После подключения в облаке будет доступна панель управления устройствами из маршрутизатора.

Что дальше
Хоть проект находится в работоспособном состоянии, он далек от завершающей стадии. Имеется ещё множество фич, которые хочется сделать и доделать. Будут новые хуки, попытки оптимизации прошивки, косметические правки интерфейса и расширение функционала маршрутизатора. Так же планируется доработать механизм взаимодействия устройств разных маршрутизаторов.
Но главной целью этой статьи является получение фидбека от людей, которые воспользуются данной системой для разработки своих устройств.
Огромное спасибо за то, что дочитали статью до конца.