# ODNFC-RS485 Modbus demo server

Минимальный пример интеграции считывателя ODNFC-RS485 с приложением на
Python. Программа опрашивает устройство по Modbus RTU и выполняет две команды:

- карта 13,56 МГц (HF) — команда `OK`;
- карта EM-Marine 125 кГц — команда `ERROR`.

Команды включают штатную световую и звуковую индикацию устройства. Скрипт
работает как Modbus RTU master; ODNFC-RS485 является Modbus slave.

## Что потребуется

- ODNFC-RS485 с актуальной прошивкой и режимом считывателя `combo`;
- USB-RS485 адаптер;
- Python 3.10 или новее;
- два провода RS485 `A/B` и общий `GND`.

Параметры устройства по умолчанию:

| Параметр | Значение |
|---|---:|
| Modbus address | `1` |
| Baud rate | `115200` |
| Data format | `8N1` |

Подключите `A` адаптера к `A` устройства, `B` к `B` и объедините `GND`.
Если обмена нет, сначала проверьте маркировку `A/B`: некоторые адаптеры
используют обратные обозначения.

## Установка

Linux/macOS:

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
```

`requirements.txt` устанавливает `minimalmodbus` и `pyserial`. Скрипт не
зависит от внутренних тестовых модулей репозитория.

Windows PowerShell:

```powershell
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
```

## Запуск

Linux:

```bash
python odnfc_rs485_modbus_demo_server.py /dev/ttyUSB0
```

Windows:

```powershell
python odnfc_rs485_modbus_demo_server.py COM3
```

Для другого Modbus-адреса или скорости:

```bash
python odnfc_rs485_modbus_demo_server.py /dev/ttyUSB0 \
  --unit 2 --baudrate 57600
```

После запуска снимите обе метки минимум на 750 мс, затем поднесите их по
очереди. Пример вывода:

```text
ODNFC-RS485 ready on /dev/ttyUSB0: unit=1, 115200 8N1
HF -> OK, EM-Marine -> ERROR; rearm=750 ms
HF uid=BA67F93500000000 -> OK
EM-Marine uid=4800CEA91C -> ERROR
```

Для повторного срабатывания метка должна отсутствовать непрерывно 750 мс.
Это подавляет ложные повторы при кратком пропадании UID. Значение можно
изменить:

```bash
python odnfc_rs485_modbus_demo_server.py /dev/ttyUSB0 --rearm-ms 300
```

Остановить программу можно сочетанием `Ctrl+C`.

## Карта используемых регистров

| Holding registers | Назначение |
|---|---|
| `0x0000..0x0003` | HF UID, до 8 байт |
| `0x0004..0x0006` | EM-Marine UID, 5 байт |
| `0x00F0` | Управление индикацией и замком |

Значения `0x00F0`:

| Значение | Действие |
|---:|---|
| `1` | `OK`: открыть замок, зелёная индикация, сигнал OK |
| `2` | `ERROR`: закрыть замок, красная индикация, сигнал ошибки |
| `3` | Закрыть замок |

Демо использует FC03 для чтения регистров и FC06 для записи команды.

## Ошибки связи

Одиночный таймаут не останавливает программу: входной буфер очищается, после
чего опрос продолжается. Пример:

```text
WARN Modbus: timeout after 0/3 response bytes; consecutive=1, total=1
```

После пяти последовательных ошибок программа завершается. Проверьте:

1. правильность порта и Modbus-адреса;
2. скорость `115200` и формат `8N1`;
3. соединения `A/B/GND`;
4. что порт не занят другой программой;
5. права доступа к последовательному порту.

Все параметры командной строки доступны через:

```bash
python odnfc_rs485_modbus_demo_server.py --help
```
