
В этой статье я хочу рассказать о своем опыте создания IoT самоделки и интеграции ее в облако Tuya (также известного как Smart Life)
С чего все начиналось
Чуть больше года назад у меня появился увлажнитель воздуха. Так как я являюсь адептом всевозможных автоматизаций и умного дома, увлажнитель сразу выбирался с Wi-Fi и возможностью управления через облако. Я использую Smart Life, так как это наиболее универсальный вариант, который работает почти со всеми устройствами умного дома. Российские сервисы типа Алисы или Маруси гораздо более привередливы к типам устройств (например, тот самый увлажнитель подружить с Алисой так и не получилось). Плюс ко всему, в большинстве случаев синхронизация с ними осуществляется через тот же Smart Life.
После покупки увлажнителя естественным образом возникла идея поставить в комнату какой-нибудь датчик влажности и прописать сценарии, чтобы поддерживать влажность в комнате на одном уровне. Однако беглый поиск готовых вариантов разочаровал: либо дорого, либо плохие отзывы. Основной поток жалоб был на точность, показания у двух одинаковых датчиков, судя по отзывам, могли отличаться на 10 и более процентов. После того, как ни один из готовых вариантов не понравился, я решил попробовать сделать свой.
Составляем ТЗ
Итак, основным требованием к девайсу было показывать влажность и передавать показания в Smart Life. Сразу к этому добавилось желание видеть и температуру воздуха в комнате (подавляющее большинство датчиков влажности совмещено с датчиками температуры). Помимо этого появилась идея мониторить уровень углекислого газа. Это довольно полезная функция, чтобы знать, когда нужно проветривать. Например, можно сделать сценарий с уведомлением на смартфон.
Также хотелось иметь обычные часы (дата и время). Причем, раз мы подключаемся к облаку, значит, будем иметь доступ в Интернет, и можем брать время с NTP серверов. То есть в системе не нужен модуль реального времени. Также доступ в Интернет дает возможность подключиться к какому-нибудь метео-API и брать оттуда данные о погоде на улице.
Выбор дисплея
Следующим вопросом было на чем это все отображать. По сути вариантов не очень много: чаще всего на готовых решениях используется LCD дисплей без подсветки. Однако найти такой именно под свои задачи довольно сложно. Почти все такие дисплеи сегментные, то есть на них заранее есть области, которые будут темнеть или, наоборот, светлеть. Поэтому найти модуль с нужным расположением сегментов - это еще более сложная задача. И даже если найти получится, такой вариант существенно ограничивает р��зработчика в дальнейших апгрейдах системы. Поэтому очень хотелось экран, где можно управлять пикселями.
Среди таких вариантов доминируют цветные LCD дисплеи с подсветкой. Еще есть недорогие монохромные OLED дисплеи, но они обычно крошечные. Кроме того, оба вышеперечисленных варианта имеют проблемы с работой ночью, так как подсветка в темноте может быть очень яркой и мешать спать.
Итого получается, что нужно что-то без подсветки, но с возможностью управлять пикселями. Такой вариант есть, и называется он E-Ink (или электронные чернила). Эта та самая штука, которая есть в каждой читалке для электронных книг. У нее есть важные преимущества:
Отсутствие подсветки. Внешне дисплей выглядит как лист бумаги
Возможность управлять каждым отдельным пикселем
Наличие недорогих модулей на маркетплейсах
Простота управления этими модулями (не сложнее, чем OLED или LCD)
Минусы тоже есть:
Монохромность. Большинство вариантов могут красить пиксель в черный или белый. Градаций цвета нет. Есть варианты с тремя цветами (добавляется красный). Есть и полноцветные, но их стоимость в разы выше
Скорость обновления. Полностью экран обновляется за пару секунд. Для применения в метеостанции это не очень кричично, обновление там происходит раз в минуту (для времени) и еще реже (в среднем) для показателей климата. Также проблему решает частичное обновление экрана (это гораздо быстрее)
Как ни странно, энергонезависимость. Если вдруг система отключится или зависнет, экран не отключится. В итоге узнать о проблеме можно будет только по отставшим часам. Решается проблема через облачный контроль, например, теми же уведомлениями.
В итоге было решено строить систему вокруг такого дисплея.
Датчики
Нужно было выбрать достаточно точные датчики температуры/влажности и углекислого газа. С последним я долго не думал и взял MH-Z19. Да, дорого, но зато точно и стабильно.
С температурой/влажностью выбирал дольше. Хотелось хорошую точность за приемлемую цену. В итоге остановился на SHT-41. Погрешность по температуре у него 0.2 градуса, по влажности от 1.5 до 2.5 процентов, что для моих задач вполне подходило.
Контроллер
От контроллера в такой системе требуется не очень много. По сути, подключаться к Wi-Fi, собирать данные с датчиков и выводить все на экран, а так же отправлять в облако. Из доступных контроллеров такое "из коробки" умеют ESP32 и ESP8266. Так как стоят они примерно одинаково, а 32-я гораздо мощнее и несет больше памяти, выбор был очевиден.
Собираем все вместе
Так как систему я собирал в единичном экземпляре (потом сделал еще одну на подарок), делать печатную плату не стал. Собрал все на макетной плате. Компоновку сделал так, чтобы максимально удалить датчик температуры от ESP - возможного источника нагрева.



