Контейнер RouterOS, который проксирует последовательный порт через HTTP с использованием TCP serial (RFC-2217)

Здесь выкладываем скрипты
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Ответить
Sertik
Сообщения: 1601
Зарегистрирован: 15 сен 2017, 09:03

Приветствую, друзья.

Как-то у меня возникла задача подключить к Микротик serial MP3 Player с чипом YX5300, разработанный компании Catalex, а потом спертый и многократно клонированный нашими друзьями китайцами.

Вот такое устройство: Изображение
Я писал об этом в том числе здесь https://habr.com/ru/articles/776908/, где решил задачу через Laurent-5G

Проблема в том, что Роутер ОС может предоставить порт для подключаемого устройства либо serial либо USB, но в ней нет какого-то "клиента rfc2217" (в этом не разбираюсь и не знаю честно что это за хрень) и управлять, передавать/получать данные этому/от этого устройства из скриптов пользователя РОС не может.

Но, потом я нашёл на оф. форуме https://forum.mikrotik.com/viewtopic.ph ... 9#p1042969 способ обойти эту проблему для ЛЮБЫХ устройств ИМЕЮЩИХ RS-232 или USB. Она в частности может быть решена через проксирование данных через контейнер, но только разумеется для Роутер ОС 7 и только на RB с процессорами ARM.

Автор работы написал также отличный скрипт, который автоматически устанавливает нужный контейнер в Роутер ОС для решения этой задачи.
Исходник скрипта и оригинал описания данной работы здесь: https://github.com/tikoci/serial2http

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

Просьба к тем у кого есть необходимость, желание и возможность попробовать это решение и отписаться. Честно сам пока не пробовал.

P/S Просьба также ко всем, в том числе нашим продаванам, кто прёт готовые инструкции и размещает на своих сайтах уважать немного чужой труд и хотя бы ссылаться на авторов.
Последний раз редактировалось Sertik 19 дек 2023, 12:23, всего редактировалось 9 раз.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1601
Зарегистрирован: 15 сен 2017, 09:03

Serial2http - контейнер Router OS 7 для проброса serial-порта через HTTP и TCP
[контейнер для подключения последовательного порта к RouterOS CLI]

(Инструкция по установке и использованию)


https://github.com/tikoci/serial2http, адаптированный перевод Sertik 18.12.2023

Введение

RouterOS поддерживает последовательные порты, доступные по команде /port print, включая устройства, подключаемые по USB или порты самого роутера. В то же время RouterOS позволяет подключаться к последовательному порту из локальной сети или удалённо через IP адрес инструментом /ports/remote-access, «пробрасывая» последовательный порт в Ethernet:

Код: Выделить всё

/port remote-access add port=serial0 protocol=rfc2217 tcp-port=22171
Но в Router OS нельзя использовать клиент RFC-2217 в скриптах или командной строке (CLI). Например, в Роутер ОС нельзя отправить данные через serial-порт на подключенное (или удаленное) последовательное устройство: система порт предоставляет, а инструмент обмена данными - нет.

Использование последовательных портов в RouterOS

описывается в официальном руководстве: https://help.mikrotik.com/docs/display/ROS/Ports
полезная информация есть также здесь: http://forum.mikrotik.com/viewtopic.php ... 17#p138054

Одним из обходных путей является возможность создания командой Роутер ОС интерфейса ppp-клиента с портом, установленным для последовательных устройств:

Код: Выделить всё

/interface ppp-client add name=ppp-out1 dial-on-demand=no port=serial0 null-modem=yes disabled=no
после чего команды можно будет выдавать через:

Код: Выделить всё

/ppp-out1 at-chat input="ATX"
Или возможна сразу передача данных через добавленный интерфейс и его удаление:

Код: Выделить всё

/interface ppp-client add name="scripttemp" dial-on-demand=no port=serial0 modem-init="I am the string" null-modem=yes disabled=no
/interface ppp-client remove [/interface ppp-client find name="scripttemp"]
Но это работает только с последовательными устройствами, имеющими набор AT-команд. И этот трюк не сработает, если в ответ не будет получено «ОК». Было бы лучше, если бы чат был более гибким и имел бы возможность настройки проброса, подобно /port/remote-access, для вставки данных в общие порты, но в существующих версиях Роутер ОС это пока не возможно.

Использование HTTP через контейнер для «чата»

