Системы контроля управления доступом в IoT — умеем, знаем, практикуем

И снова привет, мир!

В прошлой статье про IoT-елочку в голосовании многие отметили, что интересна тема управления устройствами в зависимости от количества человек в помещении. Это довольно масштабная задача, и мы предлагаем разделить ее решение на несколько этапов. Сегодня поговорим о системе контроля управления доступом (СКУД), которая, будучи подключенной к платформе интернета вещей Rightech IoT Cloud (далее по тексту – платформа), является базовым элементом в системе подсчета количества человек в офисе. Мы уже поверхностно освещали этот кейс в одной из статей, но сегодня рассмотрим этот проект более подробно и погрузимся в особенности исполнения.

СКУД?

Система контроля и управления доступом, СКУД (англ. Physical Access Control System, PACS) — совокупность программно-аппаратных средств контроля и управления, главная цель которой – ограничение и регистрация входа-выхода объектов (людей, транспорта) на заданной территории через «точки прохода»: двери, ворота, КПП.

С чего все началось

Задача обеспечить контроль за входом-выходом в офисе возникла еще в те времена, когда у нас был выход на крышу с отличным видом на Москву, и поэтому часто приходили люди, не являющиеся нашими сотрудниками. Тогда мы решили принять какие-то меры по безопасности и установить СКУД.

Архитектура

Система открытия дверей по карте

В качестве модуля, отвечающего за обработку информации по считыванию бесконтактных карт, выбрали GATE-8000. 

Основные достоинства контроллера:

  • формирование и хранение необходимой информации о факте открытия двери по карте и времени прохода человека в офис;

  • возможность автономной работы и защиты от зависания; 

  • хранение 16 тысяч ключей и 8 тысяч событий;

  • простое подключение и управление;

  • российский производитель, хорошая документация с описанием работы контроллера.

Внешний вид платы с контроллером
Внешний вид платы с контроллером

Основной принцип работы: контроллер обрабатывает информацию, поступающую со считывателя, и с помощью встроенного реле коммутирует исполнительное устройство – электромагнитный замок двери. 

Система взаимодействия с платформой

После того, как контроллер установили в систему по общей схеме подключения, а карты записали в память, мы уже обезопасили себя от прохода в офис посторонних. А дальше возник вопрос, как подключить этот контроллер к платформе Rightech ioT Cloud. Ведь очень здорово иметь а) графический интерфейс, в котором можно полистать историю всех проходов, б) возможность отправки команд на открытие двери удаленно, не отходя от рабочего места, например, для гостей или доставщика еды.

У контроллера нет выхода в Интернет и видимой возможности подключения к платформе, к тому же все события нужно принудительно считывать из его циклического буфера. Однако у него есть свой протокол обмена данными с компьютером управления, благодаря которому можно отправлять на контроллер команды, такие как считать из контроллера, записать в контроллер,  открыть/закрыть замок и другие. Значит, нужно сделать некоторую программно-аппаратную прослойку между контроллером и платформой – агента, который будет отправлять команды на чтение событий и управление контроллером.

Обращаем внимание, что в данной архитектуре функция открытия двери при прикладывании карты не перестанет выполняться при отсутствии Интернета. За открытие двери и сбор информации отвечает контроллер СКУД, поэтому в случае потери Интернета, единственное, что нам грозит, – это то, что агент, который доставляет данные на платформу, не будет функционировать, так как не сможет получать команды на чтение буфера. Однако при восстановлении соединения все события считаются в полном объеме и не потеряются, так как они будут сохранены в буфере контроллера СКУД.

▍Аппаратная часть

Для начала нужно было выбрать устройство, которое будет всегда в активном состоянии с включенной программой-агентом в непосредственной близости от платы СКУД. Из многообразия микрокомпьютеров первое что попало под руку выбор пал на Raspberry Pi.

Дальше возник вопрос, как подсоединить GATE-8000 к Raspberry – то есть как подключить последовательный интерфейс RS485 от GATE к USB от микрокомпьютера. Начались поиски переходника USB-RS485. Первый вариант, который мы испробовали, – Espada за 200 рублей. Надежда на то, что маленький хлипкий китайский переходник заработает, была небольшой. Он и не заработал. Вместо нужных данных приходило что-то похожее по виду и размеру, но… всё же не то. В чем было дело: в отсутствии гальванической развязки, невозможности поддерживать скорость 19200 bps или же просто в некачественной элементной базе, – загадка. Но после обращения к производителю GATE-8000, мы получили рекомендацию на более дорогой (в 10 раз) и громоздкий (но аккуратный и корпусированный) переходник Z-397, который заработал тут же как надо. 

▍Программная часть

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

  1. Что нужно – взаимодействие с GATE-8000 для отправки команд и получения данных. 

    Как решим – изучим протокол GATE, напишем сериализатор и десериализатор данных, подключим библиотеку для работы с последовательным портом.

  2. Что нужно – взаимодействие с платформой для получения команд и отправки данных.

    Как решим – выберем для общения протокол MQTT, в коде воспользуемся готовой библиотекой Paho MQTT.

Итак, мы приступили к изучению протокола GATE-8000, который является закрытым, поэтому ниже рассказано только о некоторых его особенностях. Он достаточно низкоуровневый, и необходимо обращаться напрямую к регистрам памяти устройства. В документе по этому протоколу описаны кадры запросов от компьютера контроллеру и кадры ответов контроллера компьютеру. Меняя поля в кадре запроса, можно отправлять на устройство различные команды и получать информацию из регистров. 

Одна из особенностей протокола в том, что инициатором обмена всегда является компьютер. Поэтому есть два подхода работы с устройством: 

1) задавать всю логику работы в агенте;

2) использовать внешние запросы (от платформы). 

Мы выбрали второй вариант и вынесли логику с конечного устройства на платформу (подробнее про сервис сценариев автоматизации >>>). Так ее легко адаптировать и подстроить, при этом код программы остается компактным и позволяет просто формировать команды для устройства, а платформа в свою очередь координирует отправку команд и их периодичность. 

Всегда ли нужно выносить логику работы с устройства?

Такое решение, конечно, не подойдет, если от устройства требуется предпринять действия мгновенно (например, если идет речь о жизни человека), но даже в таком случае часть логики можно вынести на платформу. Как вариант, для выбора заранее запрограммированных шаблонов поведения.

После того как мы внимательно изучили этот протокол, формат кадров и список команд, возникла первая сложность. Команды для чтения буфера, в котором содержатся события о том, кто и во сколько пришел, не оказалось. А ведь получить эту информацию – первоочередная задача. Понадобилось изучить карту памяти контроллера, чтобы определить адреса, по которым нужно считывать данные.

Карта памяти контроллера? WTF?

Под картой памяти контроллера (термин из протокола) имеется в виду таблица с описанием заполнения регистров памяти, а не микрофлешка =). 

Следующая особенность работы с контроллером в том, что за один цикл чтения можно получить только 12 событий, по 8 байт на каждое. А на каждый проход человека в офис генерируется уже два события:

1) найден ключ в банке ключей (банк ключей – еще один блок в распределенной памяти контроллера);

2) состоялся проход (если он, конечно, состоялся). 

Ниже представлен фрагмент кода на С++, реализующий метод одного цикла чтения буфера.

bool SerialPortInlet::readBufferCycle(unsigned short& bottom, unsigned short const& top, unsigned char& u_lowerBound,
    	unsigned char& l_lowerBound, std::vector<unsigned char>& readBuffer, std::string& result)
{
	// Подсчет байтов, которые необходимо считать
	unsigned short byteCountTmp = top - bottom;
	BOOST_LOG_SEV(log_, logging::info) << "Need read " << byteCountTmp << " byte";
	unsigned char byteCount;
	// За один цикл нельзя прочитать более 12 событий (96 байт)
	byteCount = byteCountTmp > 0x60 ? 0x60 : (unsigned char)byteCountTmp;
	BOOST_LOG_SEV(log_, logging::info) << "Read " << +byteCount << " byte";
	// Описываем тело команды
	std::vector<unsigned char> body = {0x02, 0xA0, byteCount, u_lowerBound, l_lowerBound};
	std::vector<unsigned char> command;
	// Получаем полный текст команды
	generateComplexCommand(command, Command::BYTE_CODE_READ, body);
	// Если не удалось по каким-то причинам отправить команду (например, конечное устройство не подключено), возвращается false
	if (!sendCommand(command, result))
	{
    	return false;
	}
	// Иначе отправляем ответ с устройства на парсинг по событиям
	SerialPortType::Answer answerEvents;
	if(!Parsers::parserAnswer(log_, result, answerEvents, Command::BYTE_CODE_READ))
	{
    	BOOST_LOG_SEV(log_, logging::error) << "Failed parse buffer reading";
    	return false;
	}
	readBuffer.insert(readBuffer.end(), answerEvents.body.begin(), answerEvents.body.end());
	// Сдвигаем нижнюю границу буфера для чтения следующих событий
	bottom = bottom + byteCount;
	u_lowerBound = (unsigned char)(bottom >> 8) ;
	l_lowerBound = (unsigned char)bottom;
	return true;
}

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

