Наверное каждый любитель электроники имеет в запасе модули приобретенные на всякий случай. Так несколько лет назад я не смог пройти мимо 1.5 дюймового E-Ink дисплея, лежащего на витрине радиомагазина. Через некоторое время нашлось для него применение. В статье ESP32 E-Paper Thermometer описывается, как отображать окружающую температуру, измеренную с помощью датчика DS18B20. Проект выполнен в Arduino IDE. Но я решил пройти "Путь самурая" и портировать код на ESP-IDF. Пришлось немного повозится с библиотеками для работы с дисплеем. На этом мой путь не окончился, как говорят: "У самурая нет цели, есть только путь". И я решил, что было бы неплохо добавить еще несколько сенсоров, измеряющих влажность, давление, CO2, а потом отправлять эти данные по MQTT. В том же радиомагазине был приобретен фанерный домик-конструктор со светодиодным ночником. А в другом магазине - модуль с датчиками. Таким образом родилась идея сконструировать Micro-smart-home. На передней части домика расположен дисплей на пластиковых стойках. А с другой стороны расположен модуль с сенсорами.

Вид со стороны модуля с сенсорами

Модуль ESP32
В проекте используется модуль ESP32, приобретенный несколько лет назад.
Эта картинка соответствует его реальной распиновке. По размером он как раз помещается в домик. На картинке со стороны сенсоров видны пару винтов - это ESP32 крепится ими к боковой стенке.

Основные характеристики:
Процессор: Tensilica Xtensa LX6.
Память:
SRAM: до 520 КБ.
Flash: 4 МБ.
Беспроводная связь:
Wi-Fi 802.11 b/g/n.
Bluetooth 4.2 (BR/EDR и BLE).
Интерфейсы:
UART, SPI, I2C, I2S, PWM, ADC, DAC, GPIO.
GPIO: 25. (те что на модуле без учета питания и EN)
Подробнее в документации
E-Ink дисплей
Это модуль с диагональю 1.54 дюйма и разрешением 200×200 пикселей. Оснащён встроенным контроллером и использует интерфейс SPI для связи. Поддерживает частичное обновление экрана.
Благодаря таким преимуществам, как сверхнизкое энергопотребление, широкий угол обзора и возможность сохранять изображение без подачи питания, этот дисплей идеально подходит для использования в электронных ценниках, промышленных приборах и других встраиваемых системах.
Wiki страничка.
Отличие моего экземпляра в том, что у модуля имеется дополнительный набор выводов внизу. К этим выводам можно подключать стандартные перемычки.

Особенности
Не требует подсветки, сохраняет последнее изображение даже при отключении питания
Сверхнизкое энергопотребление — питание требуется в основном только при обновлении
Интерфейс SPI, совместим с такими платами, как Raspberry Pi, Arduino, STM32, ESP32 и др.
Встроенный преобразователь уровней напряжения, подходит для микроконтроллеров с питанием 3.3В и 5В
Поставляется с примерами кода и документацией (поддержка Raspberry Pi, Jetson Nano, Arduino, STM32)
Технические характеристики
Рабочее напряжение: 3.3В / 5В
Интерфейс: 3-проводный SPI, 4-проводный SPI
Габаритные размеры: 48 мм × 33 мм
Размер области отображения: 27.6 мм × 27.6 мм
Шаг пикселя: 0.138 мм × 0.138 мм
Разрешение: 200 × 200 пикселей
Цвета отображения: черный, белый
Уровни серого: 2
Время частичного обновления: 0.3 с
Время полного обновления: 2 с
Потребляемая мощность при обновлении: ~26.4 мВт
Потребляемая мощность в режиме ожидания: <0.017 мВт
Угол обзора: >170°
Назначение выводов
Обозначение | Назначение |
---|---|
VCC | Питание 3.3В / 5В |
GND | Земля |
DIN | SPI — линия MOSI |
CLK | SPI — линия SCK |
CS | Выбор чипа SPI, активный уровень — низкий |
DC | Выбор данных/команды (высокий уровень — данные, низкий — команда) |
RST | Аппаратный сброс, активный уровень — низкий |
BUSY | Статус занятости, активный уровень — высокий |
Датчик температуры DS18B20
DS18B20 — это цифровой датчик температуры, работающий по протоколу 1-Wire. Устройство поддерживает настраиваемое разрешение измерений от 9 до 12 бит и может сохранять полученные данные во встроенной энергонезависимой памяти (EEPROM). Благодаря поддержке 1-Wire-интерфейса, датчик может функционировать как в одиночном режиме, так и в составе сети, объединённой общей шиной, управляемой центральным микроконтроллером.