В роутер ОС версии 7 появилась поддержка технологии Docker container. Поскольку /container не имеет прямого доступа к последовательным портам, то для использования контейнера с этой целью требуется обязательное использование /ports/remote-access, включая любое последовательное устройство, подключенное к Микротик напрямую, поскольку между контейнером и RouterOS разрешен только IP, а не устройства /dev (tty, usb и т. д.).

RouterOS имеет инструмент /tool/fetch для веб-запросов, но это не работает напрямую с serial портами (а также с портами через удаленный IP-доступ). Но для этого можно использовать контейнер serial2http для Роутер ОС 7, содержащий небольшой скрипт на Python, который прослушивает входящий запрос HTTP типа POST, отправляет данные через последовательный порт, прокинутый на IP (через /port/remote-access), а затем возвращает результат от последовательного устройства в ответе HTTP в виде обычного текста.
Когда контейнер «serial2http» установлен и запущен, можно отправить «мои произвольные данные» на последовательное устройство с IP-адресом, а выходные данные, возвращённые устройством, будут доступны в CLI Router OS или скрипте:

Код: Выделить всё

# send text to the serial via the serial2http container
:global answer [/tool/fetch url=http://172.22.17.1 method=post http-data="my-data-to-go-to-serial" as-value output=user]
Использование библиотеки Python PySerial

Библиотека Python pySerial используется для подключения к любому последовательному порту, указанному в настройках контейнера (envs) для SERIALURL. PySerial использует схему URL-адресов для описания хоста, поэтому настройка envs может измениться на конкретное последовательное устройство, используемое для связи.

key="SERIALURL" value="rfc2217://172.22.17.254:22171?ign_set_control&logging=debug&timeout=3"

Важным для контейнера Serial2http является URL-адрес PySerial, указанный выше. См. https://pyserial.readthedocs.io/en/late ... dlers.html для получения подробной информации о том, что можно установить в окружениях SERIALURL выше.

Например, если вы установили тип raw для элемента в /ports/remote-access, используйте: socket:// в SERIALURL.
Если вы хотите расширенно использовать этот контейнер, следует ознакомиться с остальной частью PySerial. Этот контейнер делает очень простую вещь: ищет «\n» (символ новой строки) во входящем последовательном IP-адресе, чтобы знать, когда возвращать ответ через HTTP. Но его можно легко адаптировать для выполнения более сложных действий на Python, с разветвлением кода здесь, или изменить сценарий через монтирование в RouterOs).

Установка контейнера Serial2http в RouterOS


1. Настройка переменных в /container/envs

Контейнер использует переменные среды для управления. Приведенные ниже настройки следует импортировать в Mikrotik, чтобы можно было их редактировать. Внутри контейнера используются те же значения, что и по умолчанию. Перед добавлением контейнера Serial2http необходимо внести следующие настройки в /container/envs:

Код: Выделить всё

/container/envs {
    # HTTP port the container listens for commands on...
    add name="serial2http" key="PORT" value=80 
    # PySerial "URL" to serial device via RFC2217 (use socket:// for "raw")
    add name="serial2http" key="SERIALURL" value="rfc2217://172.22.17.254:22171?ign_set_control&logging=debug&timeout=3"
    # most options can be set in the pyserial's url, BAUDRATE must be explicit 
    add name="serial2http" key="BAUDRATE" value=115200
    # timeout to use if not in pyserial's url 
    add name="serial2http" key="TIMEOUT" value=5
}
Чтобы удалить их используйте команду:

Код: Выделить всё

/container/envs [find name="serial2http"] remove


2. Установка mount для изменения исходного кода

Если вы захотите позже отредактировать код Python, вы можете добавить файл mount. Код устанавливается в /app внутри контейнера, и этот каталог будет доступен RouterOS. В RouterOS /container/mounts dst= это каталог внутри контейнера, а src= это используемый путь RouterOS. Ниже предполагается, что disk1/ является местом хранения RouterOS контейнера, при необходимости эту настройку можно изменить:

Код: Выделить всё

/container/mounts {
    add name=serial2http src=disk1/serial2http-app dst=/app
}
Для удаления используйте:

Код: Выделить всё

/container/mount [find name="serial2http"] remove
Важно: путь Роутер ОС не может начинаться с косой черты ("/"), поэтому src= не может иметь «/» в начале.


3. Создание интерфейса и адресации для контейнера

Добавим для контейнера интерфейс типа veth с подсетью и шлюзом и создадим для него адресацию в /ip/address:

