Умный координатный домофон на ESP с плеером для камер
Ленинский проспект д. 1/11
Пн-Сб: 9:00-20:00
info@skudov.net оставить заявку

Умный координатный домофон на 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");
}

Если нет сигнала с камеры — чеклист диагностики

Камера не отвечает на пинг

  1. Проверьте, что камера и ESP32 в одной подсети (192.168.1.x)
  2. Отключите изоляцию клиентов в настройках роутера
  3. Убедитесь, что статический IP камеры не конфликтует с DHCP-пулом

Видео дёргается или зависает

  1. Снизьте разрешение субпотока до 320×240
  2. Уменьшите качество JPEG до 50%
  3. Проверьте уровень сигнала WiFi — ниже -70 dBm будут потери пакетов

Перегрев ESP32 при длительной работе

ESP32 греется до 60-70°C под нагрузкой — это нормально. Если выше 80°C или перезагружается:

  1. Добавьте радиатор на чип
  2. Снизьте частоту CPU до 160 МГц (вместо 240)
  3. Обеспечьте вентиляцию корпуса

Матричная клавиатура 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 к реальной линии домофона без тестирования на столе. Ошибка в коде может замкнуть линию и заблокировать домофон для всего подъезда.

Тест на столе:

  1. Подайте питание, откройте Serial Monitor
  2. Проверьте WiFi-подключение (должен получить IP)
  3. Откройте веб-интерфейс с телефона

Эмуляция вызова:

  1. Подайте 3.3В на GPIO детектора через резистор
  2. FSM должен перейти в состояние RING
  3. Нажмите кнопку «ответить» — реле должно щёлкнуть

Проверка видео:

  1. Откройте страницу с проигрывателем камер
  2. Убедитесь, что кадры обновляются без артефактов
  3. Протестируйте переключение между камерами

Чеклист готовности:

  • Реле щёлкают по командам
  • Звук идёт в обе стороны
  • Видео с камеры отображается
  • Веб-интерфейс открывается со смартфона
  • Нет перегрева за 30 минут работы

Когда всё работает на столе — можно подключаться к линии. Начните с «только слушать» — детектор вызова без управления реле. Убедитесь, что определяете вызовы корректно. Потом добавляйте управление.

Следующий шаг — интеграция с Home Assistant через ESPHome или MQTT. Это откроет автоматизации: уведомления в Telegram, автооткрытие по геолокации, запись видео при вызове.


Проект сложнее, чем рассчитывали?

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

Проектируем и монтируем системы видеонаблюдения, СКУД и домофонии под ключ. Работаем с частными домами, офисами и подъездами в Москве и области. За 10 лет реализовали больше 5000 проектов разной сложности.

Что получите:

  • Проект под конкретные задачи: от одной камеры до интеграции с умным домом
  • Монтаж с гарантией 3 года на оборудование и работы
  • Бесплатный выезд инженера для оценки объекта
  • Три варианта сметы за 24 часа: эконом, оптимум, максимум

Консультация бесплатная. Инженер приедет, покажет работу оборудования на месте и объяснит, какое решение подойдёт.


Телефон: +7 (495) 987-33-89
Адрес: Москва, Ленинский проспект д. 1/11
Время работы: Пн-Сб: 9:00-20:00
География: Москва и Московская область


Позвоните или оставьте заявку на сайте — обсудим задачу и предложим варианты.

    Быстрая консультация

    Оставьте заявку и наш менеджер свяжется с Вами в течении 15 минут.

    Как удобно связаться?