У MH-Z19 есть несколько способов передачи данных - аналоговый, через ШИМ и через UART. Я выбрал последний способ, так как это позволяет управлять самим датчиком, например, калибровать.
Датчик температуры подключается по I2C, экран - по SPI. Кнопку добавил для сброса и некоторых настроек.
Корпус печатал на 3D принтере. Он состоит из трех сегментов, основная часть, деталь, которая прижимает экран, и крышка. На крышке есть вырез, чтобы чем-нибудь тонким можно было нажать кнопку для сброса.
Прошивка
Так как ESP32 работает со своей операционной системой, есть возможность писать многопоточный код, чем я и воспользовался. Архитектура прошивки строится вокруг общего состояния, с read-write доступом для потоков, общих настроек с таким же доступом и самих потоков-воркеров. Каждый из них, если нужно, читает состояние, выполняет какое-то свое действие, обновляет состояние и засыпает на свой тайм-аут. Вот список воркеров:
sensorUpdateTask - раз в 30 секунд снимает показания со всех датчиков и записывает в общее состояние
displayUpdateTask - раз в секунду читает состояние. Если что-то изменилось, обновляет дисплей
wifiUpdateTask - раз в секунду проверяет доступность wifi. Если доступ потерян, выставляет флаг в состоянии. Если флаг выставлен, то воркеры, которым нужен Интернет, встают на паузу до восстановления подключения, которое инициируется этой же задачей
timeUpdateTask - раз в секунду берет системное время и прописывает его в состояние. Системное время синхронизируется с NTP серверами автоматически силами ESP32
weatherUpdateTask - раз в 15 минут обращается к API и получает данные о погоде. Обновляет состояние
tuyaTask - раз в минуту читает состояние и отправляет показания датчиков в облако. Подробнее о механизме отправки в следующем разделе.
Для обеспечения согласованности общее состояние имеет мьютекс. Для чтения или изменения состояния воркер захватывает мьютекс. Причем, чтобы не тормозить остальных воркеров, реализован принцип записи из локального состояния. Например, воркер получения погоды, захватывает мьютекс, получает информацию, что Интернет доступен, и отпускает мьютекс. После этого следует запрос к API, который может занять много времени. Когда данные уже получены, следует новый захват мьютекса и обновление состояния. Таким образом, не происходит длительной блокировки остальных потоков. Аналогично работают и другие воркеры.
Такая архитектура позволяет избегать deadlock'ов. Но на всякий случай дополнительно используется механизм watchdog, который есть в операционной системе ESP32. Он перезагрузит всю систему, если один из воркеров зависнет на долгое время.
Подробнее код можно посмотреть на Github: https://github.com/VGorash/VG_Meteo
Работа с облаком
Самым сложным в этом проекте было разобраться с тем, как подключить свое устройство к Tuya. Документации по этому вопросу не очень много, поэтому многое приходилось выяснять на своих ошибках.
Итак, в первую очередь необходимо создать новый продукт на платформе разработки. Выбираем тип продукта, у меня это Temperature and Humidity Clock. Далее необходимо выбрать протокол. В нашем случае подходит только один - TuyaLink. После это выбираем метод связи - WiFi.

После создания продукта необходимо настроить его Data Points. Это те показания, которые мы хотим видеть в облаке. У меня это три показания: температура, влажность и CO2. Создаем кастомные варианты, так как стандартных для TuyaLink не предлагается.

Теперь идем на вкладку Device Management. И вот тут начинается самое неочевидное. Нам надо привязать девайс, но не просто так, а в конкретный дата-центр. Если выбрать не тот, подключиться из мобильного приложения потом не получится. Для подключения девайса нужна лицензия API. Для каждого проекта дается две бесплатных лицензии. И тут проблема: для России и СНГ нужно выбирать Central Europe Data Center, а лицензию можно получить только для китайского. Но есть решение. Выбираем китайский дата-центр, запрашиваем бесплатную лицензию. Обычно ее дают в течение минуты-двух.

Далее нужно перенести лицензию. Для этого кликакем на "Remaining Licenses" (рядом с кнопкой получения), в окне переноса выбираем Central Europe Data Center и наш проект.
Теперь у нас есть лицензия, и мы можем зарегистрировать продукт. Для этого возвращаемся в Device Management, обязательно переключаемся на Central Europe Data Center и кликаем на Register Device. В форме можно ничего дополнительно не заполнять, просто подтверждаем. Поздравляю, девайс зарегистрирован.
Теперь нужно научить нашу систему отправлять данные в облако. Для этого используется MQTT. Для подключения можно использовать любую библиотеку, основной нюанс в имени пользователя и пароле. Сначала нам нужно узнать Device ID и Device Secret. Для этого на вкладке Device Management выбираем наш девайс, который мы зарегистрировали, справа кликаем на три точки и жмем Details.

Имя пользователя - это Device ID (еще важно не перепутать его с Product ID), но не сам по себе, а с дополнительной информацией. В моей прошивке есть функция, которая готовит правильное имя пользователя:
String calculateUsername(int64_t timestamp)
{
return String(DEVICE_ID) + String("|signMethod=hmacSha256,timestamp=") + String(timestamp) + String(",secureMode=1,accessType=1");
}
Timestamp берем из системного времени. С паролем еще сложнее. Он строится из Device Secret, через хэширование. Для этого берется строка из ID, таймстампа и служебной информации, хэшируется через SHA256 HMAC, и потом к ней добавляется Device Secret, так же в виде хэша:
String calculatePassword(int64_t timestamp)
{
byte password_bytes[32];
char password[65];
Serial.print(timestamp);
Serial.print("\n");
const char* secret = DEVICE_SECRET;
const char* content = (String("deviceId=") + String(DEVICE_ID) + String(",timestamp=") + String(timestamp) + String(",secureMode=1,accessType=1")).c_str();
SHA256 hasher;
hasher.resetHMAC(secret, strlen(secret));
hasher.update(content, strlen(content));
hasher.finalizeHMAC(secret, strlen(secret), password_bytes, 32);
arrayToString(password_bytes, 32, password);
return String(password);
}
Еще у нас нет сертификатов TLS на нашем контроллере. И есть два варианта, установить его туда или проигнорировать. Я выбрал второй вариант, так как мой проект не связан с чем-то конфиденциальным. Но в других случаях безопасностью пренебрегать не стоит.
Когда мы подключились к серверу, надо передавать туда данные. Это делается в формате JSON, но опять же с дополнительной информацией. Мой код отправки выглядит вот так:
String topic = String("tylink/") + String(DEVICE_ID) + String("/thing/property/report");
char buffer[512];
sprintf(
buffer,
"{\"msgId\":\"%llu\", \"time\":%llu, \"data\":{\"temperature\":{\"value\":%d,\"time\":%llu},\"humidity\":{\"value\":%d,\"time\":%llu},\"co2\":{\"value\":%d,\"time\":%llu}}}",
m_messageCounter++,
timestamp,
(int)(temperature),
timestamp,
(int)(humidity),
timestamp,
co2,
timestamp
);
m_client->beginMessage(topic.c_str());
m_client->print(buffer);
m_client->endMessage();
Если все сделано правильно, система подключится к облаку и начнет передавать данные. Проверить это можно на вкладке Online Debugging. Выбираем девайс, и можно посмотреть, что он присылает, и как это интерпретирует облако.

Приложение
В принципе уже в таком виде все будет работать. Можно подключать метеосистему к приложению Smart Life. Для этого сначала нужно включ��ть возможность биндинга во все аккаунты. Переходим на вкладку Device Configuration, дальше Binding Configuration, и включаем возможность биндинга для всех аккаунтов.

После этого можно подключать к приложению. Для этого переходим на вкладку Device Management, справа выбираем QR Code Binding. Tuya сгенерирует QR код, который нужно отсканировать в приложении Smart Life. Все, теперь мы можем видеть показания нашей системы в приложении и использовать их в своих сценариях.
Интерфейс
На этом в принципе можно и остановиться, но мне хотелось видеть не скучные цифры на белом фоне, а полноценную страницу девайса. Например, хотелось бы смотреть графики показаний за день, неделю и так далее.
Чтобы это сделать, нам нужна своя панель для девайса. На сайте платформы очень мало документации, как это нужно делать. Я потратил несколько вечеров, чтобы со всем разобраться.
Итак, в первую очередь нам нужно создать клауд проект для нашей панели. Для этого на платформе переходим на страницу создания клауд проектов и создаем.

При создании проекта выбираем метод разработки Smart Home и наш европейский дата-центр.
Теперь нужно создать мини-приложение, которое и будет нашей панелью. Для этого в нашем девайсе заходим во вкладку Application Development, выбираем там Panel Development -> Self-Developed Panel. Дальше нас перекинет на страницу создания мини-приложений. Создаем там новое приложение и линкуем его к проекту, который создали ранее.
Теперь все готово для разработки. Нужно скачать их IDE для мини приложений. Мини-приложения по сути являются веб-приложениями на React. IDE позволяет сконфигурировать проект и дебажить его. Редактора кода там нет. Я использовал для работы с кодом Web Storm.
При создании проекта можно выбрать готовый шаблон. И там есть как раз довольно удачный пример для датчика температуры и влажности, сразу с графиками. Я выбрал этот шаблон и дальше редактировал проект. Убирал ненужные функции, добавлял график для CO2, менял ID для Data Points. Когда все готово, можно через IDE сгенерировать код для дебага в реальном Smart Life. После дебага релизим приложение и отправляем его на ревью. Оно, судя по всему, формальное и автоматическое. У меня аппрув пришел буквально в течение минуты. После аппрува можно возвращаться на страницу девайса и линковать к нему наше мини-приложение.
Отдельно стоит сказать про графики. Если запустить приложение просто так, работать будет все, кроме графиков. Чтобы они заработали, надо включить накопление статистики. Это делается через заявку, которую уже обрабатывают вручную. В заявке нужно указать продукт и ID Data Point'ов, для которых нужна статистика.

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

kalapanga
18.11.2025 06:28Спасибо за интересную статью! Есть вопрос. Сейчас устройство видно в Smart Life. А увидит ли его например Умный дом Яндекса как прочие устройства из аккаунта Smart Life (розетки, выключатели)? Или для этого нужны ещё какие-то действия? Или это совсем невозможно?

viacheslav_gorash Автор
18.11.2025 06:28Я пробовал с Яндексом, но у меня не получилось. Там есть функция синхронизации устройств со Smart Life. Но при этом подтягиваются не все устройства. Например, фабричный датчик влажности подтянулся, а мой - нет. Но при этом фабричный увлажнитель воздуха не подтянулся. Каких-то критериев, что нужно Яндексу для распознавания датчика, я нигде не нашел.
Как вариант, если нужна синхронизация именно в Яндекс, можно попробовать через разработку навыка для Алисы, тогда вообще можно без Smart Life обойтись

xSVPx
18.11.2025 06:28>так как подсветка в темноте может быть >очень яркой и мешать спать.
Копеечный фотодиод преврашает брюки в систему на которой видно в любых условиях и ночью оно не мешает.
Вообще eink для автономности, тут в нём смысла ноль. Для удобства нужен rgb светодиод который показывает цветом текущий статус. У меня оранжевеет и краснеет если параметры выходят за норму.
И вот тогда я смотрю в цифры, и то не всегда, в целом они мало нтересны. А просто так в них никто никогда смотреть не будет. Это иначе не умный дом, а лютый гемморой. По хорошему и светодиод не нужен, т.е. ваши системы проветривания итп должны делать всё сами, и лишь в случае лютой аварии посылать уведомление в телефон. Но у меня пока нету электропривода на окнах...

viacheslav_gorash Автор
18.11.2025 06:28Вариантов индикации множество, и тут, скорее, вопрос вкуса и предпочтений. Я полагаюсь в основном на уведомления (они приходят на смарт-часы, которые всегда с собой). Но для визуального наблюдения светодиод или какая-то другая цветовая шкала тоже очень неплохой вариант. Автоматическое проветривание - это вообще лучший вариант, но, наверное, его надо делать не через привод на окне, а через бризер (регулировать поток воздуха с него по показаниям датчика)

NutsUnderline
18.11.2025 06:28Вообще eink для автономности
на вкус и цвет. как оказывается фанаты чернил готовы смотреть видео на таких экранах
rgb цвет тут недавно одни дизайнеры надизайнили как раз для такого
конкретно для внутреннего состояния это показометр, но метеостанция еще показывает внешнюю погоду ну и вообще всякое

veselovi4
18.11.2025 06:28Пародон. По итогу десплей то КАКОЙ использовали? Ценник на него вменяемый? ))

viacheslav_gorash Автор
18.11.2025 06:28EInk от WeAct. Чуть больше тысячи рублей на али. Вот: https://ali.click/8xttp6

NutsUnderline
18.11.2025 06:28я думаю полезным будет так же упомянуть что на ali есть готовые сборки e-ink экрана и esp32. с готовым корпусом и кнопочками, только датчики подключить. Есть точно такой же квадратный 4.2" и прямоугольный 5.79"
NutsUnderline
Вполне изящный проект.
tuya кажется идеалом по задумке, но как только видишь 5 несвязанных серверов, да все эти датапоинты то становится грусно.