Умный координатный домофон на ESP с плеером для камер
Зачем собирать домофон самому, если есть готовые?
Готовые видеодомофоны работают только со своими камерами и панелями. Интеграция с Home Assistant, Telegram-ботами или кастомными сценариями — закрытая тема. Хотите видеть на экране домофона картинку с IP-камеры во дворе? Производитель скажет «купите нашу камеру».
Самодельный домофон на ESP32 снимает эти ограничения. Подключаете любые RTSP-камеры, пишете свою логику открытия (по расписанию, по геолокации, по лицу), встраиваете в умный дом. Бюджет проекта — 3000-5000 рублей, время сборки — 2-3 выходных.
Проект требует навыков: пайка, базовый C++, понимание работы сетей. Если ни разу не прошивали ESP через Arduino IDE — начните с мигающего светодиода. Здесь сложнее.
На выходе получите: перехват вызова с координатной панели, двусторонний звук, видеопроигрыватель с камер на дисплее, веб-интерфейс для смартфона.
Как работает координатный домофон — без этого не соберёшь
Координатный домофон использует аналоговую матричную адресацию. В отличие от цифровых систем с шифрованием и протоколами, здесь всё просто — комбинация двух проводов определяет номер квартиры.
Матрица адресации: единицы и десятки
Вызывная панель имеет два ряда контактов: единицы (0-9) и десятки (0-9). Квартира 47 — это провод «4» из ряда десятков и провод «7» из ряда единиц. При наборе номера панель замыкает соответствующую пару, и сигнал вызова идёт только в нужную квартиру.
Схема коммутации на реле проще цифрового протокола: не нужно разбирать пакеты данных, достаточно детектировать замыкание линии. ESP32 будет слушать состояние проводов и определять момент вызова.
Что перехватывает ESP32
Микроконтроллер подключается параллельно штатной трубке. Детектирует вызов (появление напряжения на линии), управляет реле для снятия трубки и открытия двери, обеспечивает аудиоканал через I2S-кодек.
Собираем комплект: что купить и сколько это стоит
ESP32: WROOM, WROVER или S3 — что выбрать
Для видео с камер нужен WROVER — у него 4 МБ PSRAM. Обычный WROOM с 520 КБ RAM не потянет декодирование MJPEG-потока, кадры будут теряться. ESP32-S3 ещё лучше (больше производительности), но дороже и сложнее в настройке.
Берите ESP32-WROVER-E DevKit с USB-C — 400-600 рублей на AliExpress. GPIO достаточно для всех модулей: SPI-дисплей, I2S-аудио, 4 реле, детектор вызова.
Аудиотракт: микрофон + усилитель + динамик
Для двусторонней связи понадобятся:
- MAX98357A — I2S-усилитель для динамика, 80-120 рублей
- INMP441 — I2S-микрофон, 150-200 рублей
- Динамик 8 Ом 2 Вт — 50 рублей
Схема с I2S избавляет от аналогового шума и упрощает код. Один DMA-буфер на приём, один на передачу.
Реле и коммутация: 4-канальный модуль на 5В
Модуль на 4 реле с опторазвязкой — 150-200 рублей. Два реле для эмуляции снятия трубки, одно для открытия двери, одно в резерве. Опторазвязка обязательна: коммутация индуктивной нагрузки даёт помехи, которые перезагружают ESP32.
Дисплей для видео: ILI9341 3.5″ или больше?
ILI9341 3.5″ (320×480) — оптимальный выбор за 500-700 рублей. Работает по SPI, библиотека TFT_eSPI поддерживает аппаратное ускорение. Дисплеи крупнее (ILI9488, 4″) требуют больше RAM и тормозят на ESP32.
Итого: ESP32 (500) + аудио (350) + реле (200) + дисплей (600) + блок питания (400) + провода и разъёмы (300) = 2350-3500 рублей.
Рисуем схему: как всё соединить между собой
Распиновка: какие GPIO для чего
SPI-дисплей (VSPI):
- GPIO18 → CLK
- GPIO23 → MOSI
- GPIO19 → MISO
- GPIO5 → CS
- GPIO21 → DC
- GPIO22 → RST
I2S-аудио:
- GPIO25 → BCLK (общий для ADC и DAC)
- GPIO26 → LRC
- GPIO27 → DATA OUT (к усилителю)
- GPIO33 → DATA IN (от микрофона)
Реле:
- GPIO32, GPIO14, GPIO12, GPIO13 → через транзисторные ключи
Детектор вызова:
- GPIO34 (ADC) → делитель напряжения от линии домофона
Согласование 3.3В и 5В — где нужен конвертер
ESP32 работает на 3.3В, реле — на 5В. Прямое подключение GPIO к реле сработает (3.3В достаточно для триггера), но надёжнее поставить конвертер уровней или управлять через транзистор BC547.
Линия домофона может давать 12-18В. Подключайте через резистивный делитель (10кОм + 4.7кОм) и стабилитрон на 3.3В для защиты ADC.
Питание: почему один БП на всё — плохая идея
Реле при переключении создают импульсные помехи. Если ESP32 питается от того же источника — будут спонтанные перезагрузки.
Решение: БП 12В 2А, от него DC-DC преобразователь на 5В для реле и дисплея, отдельный DC-DC на 3.3В для ESP32. Конденсаторы 470 мкФ на каждой шине питания.
Пишем прошивку: координатный вызов за 200 строк кода
Структура проекта: что в каком файле
PlatformIO удобнее Arduino IDE для проектов с несколькими файлами:
/src
main.cpp — setup(), loop(), FSM
intercom.cpp — логика домофона
audio.cpp — I2S, микрофон, динамик
display.cpp — TFT_eSPI, видеопоток
network.cpp — WiFi, WebSocket
/include
config.h — пины, IP камер, таймауты
Конечный автомат вызова: IDLE → RING → TALK → OPEN
Конечный автомат (FSM) — правильный способ организации логики. Куча вложенных if-else превращается в спагетти на третий день разработки.
enum State { IDLE, RING, TALK, OPEN };
State currentState = IDLE;
void updateFSM() {
switch (currentState) {
case IDLE:
if (detectRing()) {
currentState = RING;
ringStartTime = millis();
playRingtone();
}
break;
case RING:
if (buttonAnswer()) {
pickupRelay(ON);
currentState = TALK;
talkStartTime = millis();
}
if (millis() - ringStartTime > RING_TIMEOUT) {
currentState = IDLE; // не ответили
}
break;
case TALK:
if (buttonOpen()) {
openDoorRelay(ON);
currentState = OPEN;
openStartTime = millis();
}
if (millis() - talkStartTime > TALK_TIMEOUT) {
pickupRelay(OFF);
currentState = IDLE;
}
break;
case OPEN:
if (millis() - openStartTime > OPEN_DURATION) {
openDoorRelay(OFF);
pickupRelay(OFF);
currentState = IDLE;
}
break;
}
}
Таймауты защищают от зависания: если не ответили за 30 секунд — сброс в IDLE. Если разговор длится больше 2 минут — отбой.
Дребезг контактов фильтруется программно: состояние считается изменённым, если держится стабильно 50 мс.
Управление реле: не сжечь GPIO
GPIO ESP32 даёт максимум 12 мА, реле требует 70-100 мА. Прямое подключение убьёт порт.
Схема с транзистором:
GPIO → резистор 1кОм → база BC547
коллектор → реле (-)
эмиттер → GND
реле (+) → 5V
Обратный диод параллельно катушке реле обязателен — гасит ЭДС самоиндукции.
Двусторонний звук: I2S + кодек MAX98357
#include <driver/i2s.h>
void setupAudio() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 256,
.use_apll = false
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
}
16 кГц достаточно для голоса. Буферы DMA по 256 сэмплов дают задержку около 16 мс — незаметно для разговора.
Добавляем видеопроигрыватель: смотрим камеры на дисплее
RTSP vs HTTP MJPEG — что потянет ESP32
H.264 требует аппаратного декодера, которого в ESP32 нет. Программное декодирование съедает 100% CPU и даёт 2-3 кадра в секунду. Неприемлемо.
MJPEG — поток отдельных JPEG-кадров. ESP32 декодирует JPEG аппаратно, получается 15-20 FPS на разрешении 640×480.
Настройте камеру на субпоток: основной поток пусть пишется на NVR в 1080p H.264, субпоток — 640×480 MJPEG для ESP32.
Библиотека esp32-camera: подключаем поток
Несмотря на название, библиотека esp32-camera работает и с внешними камерами по HTTP:
#include
#include
void fetchFrame() {
HTTPClient http;
http.begin("http://192.168.1.100/mjpeg/snap.cgi");
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
int len = http.getSize();
uint8_t buffer = (uint8_t )ps_malloc(len);
WiFiClient *stream = http.getStreamPtr();
stream->readBytes(buffer, len);
JpegDec.decodeArray(buffer, len);
drawFrame();
free(buffer);
}
http.end();
}
ps_malloc выделяет память в PSRAM — иначе буфер на 50-100 КБ не влезет в основную RAM.
Вывод на дисплей: TFT_eSPI и двойная буферизация
#include
TFT_eSPI tft = TFT_eSPI();
void drawFrame() {
uint16_t frameBuffer = (uint16_t )ps_malloc(320 480 2);
while (JpegDec.read()) {
for (int y = 0; y < JpegDec.MCUHeight; y++) {
for (int x = 0; x < JpegDec.MCUWidth; x++) {
int px = JpegDec.MCUx * 8 + x;
int py = JpegDec.MCUy * 8 + y;
frameBuffer[py 320 + px] = JpegDec.pImage[y 8 + x];
}
}
}
tft.pushImage(0, 0, 320, 480, frameBuffer);
free(frameBuffer);
}
Двойная буферизация убирает мерцание: пока один буфер выводится на экран, второй заполняется новым кадром.
Объединяем всё в сеть: ESP32, камеры, смартфон
Настройка сети: почему камерам нужен статический IP
ESP32 должен знать адрес камеры заранее — DHCP-lease может измениться после перезагрузки роутера. Задайте камерам статические IP в диапазоне 192.168.1.100-199, ESP32 — 192.168.1.50.
В config.h:
const char* CAMERA_IPS = {
"192.168.1.100", // подъезд
"192.168.1.101", // двор
"192.168.1.102" // парковка
};
Веб-интерфейс: открыл браузер — видишь камеру
AsyncWebServer раздаёт HTML-страницу и WebSocket для видео:
#include
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
void setupWebServer() {
server.on("/", HTTP_GET, (AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", "text/html");
});
server.addHandler(&ws);
server.begin();
}
index.html получает JPEG-кадры через WebSocket и рисует в canvas — работает на любом устройстве с браузером.
Подключаем смартфон: REST API или WebSocket?
WebSocket лучше для видео — постоянное соединение без накладных расходов на каждый кадр. REST API — для управления: /api/open (открыть дверь), /api/status (состояние системы).
Защищаем систему — чтобы сосед не открыл вашу дверь
HTTPS на ESP32: включаем за 10 строк
#include
const char* ssl_cert = R"(-----BEGIN CERTIFICATE-----
...ваш сертификат...
-----END CERTIFICATE-----)";
const char* ssl_key = R"(-----BEGIN PRIVATE KEY-----
...ваш ключ...
-----END PRIVATE KEY-----)";
server.beginSSL(ssl_cert, ssl_key);
Самоподписанный сертификат создаётся через OpenSSL за минуту. Браузер ругнётся один раз, потом запомнит.
Токен доступа вместо пароля
Пароль в URL — плохо, остаётся в логах. Генерируйте 32-байтовый токен и передавайте в заголовке:
void handleOpen(AsyncWebServerRequest *request) {
if (!request->hasHeader("X-Auth-Token")) {
request->send(401);
return;
}
if (request->getHeader("X-Auth-Token")->value() != AUTH_TOKEN) {
request->send(403);
return;
}
openDoor();
request->send(200, "text/plain", "OK");
}
Если нет сигнала с камеры — чеклист диагностики
Камера не отвечает на пинг
- Проверьте, что камера и ESP32 в одной подсети (192.168.1.x)
- Отключите изоляцию клиентов в настройках роутера
- Убедитесь, что статический IP камеры не конфликтует с DHCP-пулом
Видео дёргается или зависает
- Снизьте разрешение субпотока до 320×240
- Уменьшите качество JPEG до 50%
- Проверьте уровень сигнала WiFi — ниже -70 dBm будут потери пакетов
Перегрев ESP32 при длительной работе
ESP32 греется до 60-70°C под нагрузкой — это нормально. Если выше 80°C или перезагружается:
- Добавьте радиатор на чип
- Снизьте частоту CPU до 160 МГц (вместо 240)
- Обеспечьте вентиляцию корпуса
Матричная клавиатура 4×4: как подключить и опросить?
Матрица 4×4 использует 8 GPIO: 4 строки и 4 столбца. Подключайте к любым свободным портам (GPIO2, GPIO4, GPIO15, GPIO16 для строк; GPIO17, GPIO25, GPIO26, GPIO27 для столбцов — примерная раскладка).
Библиотека Keypad.h сканирует матрицу автоматически:
#include
char keys[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[4] = {2, 4, 15, 16};
byte colPins[4] = {17, 25, 26, 27};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);
void loop() {
char key = keypad.getKey();
if (key) handleKey(key);
}
Подтягивающие резисторы не нужны — библиотека использует внутренние pull-up.
Можно ли обойтись без проводов к вызывной панели?
ESP-NOW связывает два ESP32 на расстоянии до 200 метров прямой видимости. Один модуль ставится рядом с вызывной панелью, второй — в квартире.
Питание от 18650 аккумуляторов с deep sleep: в режиме ожидания потребление падает до 10 мкА. Одной батареи хватает на 6-12 месяцев при 5-10 вызовах в день.
Ограничения: задержка пробуждения 200-500 мс, возможны пропуски коротких вызовов. Для надёжной работы добавляйте буферный конденсатор, который держит питание во время пробуждения.
Какой блок питания взять для всей системы?
Расчёт потребления:
- ESP32 WROVER: 160-240 мА (пиково до 500 мА при WiFi-передаче)
- Аудиоусилитель MAX98357: 200-500 мА (зависит от громкости)
- 4 реле: 70 мА × 4 = 280 мА (все включены одновременно — редко)
- Дисплей ILI9341: 80-120 мА
Суммарно: 700-1500 мА в пике.
Рекомендация: БП 12В 2А (24 Вт) с запасом. От него два DC-DC: LM2596 на 5В 3А для реле и дисплея, AMS1117 на 3.3В для ESP32.
USB-питание от компьютера — плохо: порт даёт максимум 500 мА, при пиковой нагрузке напряжение просядет и ESP32 перезагрузится.
Первый запуск: что проверить перед подключением к подъездной линии
Не подключайте ESP32 к реальной линии домофона без тестирования на столе. Ошибка в коде может замкнуть линию и заблокировать домофон для всего подъезда.
Тест на столе:
- Подайте питание, откройте Serial Monitor
- Проверьте WiFi-подключение (должен получить IP)
- Откройте веб-интерфейс с телефона
Эмуляция вызова:
- Подайте 3.3В на GPIO детектора через резистор
- FSM должен перейти в состояние RING
- Нажмите кнопку «ответить» — реле должно щёлкнуть
Проверка видео:
- Откройте страницу с проигрывателем камер
- Убедитесь, что кадры обновляются без артефактов
- Протестируйте переключение между камерами
Чеклист готовности:
- Реле щёлкают по командам
- Звук идёт в обе стороны
- Видео с камеры отображается
- Веб-интерфейс открывается со смартфона
- Нет перегрева за 30 минут работы
Когда всё работает на столе — можно подключаться к линии. Начните с «только слушать» — детектор вызова без управления реле. Убедитесь, что определяете вызовы корректно. Потом добавляйте управление.
Следующий шаг — интеграция с Home Assistant через ESPHome или MQTT. Это откроет автоматизации: уведомления в Telegram, автооткрытие по геолокации, запись видео при вызове.
Проект сложнее, чем рассчитывали?
Одну плату собрать и отладить реально за пару выходных. Но если нужна связка из нескольких камер, интеграция с существующим домофоном и работающее решение без месяцев отладки — расчёт меняется. Тогда проще отдать проект нам.
Проектируем и монтируем системы видеонаблюдения, СКУД и домофонии под ключ. Работаем с частными домами, офисами и подъездами в Москве и области. За 10 лет реализовали больше 5000 проектов разной сложности.
Что получите:
- Проект под конкретные задачи: от одной камеры до интеграции с умным домом
- Монтаж с гарантией 3 года на оборудование и работы
- Бесплатный выезд инженера для оценки объекта
- Три варианта сметы за 24 часа: эконом, оптимум, максимум
Консультация бесплатная. Инженер приедет, покажет работу оборудования на месте и объяснит, какое решение подойдёт.
Телефон: +7 (495) 987-33-89
Адрес: Москва, Ленинский проспект д. 1/11
Время работы: Пн-Сб: 9:00-20:00
География: Москва и Московская область
Позвоните или оставьте заявку на сайте — обсудим задачу и предложим варианты.