Сегодня речь пойдет о системе верификации пользователей, которая в будущем сможет стать (и станет, я надеюсь) полноценной системой двухфакторной верификации пользователей. В качестве первого фактора будем использовать RFID карту, в качестве второго - распознавание лица пользователя с помощью OpenCV. На данный момент второй фактор работает в ручной режиме и фото отправляется в Телеграм оператору. Но автор топика активно работает над адаптацией каскада Хаара для распознавания лиц. И, как знать, может скоро и выйдет еще одна статья. Не будем загадывать. Все равно в одну статью это все не уместить. Поэтому начнем. Кому интересно - добро пожаловать под кат.
1. Схемотехническое проектирование
1.1 Лирическое отступление
Я считаю, что наш ГОСТ вполне имеет право на жизнь. И, если следовать порядку проектирования, описанному в нем, то процесс разработки и поддержки любого реального проекта становится проще и понятнее любому члену команды. По крайней мере это точно касается маленьких проектов вроде этого, особенно если не заниматься занудством до невозможности и не пытаться соблюсти его кругом и всюду.
1.2 Непосредственно проектирование
Проектирование устройства было начато с разработки электрической структурной схемы, представленной ниже. Из схемы видно, что устройство состоит из трёх основных блоков: Raspberry Pi, модуля считывания RFID карт RFID-RC522 и WEB-камеры.
Монитор - не обязательная вещь. На него просто будут выводиться логи вроде "Карта №... Доступ разрешен".
Выбор считывателя ничем не обоснован. Взял тот, что был под рукой.

Процесс работы устройства выглядит следующим образом: пользователь прикладывает RFID карту к считывателю, Raspberry Pi проверяет разрешен ли доступ для владельца карты, если доступ разрешен, то делается фотография web-камерой. Информация о владельце карты (для примера, у нас будет ID карты) и фотография автоматически отправляются оператору устройства на заранее сконфигурированный номер в Telegram. Если пользователю данной карты доступ запрещен, то фотографирования не происходит, выдается сообщение «Доступ запрещен!» и сообщение не отправляется.
В качестве WEB-камеры может использоваться любая WEB-камера совместимая со стандартным классом USB устройств USB Image. Т.е. практически любая USB WEB-камера, за исключением совсем экзотики.
При отправке Telegram-боту сообщения вида /photo в ответ оператор получает последнее фото с камеры.
При отправке Telegram-боту сообщения вида /text в ответ, для примера, будем выводить информацию о том какой пользователь воспользовался системой последним (прошел через турникет, например).
2. Разработка ПО
2.1 Структура ПО
В начале я хотел написать свой модуль ядра для работы с SPI, но про это можно написать целую отдельную статью. Да и зачем?? Если есть готовый. Может когда-нибудь в академических целях...
Поэтому использовать мы будем стандартный драйвер spi_bcm2708.
По умолчанию он занесен в blacklist ввиду не использования его большинством пользователей. Поэтому комментируем соответствующую строчку в соответствующем файле. Это делается так:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
в этом файле комментируем строку
blacklist spi-bcm2708
Модуль активировали.
Хотел написать библиотеку для работы с этим модулем. Но и тут не получилось выпендриться. Уже есть готовая.
Для взаимодействия будем использовать уже написанную библиотеку. Она требует для работы другую - SPI-Py
Следующий набор команд установит все, что нам потребуется (git, разумеется, уже должен быть установлен):
sudo apt-get install python-dev
git clone https://github.com/lthiery/SPI-Py.git
cd SPI-Py
sudo python setup.py install
git clone https://github.com/rasplay/MFRC522-python.git
Писать будем на языке python. Работать будем в директории MFRC522-python.
cd MFRC522-python
Структура нашего проекта представлена на рисунке ниже.

Взаимодействие со считывателем RFID карт осуществляется через стандартный модуль ядра spi_bcm2708. Основные функции работы с SPI из userspace реализованы в библиотеке SPI-Py. По средствам этой библиотеки модуль чтения запускает опрос считывателя. Конфигурация модуля чтения RFID меток (регистры, функции для работы) реализованы в модуле конфигурации. В нем же хранится конфигурация Telegram бота (token). После считывания RFID метки модуль чтения обращается к модулю фото. В ответ получает фото пользователя, которое направляется в модуль отправки сообщений для отправки оператору в Telegram вместе с информацией о пользователе.
Раз уж мы решили использовать OpenCV для распознавания лиц, то осуществлять захват изображения с камеры тоже будем с её помощью. OpenCV ставится на Raspberry Pi ровно также как и на любую другую Linux-машину. Описывать процесс её установки в рамках топика не вижу смысла. Мануал по установке есть на официальном сайте, просто повторяем шаги и всё.
Далее будет описана реализация основного функционала. А полный код проекта будет доступен по ссылке в конце статьи.
Опрос RFID считывателя происходит в бесконечном цикле вида:
while continue_reading:
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL) # Опрашиваем RFID считыватель
if status == MIFAREReader.MI_OK: # Если обнаружена карта
print "Card detected"
(status,backData) = MIFAREReader.MFRC522_Anticoll()
if status == MIFAREReader.MI_OK:
print "Card read UID: "+str(backData[0])+","+str(backData[1])+","+str(backData[2])+","+str(backData[3])+","+str(backData[4])
if (( backData == cardA ) or ( backData == cardB ) or ( backData == cardC )): # Сравниваем для примера с тремя захардкоженными идентификаторами трёх билетиков московского метро
print "welcome"
### Получаем снимок с камеры через OpenCv ###
capture = cv.CaptureFromCAM(0)
frame = cv.QueryFrame(capture)
cv.SaveImage("../../../Camera/telegram/image/ny.jpg", frame)
del(capture)
### ####
### Запись файла с информацией о пользователе ####
f1 = open("../../../Camera/telegram/text1.txt", 'wb')
f1.write("The")
if ( backData == cardB ):
f1.write("User with cardB is comming")
elif ( backData == cardA ):
f1.write("User whith cardA is comming")
### ####
# запуск отправки в Телеграм
os.system('python3 telegram.py')
else:
print "wrong Card"
Я постарался максимально закомментировать код дабы исключить пояснения в основном тексте статьи. С остальными фрагментами кода буду поступать аналогично.
Теперь надо зарегистрировать Telegram-бота. Простейший мануал опять же есть на официальном сайте и пересказывать его шаги в этой статье я не буду. Ещё есть документация и примеры исходных кодов для интересующихся.
Требуемый нам функционал реализуем так:
### Отправка текcтовой информации ###
def mes ():
f = open('../../../Camera/telegram/text1.txt')
bot.send_message(<тут ваш идентификатор>, f.read())
return 0
### Отправка фото ###
def photo ():
photo = open('../../../Camera/telegram/image/ny.jpg', 'rb')
bot.send_photo(<тут ваш идентификатор>, photo)
return 0
mes()
photo()
Вместо <тут ваш идентификатор> вписываем идентификатор абонента, которому отсылаем сообщение.
Осталось реализовать ответы бота на сообщения. Для этого надо создать обработчики соответствующих команд /photo и /text:
### Обработка команды /text ###
@bot.message_handler(commands=['text'])
def mes (message):
f = open('../../../Camera/telegram/text1.txt') # файл с информацией, который сохраняли ранее
bot.send_message(message.chat.id, f.read()) # отправка
return 0
### Обработка команды /photo ###
@bot.message_handler(commands=['photo'])
def photo (message):
photo = open('../../../Camera/telegram/image/ny.jpg', 'rb') # фото, которое сохраняли ранее
print(message.chat.id)
bot.send_photo(message.chat.id, photo) # отправка
Реализацию основных частей рассмотрели.
3. Макет
На основании п.1 и п.2 был разработан макет устройства, представленный на фото ниже. В качестве RFID карт использовались билеты для проезда в Московском метрополитене.


К Raspberry Pi подключен RFID считыватель по интерфейсу SPI согласно таблице представленной ниже. WEB-камера подключается к USB-порту, расположенному на плате. Взаимодействие с сетью (API сервера Telegram) осуществляется через Ethernet порт.
Таблица подключения RFID считывателя RC522 к Raspberry Pi
RPi пин RC522 пин
1 Vcc
6 GND
19 MOSI
21 MISO
22 RST
23 SCK
24 NSS
На этом статья подходит в концу. Полный код проекта доступен в моем репозитории на github . Не забываем вписывать ваш токен для Telegram-бота в файле config.py, а также вписывать свой идентификатор абонента, которому надо посылать фото и информацию.
P.S.
Статья написана для участия в конкурсе т.к. своей Rasberry Pi не имею. Для реализации этого проекта взял у друга на пару месяцев первую Raspberry.
Да, разработка - процесс неспешный. Тем более, что проектом занимаюсь исключительно в свободное время.