ODNFC-LAN RFID для разработчиков (MPY)
Краткое руководство по программированию
RFID считывателя-контроллера
Ключевые правила разработки
Работа с Embedded устройством вносит свои особенности в разработку
  • 1
    Время исполнения и web-интерфейс
    У устройства всего один не очень мощный процессор. Если вы загрузите его на 100%, то ему не хватит времени, чтобы быстро выдать вашему браузеру web-интерфейс (и браузер разорвёт соединение до загрузки страницы). Поэтому, всегда оставляйте достаточное время для исполнения других потоков когда. Для этого у вас в основном цикле должна быть строка типа
    await uasyncio.sleep_ms(100)
  • 2
    Ограниченные ресурсы
    По-сравнению с ПК, у устройства очень мало памяти и вычислительной мощности. Это необходимо помнить при разработке: старайтесь не использовать большие структуры в коде и не проводить долгих вычислений.
  • 3
    Garbage collector
    Т.к. в качестве инструмента программирования используется MicroPython, то в системе работает и gc. Его работа может оказаться визуально заметной (т.е. вызвать небольшой "фриз").
    Поэтому, во-первых, старайтесь не нагружать gc - не создавайте много временных объектов в коде.
    Во-вторых, вы можете вызывать gc самостоятельно в тех местах, где пользователь этого не заметит.
  • 4
    Порядок разработки
    Разрабатывать сложные алгоритмы под Embedded устройство бывает не всегда удобно. Поэтому используем следующую схему:
    1. Предварительно код, не зависящий от железа, разрабаывается и проверяется на "обычном" Python для пк.
    2. Прогоняется на сборке MicroPython-сборке под ПК.
    3. Аппаратно зависимые элементы проверяются в консоли устройства (чёрное окно внизу на странице окна редактора устройства). Для того, чтобы использовать это окно, нужно нажать ctrl-c и MicroPython выйдет в shell. Чтобы устройство не перегрузилось по watchdog'у, его надо предварительно выключить в настройках (или коде).
  • 5
    Применение нового кода
    Чтобы новый код устройства вступил в силу, нужно нажать на кнопку "дискета" в верхнем правом углу редактора кода устройства и убедиться, что вышло уведомление "успешно".
    После этого нужно перезагрузить устройство.
    Браузер не всегда "подцепляет" перезагрузившееся устройство, так что, возможно придется обновить страницу.
Как из кода получить доступ к настройкам
web-интерфейса
Для удобства работы с устройством самые используемые настройки выведены в Web-интерфейс.
Как и какие настройки считыватель будет использовать зависит от пользовательского кода.
Из кода настройки доступны как settings - объект класса Settings из модуля config
from config import settings
Доступ осуществляется в виде settings.get('параметр'), где параметры:

Системные:
'sys-version' - версия сборки, строка. только для чтения
'sys-i-ntp' - использовать ntp. число: 1- да, 0-нет.
'sys-ntp-pool' - адрес сервера ntp, строка в формате url.
'sys-ntp-off' - смещение часов относительно utc. строка в формате '00:00',
'sys-lang' - язык интерфейса. строка: 'auto' / 'ru' / 'en'.
'sys-i-web-port' - порт web интерфейса, число.
'sys-set-pwd' - пароль доступа к окну настроек, строка.
'sys-i-set-auth' - использовать пароль для доступа к настройкам. число: 1- да, 0-нет.
'sys-web-pwd' - пароль доступа к web-интерфейсу, строка. (пользователь admin).
'sys-i-web-auth' - использовать пароль для доступа к web-интерфейсу. число: 1- да, 0-нет.
'sys-i-wdt' - включить сторожевой таймер. число: 1- да, 0-нет.
'sys-i-editor' - показывать редактор кода. число: 1- да, 0-нет.
'sys-i-dash' - показывать информационную панель. число: 1- да, 0-нет.
'sys-i-info' - время в секундах между отправками сообщений в web. число.
'sys-i-leds' - количество светодиодов в ленте подсветки. число.


Сеть:
'net-i-dhcp': тип получения ip-адреса. число: 1 - DHCP-клиент/ 0 - cтатический адрес.
'net-ip': адрес устройства (при net-i-dhcp'=0), строка в формате ip-адреса.
'net-mask': маска сети (при net-i-dhcp'=0), строка в формате ip-адреса.
'net-gw': шлюз (при net-i-dhcp'=0), строка в формате ip-адреса.
'net-dns': сервер DNS (при net-i-dhcp'=0), строка в формате ip-адреса.

RFID:
'rfid-format' - строка форматирования
'rfid-protocol': протокол передачи данных о метке. строка 'TCP' / 'UDP'..
'rfid-dest': сетевой адрес получателя, строка в формате ip-адреса.
'rfid-i-dport': сетевой порт получателя, число.
'rfid-keytype': тип ключа шифрования метки RFID. строка: 'A'/'B'/'UL'/'PL'
'rfid-key': значение ключа, строка в hex.
Пример обращения к настройкам

from config import settings

dst_ip = settings.get('rfid-dest')
dst_port = settings.get('rfid-i-dport')
format_str = settings.get('rfid-format')
wdt_en = settings.get('sys-i-wdt', False)

Пример написания своей программы
К нам поступил запрос: для ODNFC-LAN-C сделать передачу osc сообщения с данными из конкретного места mifare-карты. Благодаря нашему подходу - выпускать легкомодифицируемые под пользователя устройства, данная задача решается достаточно просто, что мы хотим наглядно продемонстрировать.

ODNFC-LAN-C (в отличие от ODNFC-LAN) не имеет встроенной поддержки osc, поэтому нам нужно закинуть данную библиотеку в устройство. Сделать это несложно: нужно нажать значок "загрузить" (стрелочка вверх) и выбрать соответствующий файл.
Далее нужно подготовить карту: для этого мы воспользовались своим считывателем ODRFID-N и программой ODRFIDKit.
На скриншоте ниже видно, что вы записали число "01" в hex формате.
Далее подготовим настройки устройства.
Конкретно в коде мы будем использовать настройки "RFID формат", "Получатель", "Порт".

"RFID формат" будет определять, какую именно область мы будем читать на карте. Описание формата можно прочитать в статье.
Теперь можно приступать непосредственно к написанию кода. Он получился достаточно компактным.
Материалы по языку можно прочитать в статье.
А по дополнительным утилитами по этому адресу.

Отдельно нужно обратить внимание на 3-секундный фильтр для защиты от слишком частых срабатываний.

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

import uasyncio as asyncio
from time import time
from rfid_utils import RFID, BUZZ, GLED, CardFilter
from uosc import Client
from machine import WDT
from config import settings

async def run():
    rfid = RFID()
    BUZZ.beeps()
    dst_ip = settings.get('rfid-dest')
    dst_port = settings.get('rfid-i-dport')
    format_str = settings.get('rfid-format')
    wdt_en = settings.get('sys-i-wdt', False)
    wdt = None
    sender = Client(dst_ip, dst_port)
    c_filter = CardFilter(3)

    if wdt_en:
        wdt = WDT(timeout=10000)

    while 1:
        if wdt_en:
            wdt.feed()
        c_filter.clean(time())
        uid = rfid.read(fmt=format_str)
        if uid and uid not in c_filter:
            c_filter.append(uid)
            sender.send('/lan', uid)
        else:
            await asyncio.sleep_ms(250)