Байтстаффинг?

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

Пример байтстаффинга из документации
Пример байтстаффинга из документации

Полная структурная схема разработанной системы выглядит так.

Работоспособность всех устройств было очень удобно проверять с помощью графического последовательного терминала СuteCom. После успешного тестирования программа была поставлена на автозапуск, а Raspberry отправилась жить на потолке рядом с платой СКУДа.

Один делает, другой смотрит, третий фотографирует, огнетушитель придерживает дверь - настоящая командная работа =)
Один делает, другой смотрит, третий фотографирует, огнетушитель придерживает дверь – настоящая командная работа =)

Работа на платформе Rightech IoT Cloud

Модель

Основные данные с контроллера – это события, на платформу они приходит в формате JSON и включают в себя поля

  • eventTime – время наступления события;

  • eventCode – код события;

  • keyNumber – номер карты сотрудника (поле может быть пустым, если событие вызвано не картой).

Модель устройства выглядит следующим образом.

Посмотреть оригинал >>>

Возможные события:

  • нажата кнопка звонка;

  • неопознанный ключ на входе;

  • неопознанный ключ на выходе;

  • ключ найден в банке ключей при входе;

  • ключ найден в банке ключей при выходе;

  • открывание оператором по сети;

  • дверь заблокирована оператором;

  • дверь оставлена открытой после входа;

  • дверь оставлена открытой после выхода;

  • проход состоялся на вход;

  • проход состоялся на выход;

  • перезагрузка контроллера.

Объект

Интерфейс объекта полностью формируется согласно разработанной модели.

Интерфейс истории журнала объекта
Интерфейс истории журнала объекта

Посмотреть оригинал >>>

Интерфейс команд
Интерфейс команд

Ура, теперь, собравшись на кухне офиса в ожидании пиццы на праздник, можно никуда не идти, а просто открыть мобильное приложение и нажать кнопку открытия двери для курьера!

Автомат

Можно заметить, что есть команда не только на чтение буфера событий, но и на запись новых границ. В памяти контроллера хранятся границы буфера – начало и конец. Когда на устройство приходит команда чтения, из памяти берутся эти границы и в их пределах происходит чтение из буфера событий. Граница конца буфера сдвигается автоматически на контроллере при получении новых событий. А вот начальную границу буфера нужно перезаписать (указав конечную границу после прошедшего чтения), чтобы не прочитать одни и те же данные повторно. Но это необходимо сделать только после того, как данные о событиях успешно отправлены на платформу.

Зафиксировать успешное получение данных и затем отправить команду на перезапись начальной границы удобно в автомате.

Посмотреть оригинал >>>

Здесь виден цикл <чтение>-<запись новой границы буфера>-<ожидание таймера> (сейчас события считываются каждые 30 секунд). 

  1. В состоянии “Read events” читаем новые события.

  2. В состоянии “Clear buffer” записываем новую границу.

  3. В состоянии “Await timer …” ожидаем начала нового цикла.

Также есть дополнительные обратные связи для состояний, в которых отправляются команды. Если в течение работы таймера не произошло успешное выполнение команды, таймер срабатывает и отправляется соответствующее сообщение оператору, после чего происходит повторная отправка команды.

Дальнейшее использование собранных данных

Данный проект нашел свое продолжение в интеграции с нашей внутренней CRM системой, в которой на вкладке информации о сотрудниках всегда видны актуальные сведения о том, кто находится или отсутствует в офисе.

Также отображается время входа/выхода из офиса, считается суммарное количество часов в месяц.

Посмотреть оригинал >>>

В мессенджер Slack каждый день пишется о том, что офис открыт, когда приходит первый человек, взявший ключи на ресепшене.

Забор данных из платформы производится по REST API. API платформы предоставляет возможность работы, взаимодействия и использования сущностей платформы и их данных в таких внешних системах, как веб-порталы, мобильные и веб-приложения или, как в нашем случае, – CRM системах.

Посмотреть проект, в котором есть пример настройки взаимодействия и получения данных с платформы >>>


Теперь мы знаем немного больше о том, как может работать СКУД в IoT-проектах. В следующих материалах рассмотрим, как рассчитать на базе полученной информации количество человек в офисе и какие практические применения есть у этой идеи.

Let’s block ads! (Why?)

Read More

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *