OD LAN RFID
для разработчиков
Краткое руководство по программированию
RFID считывателя-контроллера
Основные узлы
Технические характеристики:
1. Чтение и запись меток:
Mifare Classic 1K: полная поддержка
Mifare Classic 4K: полная поддержка
Mifare Plus S/X (SL0): полная поддержка
Mifare Classic Plus S/X 2K (SL1): полная поддержка
Mifare Classic Mini: полная поддержка
Mifare Plus X 2K/4K (SL2): ограниченная поддержка - только UID,
повышение уровня безопасности до SL3
Mifare Plus S/X 4K (SL1): полная поддержка
Mifare Plus S/X 4K (SL1): ограниченная поддерхка - только UID
Mifare Plus S/X (SL3): полная поддержка
Mifare Ultralight: полная поддержка
Mifare Ultralight Nano: полная поддержка
Mifare Ultralight C: ограниченная поддержка - только UID
Mifare Ultralight EV1 80/164: полная поддержка
Mifare DESFire: ограниченная поддержка - только UID
NTAG 213: полная поддержка
NTAG 215: полная поддержка
NTAG 216: полная поддержка

2. Дальность считывания меток: до 6 см.
3. Габаритные размеры: 95х62х20 мм.
4. Проводные интерфейсы: Ethernet, USB(сервисный).
5. Индикация: светодиоды (красный и зелёный), звуковой излучатель.
6. Один входной канал (3В, подтянут к "1").
7. Один выходной канал (1А max), напряжение соответствует напряжению питания.
8. Ёмкость встроенного накопителя: 8 МБ.
9. Четыре крепёжных отверстия М3.
10. Питание Passive PoE 12-20V.
При монтаже корпуса следует иметь в виду, что для Ethernet разъёма и кабеля требуется
дополнительное пространство в стене за считывателем.
Как начать работать
1. Подключите устройство к роутеру с dhcp-сервером Ethernet кабелем с питанием Passive PoE 12-20V.
2. Найдите в роутере новый ip-адрес, который роутер выдал устройству.
3. Запустите web-браузер и откройте странницу с указанным ip-адресом. Вы должны увидеть главное окно считывателя, как на картинке ниже.
Внимание: Если после нескольких попыток получить адрес считыватель не получит ответа от DHCP сервера, он назначит себе статический адрес 192.168.1.1. Это позволяет получить доступ к устройству при нерабочем или отсутствующем роутере.
Как программировать устройство
Считыватель можно запрограммировать несколькими способами.
  • 1
    WEB-интерфейс
    Самый быстрый и удобный способ изменить программу. В Web-интерфейсе устройства пользователю доступен редактор для написания пользовательского кода.
  • 2
    Программа UPYMon
    Наша программа для записи, удаления и редактирования файлов на встроенной файловой системе. Работает через USB или UART. В отличие от первого способа позволяет не ограничиваться одним файлом для редактирования.
  • 3
    Консоль MicroPython
    Самый тяжелый для начала, но самый подходящий для отладки сложного кода: Python REPL.
WEB-редактор

В Web-интерфейс встроен редактор для изменения кода программы. В устройстве используется адаптированный MicroPython, подробную инструкцию по которому можно скачать по ссылке.
    В качестве первого примера сделаем упрощённый пропускной пункт.
    В данной программе считыватель каждые 500мс проводит опрос RFID-интерфейса, при считывании любой карты подаёт сигнал на выходные контакты, выводит UID в WEB-интерфейс и издаёт звуковой сигнал.
      
      from rfid_utils import RFID, Buzzer, OUT
      from uasyncio import sleep_ms
      from webserver import eprint, erfid
      from binascii import hexlify
      
      async def run():
          await eprint("User code started")
          rfid = RFID()
          buz = Buzzer()
          while 1:
              await sleep_ms(500)
              uid = rfid.read()
              if uid:
                  OUT.on()
                  await erfid(uid)
                  await buz.beep()
                  await sleep_ms(3000)
                  OUT.off()
      
      Для удобства разработки мы подготовили несколько частоиспользуемых инструментов для работы с RFID считывателями и поместили их в файл rfid_utils.py:

      Объект GLED - зелёный светодиод (класс MicroPython - Pin)
      Объект RLED - красный светодиод (класс MicroPython - Pin)
      Объект OUT - выходной канал (класс MicroPython - Pin)
      Объект IN - входной канал (класс MicroPython - Pin)
      Класс Buzzer - звукогенератор
      Класс СardFilter - инструмент для защиты от повторного прикладывания
      Класс RFID - инструмент для упрощения работы с картами

      Подробнее о rfid_utils.py
      В качестве второго примера сделаем упрощённый сетевой клиент:
      
      from rfid_utils import RFID, Buzzer
      from uasyncio import sleep_ms
      from webserver import eprint
      from config import settings
      from uasyncio import AsyncUDP
      
      async def run():
          await eprint("User code started")
          rfid = RFID()
          buz = Buzzer()
          while 1:
              await sleep_ms(500)
              uid = rfid.read(settings.get('format'))
              if uid:
                  await buz.beep()
                  await AsyncUDP.udp_send(uid, (settings.get('dest'), settings.get('dport')) )
                  await sleep_ms(3000)
      
      Как из кода получить доступ к настройкам
      web-интерфейса
      Для удобства работы с устройством самые используемые настройки выведены в Web-интерфейс. Как и какие настройки считыватель будет использовать зависит от пользовательского кода.
      Из кода настройки доступны, как класс settings из модуля config.
      Доступ осуществляется в виде settings.get('параметр'), где параметры:

      (настройки RFID)
      format - строка форматирования
      protocol - протокол передачи данных о метке ('TCP'/'UDP'/'HTTP(S)')
      dest - сетевой адрес получателя
      dport - сетевой порт получателя
      keytype - тип ключа шифрования метки RFID ('A'/'B'/'UL'/'PL')
      key - значение ключа

      (настройки сети)
      iptype - тип получения ip-адреса. Может быть двух видов: 'Static' / 'DHCP'
      ip - адрес устройства, при iptype=Static
      netmask - маска сети, при iptype=Static
      gateway - шлюз, при iptype=Static
      dns - сервер DNS, , при iptype=Static
      ntp - адрес сервера точного времени

      (общее)
      wdt (bool) - включить сторожевой таймер
      lang (en/ru) - язык интерфейса (используется web-интерфейсом)
      editor (bool) - показывать редактор в интерфейсе(используется web-интерфейсом)
      dash (bool) - показывать панель в интерфейсе (используется web-интерфейсом)
      web_auth (bool) - включить web-аутентификацию (используется web-интерфейсом)
      web_pwd (str) - пароль web-аутентификации (используется web-интерфейсом)
      set_auth (bool) - включить аутентификацию при входе в настройки (используется web-интерфейсом)
      set_pwd - пароль при входе в настройки(используется web-интерфейсом)
      В качестве примера выведем в лог информацию о строке форматирования, сетевому адресу и порту получателя.

      Что в окне:
      
      from uasyncio import sleep_ms
      from webserver import eprint
      from config import settings
      
      async def run():
          await eprint("User code started")
          s = settings
          while 1:
              await sleep_ms(1000)
              await eprint('format:{}, dest:{}, port:{}'.format(s.get('format'), s.get('dest'), s.get('dport')))
      
      Пример работы с кнопкой и замком
      Пример кода для работы с замком и обработкой кнопки
      
      from time import time
      from uasyncio import sleep_ms, sleep
      from machine import WDT
      from rfid_utils import RFID, Buzzer, GLED, RLED, CardFilter, OUT, IN
      from webserver import eprint, erfid
      from config import settings, udb
      
      
      async def granted(buz): 
          GLED.on()    
          await buz.beep()
          GLED.off()
          OUT.off()
          await sleep(5)
          OUT.on()
      
      
      async def run():
          await eprint("User code started")
          rfid = RFID()
          buz = Buzzer()
          GLED.off()
          RLED.off()
          OUT.on()
          c_filter = CardFilter(5)
          wdt_enabled = settings.get('wdt')
          str_format = settings.get('format')
          if wdt_enabled:
              wdt = WDT(timeout=10000)
          while 1:
              if wdt_enabled:
                  wdt.feed()
              await sleep_ms(200)
              c_filter.clean(time())
              if IN.value() == 0:
                  await granted(buz)
              uid = rfid.read(str_format)
              if uid and uid not in c_filter:
                  c_filter.append(uid)
                  value = udb.get(uid)
                  if value is not None:
                      await eprint(uid + ' granted')
                      await granted(buz) 
                  else:
                      RLED.on()
                      await eprint(uid + ' denied')
                      await buz.beep(500)
                      RLED.off()
      
      Подключение двух считывателей к одному замку
      Один считыватель управляет замком. Второй только передает сигнал о необходимости открыть замок.
      Пример кода для работы с двумя считывателями
      
      from time import time
      from uasyncio import sleep_ms, sleep
      from machine import WDT
      from rfid_utils import RFID, Buzzer, GLED, RLED, CardFilter, OUT, IN
      from webserver import eprint, erfid
      from config import settings, udb
      
      async def door(): 
          OUT.off()
          await sleep(5)
          OUT.on()
      
      async def run():
          await eprint("User code started")
          rfid = RFID()
          buz = Buzzer()
          prev_in = None
          GLED.off()
          RLED.off()
          OUT.on()
          c_filter = CardFilter(5)
          wdt_enabled = settings.get('wdt')
          str_format = settings.get('format')
          if wdt_enabled:
              wdt = WDT(timeout=10000)
          while 1:
              if wdt_enabled:
                  wdt.feed()
              await sleep_ms(100)
              c_filter.clean(time())
              if (prev_in == 0) and (IN.value() == 1):
                  await door()
              prev_in = IN.value()
              uid = rfid.read(str_format)
              if uid and uid not in c_filter:
                  c_filter.append(uid)
                  await eprint(uid + ' granted')
                  GLED.on()    
                  await buz.beep()
                  GLED.off()
                  await door()
      
      Организация памяти
      Начиная с версии 1.4 память считывателя делится на 2 части:
      /flash - постоянная память (2МБ), здесь хранятся все системные файлы. Раздел в режиме "ro" (только чтение).
      /var - память для хранения пользовательских данных (6МБ): БД, изображения и т.п. Раздел в режиме "rw" (чтение-запись).
      Пользовательский код из Web-редактора по-умолчанию хранится в /var. Для переноса его на раздел /flash нажмите кнопку "На flash".
      Это сделано, чтобы была возможность реализации алгоритма самовосстановления устройства в случае повреждения данных в /var.
      Дополнительные ресуры
      1. Общая инструкция в PDF,
      2. Техподдержка,
      3. Руководство по языку MicroPython,
      4. Инструкции "Как написать свою программу".