Разработка мобильного приложения для домофона/видеодомофона
Нажал кнопку на двери — телефон зазвонил, на экране видео с камеры, открыл дверь одним тапом. Это сценарий кажется простым, но внутри — WebRTC или SIP-стек, ONVIF-протокол, push-уведомление за доли секунды при закрытом приложении, управление реле замка через API устройства и запись событий. Проект на 4-12 недель в зависимости от требований к совместимости оборудования.
Стек: с чего начать проектирование
Первый вопрос: какое «железо» на двери?
Готовые IP-домофоны с SIP (Hikvision DS-KV6113, Grandstream GDS3710, Beward DS06M): поддерживают SIP и ONVIF. Телефон регистрируется на Asterisk/FreeSWITCH как SIP-клиент. Входящий вызов с домофона → SIP INVITE → сервер → push на телефон → CallKit (iOS) / ConnectionService (Android).
Кастомный домофон на одноплатнике (Raspberry Pi, ESP32-S3, NXP i.MX): мы выбираем стек сами. WebRTC через Pion (Go) или aiortc (Python) на устройстве — сигнализация через WebSocket на наш сервер — мобильный клиент.
Облачный домофон (Ring, Dahua, Hikvision EZVIZ): проприетарный P2P SDK. Интегрируемся через их мобильный SDK — быстро, но vendor lock-in.
Звонок с домофона: доставка за <1 секунды
Задержка уведомления критична. Нажал кнопку в 23:00 — телефон должен зазвонить немедленно, пока гость ещё стоит у двери.
iOS CallKit — правильный путь. Не обычный push, а APNs VoIP push (PKPushRegistry, PKPushType.voIP). Система будит приложение немедленно (даже при Force Quit в некоторых сценариях) и вызывает pkPushRegistry(_:didReceiveIncomingPushWith:). Там создаём CXCallUpdate и передаём в CXProvider — пользователь видит нативный интерфейс входящего звонка с видео.
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: "Дверь подъезда")
update.hasVideo = true
update.localizedCallerName = "Домофон"
provider.reportNewIncomingCall(with: callUUID, update: update) { error in ... }
APNs VoIP-сертификат отдельный от push-сертификата. voip в UIBackgroundModes в Info.plist.
Android ConnectionService + FCM с высоким приоритетом (priority: high в payload). TelecomManager.addNewIncomingCall() показывает системный звонок. Проблема: на Xiaomi, Huawei, OPPO агрессивные battery optimizations убивают FCM-соединение. Решение — JobScheduler keepalive + инструкция пользователю добавить приложение в исключения оптимизации. Либо использовать HMS Push для Huawei устройств.
Flutter: flutter_callkit_incoming + firebase_messaging. Нативные биндинги к CallKit и ConnectionService.
WebRTC-видеосвязь
После ответа на звонок — WebRTC peer connection. Сигнализация: обмен SDP через наш WebSocket-сервер (или Asterisk с WebSocket транспортом для SIP/WebRTC). ICE кандидаты собираем через STUN, для NAT traversal — TURN (Coturn).
Видео с камеры домофона: RTCVideoTrack рендерим в RTCMTLVideoView (Metal, iOS) или SurfaceViewRenderer (Android). Аудио — RTCAudioTrack. AEC (echo cancellation) встроен в WebRTC — важно для сценария «слышу своё эхо через колонку домофона».
Задержка видео: 150-400 мс при хорошем Wi-Fi. На 4G — 400-800 мс. Для принятия решения «открыть / не открыть» — приемлемо.
Управление замком
HTTP или MQTT запрос к устройству или серверу. Релейный выход: POST /api/unlock или MQTT publish("home/door/unlock", "1"). Подтверждение открытия через сенсор двери (опционально): home/door/sensor → OPEN событие отображается в приложении.
Таймаут авторизации: кнопку «Открыть» показываем только пока звонок активен. После завершения — скрываем. Лог событий: каждый звонок, открытие, отказ — пишем в БД с timestamp и userId.
Видеозапись событий
Запись видео при каждом звонке (ringback recording): медиасервер (Janus record plugin, Ant Media) пишет поток в WebM/MP4. Хранение в S3/MinIO. Ретенция: последние 30 событий или 7 дней — чистим по lifecycle rule.
Мобильный клиент показывает историю событий: timeline с превью первого кадра, длительностью и кнопкой воспроизведения. Видео играет через AVPlayer / ExoPlayer из S3 presigned URL.
Мультиквартирный дом
Несколько подъездов, несколько квартир. Маршрутизация: домофон подъезда 3 → звонит только жильцам квартир в подъезде 3, или конкретной квартире (нажали номер + вызов). В Asterisk: dialplan с Dial(SIP/apartment_${EXTEN}). Каждая квартира — отдельный SIP-аккаунт. В приложении пользователь привязан к аккаунту своей квартиры.
Гостевой доступ: владелец квартиры выдаёт временный QR-код уборщице. QR открывает дверь через HTTP API без звонка — с ограниченным сроком действия и логированием.
Этапы разработки
| Этап | Содержание | Срок |
|---|---|---|
| Аудит оборудования и архитектура | Протоколы устройства, выбор стека | 3-5 дней |
| Серверная часть | Asterisk/WebRTC-сервер, API | 1-2 недели |
| Мобильный клиент iOS + Android | CallKit, видео, управление замком | 2-3 недели |
| Запись событий и история | S3, плеер, лог | 1 неделя |
| Тестирование на железе | QA на реальном домофоне | 1 неделя |
Итого от 1 до 3 месяцев в зависимости от совместимости оборудования и требований к мультиквартирности.