Код: Выделить всё

/interface/veth {
    add name=veth-serial2http address=172.22.17.1/24 gateway=172.22.17.254
}
/ip/address {
    add interface=veth-serial2http address=172.22.17.254/24
}
Чтобы удалить эти настройки используйте:

Код: Выделить всё

/interface/veth/remove [find name=veth-serial2http]
/ip/address/remove [find interface=veth-serial2http]

4. «Проброс» физического последовательного порта на TCP-порт

Это простая задача: нужно настроить port=, сопоставим конкретный физический последовательный порт (или последовательного USB-устройство) и IP-адрес, по которому он будет доступен. В приведенных выше примерах предполагается, что порт будет доступен по адресу 172.22.17.254, используя TCP-порт 22171:

Код: Выделить всё

/port remote-access add port=serial0 protocol=rfc2217 tcp-port=22171
Если вы используете другие настройки, следует настроить их в SERIALURL в /container/envs, чтобы они соответствовали конкретным устройствам.

Необходимо настроить также /firewall роутера в соответствии с объемом поддержки, который необходим. Брандмауэр по умолчанию разрешает доступ только с одного и того же устройства (поскольку адрес интерфейса veth отсутствует в списках адресов (address list) по умолчанию). Но tcp-port= прослушивает все интерфейсы, поэтому конфигурация /firewall должна быть защищена.


5. Создание контейнера RouterOS

Есть два способа сделать это:

1. Скачать образ, созданный на GitHub, из этого репозитория, используя

Код: Выделить всё

/container add remote-image= ...
2. или используйте docker build на рабочем столе

Вариант 1. Использовать ресурс https://ghcr.io для скачивания образа контейнера.
Чтобы загрузить контейнер по его тегу, вам сначала необходимо использовать реестр контейнеров GitHub.

Код: Выделить всё

/container/config/setregistry-url=https://ghcr.io

После успешного импорта в RouterOS образ не изменится, если реестр будет изменен после импорта в /container.

Вы сможете вернуться к более распространенному Docker Hub после успешного импорта, используя:

Код: Выделить всё

/container/config/setregistry-url=https://registry-1.docker.io

Код: Выделить всё

/container/add remote-image=ghcr.io/tikoci interface=veth-serial2http env=serial2http mounts=serial2http-app logging=yes root-dir=disk1/serial2http-container
Примечание. Этот образ находится только в реестре ghcr.io. Это не DockerHub. Хотя перенести в DockerHub в дополнение к реестру контейнеров GitHub тривиально... одного реестра кажется достаточно для необычного варианта использования.

Вариант 2. Выполните сборку локально с помощью сборки Docker и скопируйте файл .tar.
В некотором смысле это проще, поскольку полученный .tar — это просто необходимая файловая система. Если описанный выше метод упаковки не работает, попробуйте этот метод.

Сначала вам понадобится установить Docker Desktop. Используя раскрывающийся список «Код» в GitHub, вы можете загрузить или клонировать Git в папку на своем настольном компьютере. Затем запустите стандартную сборку докера из этой папки в терминале:

docker build --platform linux/arm/v7 -t serial2http
docker save serial2http > ../serial2http.tar

Файл .tar будет находиться в родительском каталоге. Вы можете скопировать и установить его на свой роутер. Если мы предположим, что образ находится в disk1/serial2http.tar, следующая команда будет использовать образ файла вместо тега, как в варианте 1 выше:

Код: Выделить всё

/container/add file=disk1/serial2http.tar interface=veth-serial2http env=serial2http mounts=serial2http-app logging=yes root-dir=disk1/serial2http-container
Системе необходимо время для «извлечения» образа, поэтому подождите минуту и попробуйте запустить его. После извлечения и в «остановленном» состоянии вы можете запустить его следующим образом:


6. Запуск контейнера

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

Код: Выделить всё

/container [find tag~"serial2http"] start
Чтобы в среде UNIX отслеживать состояние контейнера в реальном времени через CLI, используйте

Код: Выделить всё

/container print Interval=1s ...:

Код: Выделить всё

/container print interval=1s proplist=tag,status where tag~"serial2http"

7. Тестирование


Эта часть сложнее. Вам понадобится подключенное последовательное устройство, использующее API запроса-ответа, заканчивающее ответ символом \n. NMEA, обычно используемый с GPS и морскими приложениями, является одним из таких протоколов.
Пример. Этот контейнер изначально был создан для использования с модемом Swarm M138 для работы с https://swarm.space, чтобы позволить RouterOS отправлять/получать сообщения через спутник в облачную службу "hive" Swarm. В отличие от модемов LTE (например, AT-команд), модем M138 использует команды в стиле NMEA, поэтому чат не работает, поэтому этот контейнер. Но, вероятно, полезно и в другом контексте.

Общие шаги по использованию:

У вас есть последовательное устройство, которое должно работать со скриптом RouterOS. Вы можете использовать /port/print, чтобы отобразить найденные последовательные порты.
В /ports/remote-access вам, возможно, придется изменить port=, чтобы он соответствовал последовательному порту, к которому подключается устройство.
Вам нужно будет знать команды, которые вы хотите отправлять/получать. Для модема Swarm M138, серийник устройства можно получить, выполнив следующие действия:

Код: Выделить всё

/tool/fetch http-method=post url=http://172.22.17.1 output=user http-data="\$CS*10\n" 

outputs:
status: finished
downloaded: 0KiBC-z pause]
data: $CS DI=0x003e79,DN=M138*7c

Возможно, некоторые последовательные устройства определяются как устройства LTE (и/или вы хотите использовать их с модемом LTE). Если это так и у вас нет «настоящего» интерфейса LTE, установите для определения модема LTE использование «последовательного» режима вместо «авто» или «mbim». Для этого используйте:

Код: Выделить всё

/interface/lte/settings/set mode=serial 
Управление контейнером serial2http

Конфигурацию контейнера можно настроить с помощью envs в /container/envs и остановить/запустить контейнер, чтобы использовать все новые настройки.

Поскольку контейнер по сути является оболочкой PySerial, дополнительную информацию см. на странице https://pyserial.readthedocs.io/en/latest/.


Автоустановка контейнера скриптом SERIAL2HTTP.rsc

Скрипт для Роутер ОС SERIAL2HTTP.rsc автоматически установит или заменит контейнер Serial2http. Он доступен для скачивания по ссылке:

https://raw.githubusercontent.com/tikoc ... 2HTTP.rsc

Прежде чем использовать этот скрипт, убедитесь, что вы точно понимаете, что он делает. Имейте в виду, что вероятно будет необходима некоторая адаптация скрипта к Вашим условиям (конфигурации роутера и т.д…). Предложенный скрипт может содержать и ошибки и необходимо достаточно протестировать предлагаемый скрипт, чтобы выявить их все.

Скрипт представлен в виде функции, которую можно использовать с параметрами. Вы можете поместить код скрипта в /system/script или загрузить скрипт в RouterOS используя команду /import SERIAL2HTTP.rsc Запуск скрипта создаёт в окружении переменных глобальную одноимённую функцию SERIAL2HTTP, которую затем можно вызвать из CLI или Ваших скриптов.

Специально поддерживает операцию «сборки». Далее используются те же IP/порты, что и при ручном процессе, но он автоматизируется. Если скрипт импортирован, следующая команда установит необходимый контейнер и выполнит всю настройку:

Код: Выделить всё

$SERIAL2HTTP build path=disk1 branch=main
Функция $SERIAL2HTTP сначала удаляет любой существующий контейнер Serial2http, прежде чем создавать новый образ, как обычно работают обновления в Docker. Если это нежелательно, можно выполнить процедуру обновления или удаления контейнера вручную.

Если вы просмотрите код, возможны и другие варианты, но Serial2http не требует никаких операций после установки. Поскольку при сборке будет использоваться последняя версия (если указана ветка branch=main), ее также можно использовать для обновления контейнера позже.

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

Код: Выделить всё

{
/tool/fetch url= "https:// raw.githubusercontent.com/ tikoci / serial2http / main/ SERIAL2HTTP.rsc"
:import SERIAL2HTTP.rsc;
$SERIAL2HTTP build path=nfs1 branch=main
}
Обе стороны прокси-сервера используют незащищенный IP-трафик, поэтому следует подумать о том, как лучше всего использовать firewall RouterOS для защиты обоих сторон: порт, используемый в /tool/remote-access, используемый для предоставления последовательного порта TCP и подсеть контейнера, которая прослушивает HTTP на порту 80 для отправки команд. Рекомендуется настроить /firewall Микротик так, чтобы ограничить доступ к любым IP-адресам и портам, используемым этим контейнером.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Ответить