Задача: Я живу во многоквартирном доме (обычная панельная десятиэтажка 97-й серии, 157 квартир). У нас отгороженная территория и ворота с приводом. Раньше ворота открывал человек в будке. На фоне отказа от услуг охранников из-за повышения стоимости их услуг, необходимо было сделать так, чтобы своим машинам ворота открывались автоматически, чужим — нет.
Не хотелось заводить для этого отдельный сервер, городить сложный бэкенд и продолжать держать охрану на кнопке. Всё должно было работать «само» и жить в локальной инфраструктуре.
Как сейчас это выглядит:
- на воротах установлена камера Dahua DHI‑ITC413‑PW4D‑IZ3 со встроенным ANPR (функция распознания номеров);
- управляющий выход камеры подключён к блоку управления приводом ворот CAME — так реализовано физическое открытие ворот;
- камера по протоколу ITSAPI отправляет события распознавания номеров в Node‑RED;
- дальше поток в Node-RED приводит сырые события камеры к нормальному виду и шлёт понятные уведомления в Telegram.
В этой статье (она больше для тех, кто технически подкован) я расскажу как именно всё это устроено и работает. Более простую статью нишу чуть позднее и оставлю на неё ссылку.
Архитектура: кто за что отвечает
Разделим роли:
Камера Dahua:
- распознаёт номер прямо на борту;
- держит у себя белый список номеров;
- через управляющий выход даёт импульс на контроллер ворот, если номер есть в белом списке;
- по ITSAPI отправляет в Node‑RED JSON с подробными данными: номер, цвет, марка, направление, время, флаги списков и т.п.
В камере можно настроить нечёткое соответствие чтобы при некорректном считывании некоторых букв или цифр номера камера не блокировала въезд.
Блок управления приводом ворот CAME:
- получает сигнал от камеры и физически открывает/закрывает ворота (окно около 30 секунд).
iHost + Node‑RED:
- принимает HTTP‑запросы ITSAPI от камеры;
- разбирает сложный JSON в аккуратный объект metadata;
- фильтрует и дедуплицирует события;
- формирует человеческое сообщение и отправляет его в Telegram.
Ключевая идея:
решение “открывать или нет” живёт в камере, а “понять, что случилось, и как это использовать дальше” — в Node‑RED.
ITSAPI: как камера говорит с Node‑RED
У камер Dahua помимо stream‑подхода (eventManager) есть ещё один удобный механизм — ITSAPI webhook:
- на камере настраивается URL сервера, куда она будет слать события;
- при каждом срабатывании ANPR она делает HTTP POST с JSON‑телом.
В моём случае:
- iHost с Node‑RED живёт в локальной сети по адресу 10.0.0.20;
- в Node‑RED есть сценарий «Камера ITSAPI webhook» с HTTP‑инпутом /NotificationInfo/TollgateInfo;
- в веб‑интерфейсе камеры в разделе ITSAPI я указываю:
Сервер платформы: http://10.0.0.20:1880/NotificationInfo/TollgateInfo
После этого при каждом распознавании номера камера:
- сама решает, открывать ворота (по своему белому списку);
- параллельно отправляет в Node‑RED JSON со всеми данными по событию.
Поток в Node‑RED: общий вид
Мой сценарий с названием «Камера ITSAPI webhook» состоит из нескольких логических блоков:
1. Приём HTTP‑запроса от камеры
http in /NotificationInfo/TollgateInfo → debug → Разбор тела запроса.
2. Нормализация JSON в удобный объект metadata
функция «Разбор тела запроса» приводит разные варианты формата камеры к единой структуре.
3. Дедупликация по номеру
функция «Дедупликация по номеру (1 мин)» фильтрует повторы.
4. Форматирование текста/фото для Telegram
функция «Формат сообщения для Telegram» → delay → telegram sender.
Это вся логика, которая нужна, чтобы из сырых ITSAPI‑данных получить понятное уведомление в чате.
Шаг 1. HTTP In: точка входа для ITSAPI
Первая нода в потоке — http in:
- метод: POST;
- URL: /NotificationInfo/TollgateInfo (это значение ты указываешь на камере);
- дальше сразу debug (для отладки) и функция Разбор тела запроса.
На этом этапе в msg.payload или msg.req.body лежит тот самый JSON от камеры.
Форматы у Dahua бывают чуть разные (где‑то Picture/Plate/Vehicle в корне, где‑то вложены иначе), поэтому нужна аккуратная нормализация.
Шаг 2. «Разбор тела запроса»: привести хаос к metadata
Функция Разбор тела запроса делает несколько вещей:
- принимает тело из msg.payload или msg.req.body;
- если это строка или Buffer, аккуратно парсит в объект;
- собирает воедино данные из разных веток JSON:
- Picture / NormalPic (картинка в base64, если есть);
- Plate (информация о номере);
- SnapInfo (время/координаты);
- Vehicle (данные по машине).
На выходе функция формирует:
msg.payload = {
metadata: { ... }, // все разобранные поля, приведённые к единым именам
imageBuffer: Buffer, // если пришла картинка в base64, она декодируется сюда
raw: body // исходный JSON от камеры
};
Ключевой момент:
вся логика использования живёт дальше по потоку, а “Разбор тела” только аккуратно раскладывает и не теряет ни одного поля. Это зафиксировано в правилах: состав/структуру парсинга без явного запроса не меняем.
Шаг 3. Дедупликация: защита от спама одним и тем же номером
Камера при одном и том же проезде может прислать несколько близких по времени событий с одним номером. Если всё слать в Telegram как есть, чат превратится в свалку.
Функция Дедупликация по номеру (1 мин):
- берёт номер из msg.payload.metadata.PlateNumber / PlateNo;
- хранит в flow‑контексте:
- itsapi_last_plate;
- itsapi_last_plate_time; - если тот же номер уже был в последние 60 секунд — сообщение отбрасывается (return null).
В результате в Telegram для одного проезда ты получаешь одно уведомление, даже если камера прислала несколько событий.
Шаг 4. Формат сообщения для Telegram
Функция Формат сообщения для Telegram из metadata вытаскивает только то, что полезно человеку:
- номер;
- цвет авто;
- марку/серию;
- тип ТС;
- направление;
- регион;
- время (UTC/RealUTC или AccurateTime/SnapTime);
- флаг, найден ли номер в базе (если камера отдала AllowUser).
Дальше формируется текст в духе:
Камера распознала номер А000А111
Данные от камеры:
Номер авто: А000А111
Цвет авто: White
Марка/серия: Chery
Тип ТС: SUV
Направление: Obverse
Регион: RUS
Время: 24.02.2026, 12:34:56
✅ Номер найден в базе
Если в msg.payload.imageBuffer лежит картинка (камера прислала её по ITSAPI):
- нода собирает payload вида { chatId, type: 'photo', content: imageBuffer, caption: text };
- иначе — обычное текстовое сообщение { chatId, type: 'message', content: text }.
Перед отправкой в Telegram стоит delay «Не чаще 1 сообщ/2 с», чтобы не упираться в лимиты API.
Что в итоге получилось
Каждый раз, когда своя машина заезжает во двор:
Камера Dahua:
- распознаёт номер;
- сверяет его со своим белым списком;
- даёт сигнал на контроллер ворот;
- отправляет ITSAPI‑событие на Node‑RED.
Node‑RED на iHost:
- принимает POST /NotificationInfo/TollgateInfo;
- аккуратно разбирает JSON в metadata;
- убирает повторы;
- собирает короткий, понятный текст;
- отправляет сообщение (и, при наличии, фото) в Telegram в нужный чат.
С точки зрения жильца всё выглядит так:
«подъезжаю → ворота открываются сами»
Администратор системы (в нашем случае это Председатель ТСЖ) видит кто и когда приезжал благодаря уведомлениям в Telegram.
Почему это реально собрать за выходные
Если посмотреть по шагам, основной объём работы — это не «писать код распознавания номеров», а:
- правильно распределить роли:
- камера отвечает за распознавание и белый список;
- привод ворот — за механику;
- Node‑RED — за приём вебхука и удобный слой для людей; - настроить ITSAPI на камере и убедиться, что события доходят до Node‑RED;
- собрать поток, который:
- принимает HTTP POST;
- приводит JSON к единой структуре;
- фильтрует дубли;
- красиво оформляет сообщение.
Все эти шаги укладываются в один‑два дня включённой работы, особенно если не городить лишних сущностей и держать всю автоматику на камере и iHost, без зависания на ПК.
Дальше на эту базу уже можно навешивать что угодно: базу жильцов, аналитику, интеграцию с n8n и внешними системами. Но самое ценное, что рабочий контур “камера → ворота → Telegram” уже живёт в продакшене и не зависит от внешних сервисов и облаков.
👉 Если статья зашла — поставьте лайк. Есть мысли или опыт по теме — напишите комментарий. Подпишитесь на канал, чтобы не пропускать новые материалы. А если хотите поддержать автора — воспользуйтесь кнопкой «Поддержать» 😇
Другие статьи автора по этой теме: