Инженерия

Как мы связали облачное бронирование отеля с турникетами Hikvision

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

Ниже — как мы связали облачную систему бронирования с физическим оборудованием в локальной сети отеля, какие подводные камни встретились и почему решение тиражируется на другие объекты без боли.

Почему это не «просто HTTP-запрос»

Две части системы живут в разных мирах:

  • PMS-система бронирования — в облаке (QloApps на базе PrestaShop), доступна из интернета.
  • Контроллеры доступа — турникеты Hikvision в локальной сети отеля, за роутером и NAT, без белого IP.

Достучаться из облака напрямую до железки в частной сети нельзя: входящие порты закрыты, белого адреса нет. Пробрасывать порты на каждом объекте — это и дыра в безопасности, и постоянная головная боль на поддержке (у отелей меняются провайдеры, роутеры, IP). Нужно было решение, которое работает за любым NAT и ничего не требует от сети отеля.

Архитектура: три звена и одна ключевая идея

Мы разбили интеграцию на три части — модуль в облаке, сервис-шлюз и локальный агент:

[PMS в облаке]                        [ПК ресепшена, локальная сеть]
  Модуль бронирования                   Локальный агент (Windows-служба)
       │                                          │
       ▼                                          ▼
  Сервис-шлюз  ─── WSS (агент звонит сам) ──►  Контроллер доступа
   (наш бэкенд)                                (турникет / картридер)

Ключевая идея — инверсия соединения. Не облако стучится в отель, а локальный агент сам открывает исходящий канал наружу через WebSocket Secure (порт 443). Для роутера это обычный исходящий HTTPS-трафик — ничего открывать или пробрасывать не надо, работает за любым NAT «из коробки». Когда поступает бронирование, шлюз пишет задание в очередь и проталкивает его уже открытым каналом к нужному агенту.

Жизненный путь одного бронирования

  1. Гость оплачивает бронь в PMS → модуль кладёт задание issue в очередь шлюза (номер, период, какие зоны доступны).
  2. Шлюз находит агента нужного отеля среди открытых WSS-соединений и отправляет задание.
  3. Агент переводит его в вызовы к контроллеру: заводит гостя, генерирует/привязывает карту, ставит расписание действия по датам заезда и выезда.
  4. Контроллер подтверждает — агент возвращает статус, шлюз обновляет запись в базе, в журнале появляется строка «карта выдана».
  5. На check-out (или когда наступает дата выезда) — зеркальный сценарий revoke: карта гасится, пользователь убирается из контроллера.

Всё оборудование отеля администратор видит и настраивает в одном разделе — список турникетов с их адресами, зонами доступа и состоянием:

Список турникетов в админке
Раздел управления турникетами: каждый контроллер — с адресом в сети, зонами доступа и статусом.

Для каждого турникета задаются сетевые реквизиты, роль (вход/выход), группы прав и то, к каким зонам отеля карта открывает доступ:

Форма настройки турникета
Настройка отдельного турникета — адрес, роль, зоны доступа.

Что оказалось непростым

Стабильность канала и очередь с подтверждениями

WSS-соединение надо держать живым часами и переживать обрывы сети. Агент сам переподключается, а задания не теряются: они лежат в очереди в базе со статусами, и шлюз повторяет доставку, пока агент не подтвердит выполнение (ack). Если ПК ресепшена выключили на ночь — утром агент поднялся, забрал всё накопленное и доделал по порядку. Каждая операция идемпотентна, поэтому повтор не создаёт дублей карт.

ISAPI — это не тот REST, к которому все привыкли

Агент общается с контроллером по его родному протоколу — ISAPI поверх HTTP Digest: своя аутентификация, специфические JSON-структуры под каждый endpoint, собственные коды ошибок, а документация протокола — сотни страниц. Мы обернули всю эту «кухню» в чистый внутренний контракт, чтобы остальная система не знала деталей контроллера и оперировала простыми командами issue / revoke / status. Если завтра появится другая модель или вендор — меняется только адаптер в агенте, а не вся система.

Карта живёт ровно столько, сколько бронь

Карта должна появиться именно на период проживания и исчезнуть после выезда — ни днём раньше, ни днём позже. Мы привязали выдачу и погашение к событиям бронирования в PMS и ведём журнал каждой операции: администратор всегда видит, какая карта, кому и на какой период выдана, и может погасить её вручную досрочно.

Обновление без выездов на объект

Агент — это Windows-служба на ПК ресепшена. Чтобы не ездить в каждый отель ради новой версии, мы сделали механизм самообновления: агент подтягивает обновления сам тем же защищённым каналом и перезапускается как служба.

Безопасность

  • Никаких входящих портов в сети отеля — только исходящий WSS на 443.
  • Агент аутентифицируется на шлюзе по токену; каждый отель видит только свои задания.
  • Реквизиты контроллеров хранятся на стороне отеля, а не гуляют по облаку.
  • Полный журнал выдач/погашений — для аудита и разбора спорных ситуаций.

Стек

  • Шлюз: Node.js (WebSocket-сервер + REST для PMS-модуля), очередь и журнал в MySQL, готовность масштабироваться на много отелей через pub/sub.
  • Агент: Node.js, упакованный в Windows-службу; ISAPI Digest к контроллеру доступа; самообновление.
  • PMS: QloApps / PrestaShop — интеграция через модуль на стороне системы бронирования.
  • Тестирование: E2E-сценарии насквозь — бронирование → шлюз → агент → контроллер → запись карты → статус обратно в базу.

Результат

Отель получил полностью автоматический цикл: бронирование онлайн → карта на турникете → автопогашение на выезде, без ручной работы ресепшена и без дыры в сетевой безопасности объекта. Решение тиражировано — подключить новый отель означает лишь поставить агента на ПК ресепшена, остальная инфраструктура уже есть.

Нужна интеграция системы бронирования, CRM или сайта с физическим оборудованием — турникетами, замками, кассами, ПРРО? Напишите нам — разберём вашу задачу.

Поделиться

Готовы обсудить релиз?

Отвечаем в течение 60 минут в рабочее время — с оценкой бюджета, ориентировочным графиком и составом команды под вашу задачу.

Оставить запрос