Диапазон измеряемых температур составляет от -55 до +125 °C. В пределах температур от -10 до +85 °C точность измерения достигает ±0.5 °C. В случае отсутствия внешнего источника питания датчик может использовать паразитное питание, получаемое непосредственно от линии передачи данных.
Каждый экземпляр DS18B20 имеет уникальный 64-битный идентификационный код. Этот код состоит из 8-битного кода семейства (28h), 48-битного серийного номера и контрольной суммы CRC (8 бит). Такая структура позволяет использовать множество датчиков на одной линии, обеспечивая их индивидуальную адресацию и управление с помощью одного микроконтроллера, даже если они распределены на значительном расстоянии друг от друга.
Основные параметры DS18B20:
интерфейс связи: 1-Wire;
диапазон рабочих температур: -55…+125 °C;
точность: ±0,5 °C в пределах от -10 до +85 °C;
формат хранения температуры: 9-битное значение;
максимальное время преобразования: 750 мс.
Внутренняя структура памяти DS18B20 включает как оперативную (RAM), так и энергонезависимую (EEPROM) части. В частности:
байты 0 и 1 содержат результат измерения температуры;
байты 2 и 3 — верхний (TH) и нижний (TL) температурные пороги;
байты 4 и 5 не используются;
байты 6 и 7 — счётчики, применяемые для повышения точности;
байт 8 содержит CRC-код для проверки целостности данных.
Дополнительные команды датчика, помимо стандартных для всех 1-Wire-устройств:
Alarm Search (ECh)
— поиск датчиков с тревожным значением температуры (вышедшей за пределы TH или TL);Convert T (44h)
— запуск процесса измерения температуры и сохранения результата в памяти;Write Scratchpad (4Eh)
— запись TH, TL и байта конфигурации в RAM;Read Scratchpad (BEh)
— чтение 9 байтов RAM, включая данные температуры и CRC;Copy Scratchpad (48h)
— перенос значений TH и TL из RAM в EEPROM.
Процедура получения данных температуры:
Инициализация шины 1-Wire (reset и поиск устройств).
Отправка команды
0x44
для начала преобразования температуры.Ожидание завершения измерения (не менее 750 мс).
Отправка команды
0xBE
для чтения содержимого RAM (температурные данные находятся в первых двух байтах).
DS18B20 поддерживает два варианта питания: стандартное (трёхпроводное подключение) и паразитное (двухпроводное), что позволяет гибко интегрировать датчик в разнообразные схемы и устройства.
Модуль датчиков CJMCU-8128
Данный модуль можно найти на Aliexpress.

Модуль объединяет три цифровых датчика — CCS811, HDC1080 и BMP280, обеспечивая измерение параметров качества воздуха, включая уровень летучих органических соединений (TVOC), влажность, температуру и атмосферное давление. Все датчики подключаются через стандартный интерфейс I2C, что упрощает интеграцию в различные проекты.
Основу контроля за загрязнением воздуха в помещении составляет газоанализатор CCS811, способный определять широкий спектр летучих органических соединений (TVOC) и рассчитывать эквивалентную концентрацию углекислого газа (eCO₂). Такие соединения зачастую присутствуют в воздухе из-за испарений от строительных материалов, бытовой электроники, офисного оборудования и даже дыхания человека. Хотя CCS811 изначально проектировался для использования в компактной электронике вроде умных часов и смартфонов, его версия в модуле адаптирована для использования на макетных платах и в прототипах, благодаря удобным контактным площадкам.
CCS811 поддерживает несколько режимов работы, что позволяет эффективно управлять энергопотреблением. Это особенно важно при использовании в автономных и портативных устройствах. На плате предусмотрены дополнительные пины для подключения термистора NTC, который может применяться для температурной компенсации показаний. Для стабильной и точной работы рекомендуется выполнить "прогрев" датчика — первые 48 часов после начала эксплуатации, а также 20 минут после каждого включения питания.
HDC1080 — это цифровой сенсор температуры и влажности, разработанный компанией Texas Instruments. Он отличается компактностью, энергоэффективностью и точностью, что делает его отличным выбором для измерения микроклимата в помещениях.
Дополняет комплект BMP280 — прецизионный барометрический датчик от Bosch, который способен измерять атмосферное давление и температуру. Он поддерживает высокоскоростной обмен по шине I2C и требует минимального энергопотребления, что делает его подходящим для метеостанций, высотомеров и других IoT-приложений.
К недостаткам данного модуля я отнес бы то, что из-за нагревания сенсора CCS811, другие датчики показывают завышенную температуру где-то на 2 °C.
Основные характеристики компонентов:
CCS811:
Диапазон измерения TVOC: 0–1187 ppb
Диапазон eCO₂: 400–8192 ppm
Режимы работы: 5 вариантов
Встроенный микроконтроллер для обработки данных
Интерфейс: I2C
Напряжение питания: 1.8–3.6 В
Температурная компенсация: с использованием внешнего датчика
HDC1080:
Интерфейс: I2C
Напряжение питания: 2.7–5.5 В
Разрешение: 0.1
Влажность: 0–100% RH
Температура: от –40°C до +125°C
Точность: ±3% RH, ±0.2°C
Заводская калибровка, дополнительных компонентов не требует
BMP280:
Напряжение питания: 1.71–3.6 В
Скорость интерфейса I2C: до 3.4 МГц
Ток потребления: 2.7 μA при 1 Гц
Уровень шума: до 0.2 Па и 0.01°C
Диапазон давления: 300–1100 hPa (примерно от +9000 м до –500 м)
Интерфейс: I2C
Калиброван на заводе
Полезные ресурсы:
Схема подключения.
Схема подключения нарисована во Fridzing. Библиотеки в основном скачивал готовые на просторах сети. Компонент для модуля CJMCU-8128 сделал по примеру на youtube. Модуль ESP32, который используется в действительности немного отличается набором пинов от библиотечного, но в целом расположение выводов соответствует.

А так выглядит картинка Fritzing на Breadboard вкладке

проект файла e-home.fzz
Реализация программной части
В исходном примере ESP32 E-Paper Thermometer проект выполнен в Arduino IDE. Библиотеки для работы с e-paper дисплеем и сенсорами модуля CJMCU-8128 также реализованы для Arduino. В первом варианте проекта я изрядно убил времени, чтобы собрать нужные исходные файлы и отредактировать существующие, а затем заставить работать дисплей на ESP-IDF. В обновленной версии проекта поступил намного проще. Первым делом создал новый проект в ESP-IDF 5.4.1 - последняя стабильная версия на момент написания. В ESP-IDF версии 5.x можно установить Arduino как зависимость.
idf.py add-dependency "espressif/arduino-esp32^3.0.2"
Библиотеки для дисплея
Далее собираем необходимые компоненты для работы дисплея. Клонируем следующие проекты в components каталог:
Adafruit-GFX-Library - основная графическая библиотека для Adafruit дисплеев, предоставляющая общий набор графических примитивов.
Adafruit_BusIO - вспомогательная библиотека для работы дисплея с I2C, SPI
GxEPD - библиотека отображения на e-paper дисплее с общим базовым классом и отдельным классом ввода-вывода для Arduino.
BitmapGraphics.h - необходим для отрисовки на дисплее пиктограммы термометра, символа °C и надписи Temperature
.
Есть уже готовая реализация Adafruit-GFX-Library-ESP-IDF. Я не пробовал работать с этой библиотекой, возможно с ней все проще. Также существует библиотека GxEPD2, возможно попробую использовать её.
Библиотека GxEPD реализует абстрактные методы Adafruit-GFX-Library. Из GxEPD нам нужно только GxGDEH0154D67-исходники для данного типа дисплея. GxEPD используется в ESP32 E-Paper Thermometer проекте, поэтому остановился на ней. Компилятор ESP-IDF 5.4.1 ругается на то, что методы класса GxIO не переопределены. В ранних версиях IDF такой ошибки не было. Проще всего можно добавить пустую реализацию методов или обозначить их как чисто виртуальные методы, добавив = 0 для виртуальных методов без реализации в заголовок GxIO.h
.
virtual void writeDataTransaction(uint8_t d) = 0;
virtual void writeData16Transaction(uint16_t d, uint32_t num = 1) = 0;
virtual void writeCommand(uint8_t c) = 0;
virtual void writeData(uint8_t d) = 0;
virtual void writeData(uint8_t* d, uint32_t num) = 0;
virtual void writeData16(uint16_t d, uint32_t num = 1) = 0;
virtual void writeAddrMSBfirst(uint16_t d) = 0;
virtual void startTransaction() = 0;
virtual void endTransaction() = 0;
virtual void selectRegister(bool rs_low) = 0;
virtual void setBackLight(bool lit) = 0;
Библиотеки для сенсоров
Для модуля датчиков CJMCU-8128 используются библиотеки Adafruit, CCS811 и ds18b20.
Adafruit_Sensor - унифицированный модуль абстракции для сенсоров от Adafruit.
Adafruit_BMP280_Library - библиотека для датчика измерения барометрического давления и температуры BMP-280.
Adafruit_Si7021 - библиотека для датчика влажности/температуры Adafruit Si7021.
CCS811 - библиотека Arduino для цифрового датчика газа CCS811 контроля качества воздуха в помещении.
ds18b20 - простая библиотека для одного DS18B20 на ESP32.
Эти библиотеки можно подключить как компоненты IDF, или просто просто как файлы проекта в основном модуле. Для IDF 5.x существует DS18B20 Device Driver с возможностью работы с многими DS18b20 сенсорами.
Подключение к Wi-Fi (режим STA):
EventGroup
— это механизм синхронизации задач в FreeRTOS. Он позволяет задачам или обработчикам событий общаться между собой с помощью набора битов (флагов), где каждый бит обозначает какое-то событие или состояние.
Создаётся группа событий wifi_event_group
, внутри которой будет использоваться, например, бит BIT0
(часто это 1 << 0
, то есть 0x01
), чтобы отслеживать успешное подключение к Wi-Fi.
Подключение к Wi-Fi:
После запуска Wi-Fi и выполнения
esp_wifi_connect()
ESP32 пытается подключиться к точке доступа.
Успешное подключение и получение IP:
В обработчике IP-событий:
case IP_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, BIT0);
Устанавливается битBIT0
— это сигнал, что подключение завершено успешно (ESP32 получила IP от DHCP).Ожидание в главной задаче:
Вwifi_start()
:
xEventGroupWaitBits(wifi_event_group, BIT0, false, true, portMAX_DELAY);
Эта строка блокирует выполнение функции до тех пор, пока не будет установленBIT0
, т.е. пока устройство не подключится к Wi-Fi.
Это нужно для того, чтобы не продолжать запуск MQTT-клиента, пока не будет Wi-Fi подключения.
Создание группы событий (
wifi_event_group
) - используется для синхронизации статуса подключения.Инициализация сетевого стека:
esp_netif_init()
— инициализация TCP/IP стека.esp_event_loop_create_default()
— создание цикла обработки событий.esp_netif_create_default_wifi_sta()
— создание интерфейса Wi-Fi в режиме станции (STA).
Инициализация Wi-Fi:
esp_wifi_init()
— инициализация драйвера Wi-Fi.Регистрация обработчиков событий Wi-Fi и IP (
esp_event_handler_instance_register
).
Настройка подключения:
Задание SSID и пароля в структуре
wifi_config_t
.Установка режима станции:
esp_wifi_set_mode(WIFI_MODE_STA)
.Применение конфигурации:
esp_wifi_set_config()
.
Запуск Wi-Fi:
esp_wifi_start()
— запуск Wi-Fi.В
WIFI_EVENT_STA_START
вызываетсяesp_wifi_connect()
.
Обработка событий:
При отключении (
WIFI_EVENT_STA_DISCONNECTED
) — попытка повторного подключения.При получении IP (
IP_EVENT_STA_GOT_IP
) — установка бита события (BIT0
) в группе событий.
Ожидание подключения:
xEventGroupWaitBits(..., BIT0, ...)
— блокирующее ожидание успешного подключения к Wi-Fi.
Исходный файл wifi.c.
Работа с MQTT:
Создание группы событий (
mqtt_event_group
) — для синхронизации при необходимости (в данном коде не используется явно).Настройка MQTT клиента:
URI брокера:
mqtt://192.168.1.107:1883
.Интервал Keepalive = 10 секунд.
Last Will сообщение при отключении:
"0"
в топикesp-home/status/activ
(с флагомretain
).
Инициализация и запуск:
esp_mqtt_client_init()
— инициализация клиента.esp_mqtt_client_register_event()
— регистрация обработчика событий.esp_mqtt_client_start()
— запуск клиента.
Обработка событий MQTT:
MQTT_EVENT_CONNECTED
— подписка наesp-home/cmnd/#
.MQTT_EVENT_SUBSCRIBED
— публикация"1"
вesp-home/status/activ
.MQTT_EVENT_DATA
— вывод полученных сообщений (топик + данные).Также логируются события отключения, ошибки, публикации и отписки.
Исходный файл mqtt.c.
Логика основного модуля
Инициализация:
Запуск системы:
Инициализация NVS (
nvs_flash_init()
).Подключение к Wi-Fi (
wifi_start()
).Запуск MQTT-клиента (
mqtt_app_start()
).
Создание задачи
display_task
:Задача отвечает за работу с сенсорами, отображение данных и отправку по MQTT.
display_task функция
1. Инициализация сенсоров и дисплея:
DS18B20 — температурный датчик на GPIO 25 (
ds18b20_init()
).I2C-шина (SDA=33, SCL=32) — для остальных сенсоров.
Сенсоры:
CCS811 — датчик CO₂ и TVOC.
BMP280 — температура и давление.
Si7021 — температура и влажность.
E-ink дисплей — инициализация с пиктограммой.
2. Основной цикл задачи
Считывание значений с сенсоров:
DS18B20 - температура на улице.
BMP280 — температура и давление в помещении.
Si7021 — температура и влажность в помещении.
CCS811:
Установка климатических данных (темп./влажн.) для компенсации.
Получение CO₂ и TVOC.
Обновление e-link дисплея:
Показывается температура с DS18B20 (частичное обновление).
Формирование JSON-строки (
sprintf
) с измерениями:Все значения сенсоров включаются в строку
buffer
в форматеPAYLOAD
.
Публикация данных через MQTT:
Тема:
"esp-home/send"
.Данные:
buffer
.
Задержка перед следующим измерением:
vTaskDelay(3000 / portTICK_PERIOD_MS);
(3 секунды).
Исходный файл main.cc
Структура проекта
home-sensors/
├── components/
│ ├── Adafruit_BusIO/ # Adafruit I2C/SPI bus abstraction library
│ ├── Adafruit-GFX-Library/ # Adafruit graphics primitives for displays
│ ├── Adafruit-sensors/ # Adafruit sensors
│ ├── ds18b20/ # 1-Wire DS18B20 temperature sensor driver
│ ├── GxEPD/ # E-paper display driver library
│ └── ccs811/ # CCS811 air quality sensor driver
├── main/
│ ├── BitmapGraphics.h # Header for bitmap/e-paper graphics utilities
│ ├── wifi.h # Wi-Fi connection management header
│ ├── mqtt.h # MQTT client interface header
│ ├── main.cc # Main application entry point
│ ├── wifi.c # Wi-Fi connection management implementation
│ └── mqtt.c # MQTT client implementation
├── CMakeLists.txt # Project build configuration
└── README.md # Project overview and instructions
Исходный код проекта находится в этом репозитории.
Заключение
Проект выполнен на ESP-IDF версии 5.4.1. Arduino-фреймворк подключен как зависимость espressif/arduino-esp32
. Такой подход позволяет достаточно легко адаптировать различные готовые решения Arduino-платформы на ESP-IDF. Но иногда требуется доработка библиотек и CMakeLists.txt - файлов. Необходимо обращать внимание на конфигурацию в исходниках библиотек, такую как инициализация портов ввода-вывода, шин I2C и прочего.
На ESP-IDF реализована логика считывания данных из сенсоров: DS18B20, CCS811, BMP280, Si7021, CCS811 с помощью библиотек для среды Arduino.
Портирован исходный код из проекта ESP32 E-Paper Thermometer для отображения температуры от датчика DS18B20 на E-Ink дисплее.
E-Ink дисплей подключен по SPI согласно дефолтной конфигурации в библиотеке.
Данные передаются по MQTT в домашнюю систему.