USB GPIO EXTENDER – ещё одна возможность управления нагрузками с роутера Микротик

от автора

Ранее, я писал несколько статей о возможности управления реле непосредственно из Роутер ОС Микротик таких устройств как Laurent и Rodos, а также при использовании возможностей встроенных GPIO RB Mikrotik 33G. Многие считают это не нужным или не дооценивают, а зря, так как это весьма полезный функционал, например, для перезагрузки зависшего сетевого оборудования, включения дополнительного оборудования или аппаратной защиты ПК, NAS и др. непосредственно с роутера.

Недавно, я нашёл в Интернет отечественную компанию «Открытые разработки» и её продукт USB GPIO EXTENDER – маленькое и симпатичное устройство для USB-порта, имеющее «на борту» 10 цифровых линий: 5 линий ввода и 5 линий вывода.

image
Рис 1. USB GPIO EXTENDER

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

Устройство поддерживает следующие команды:

image

И при их выполнении отдает в том же формате ответы от устройства:

image

Как мы видим из списка команд почему-то есть команды чтения состояний IN-линий, но нет аналогичных команд чтения состояний линий OUT… Как узнать в каком состоянии находятся выходные линии не понятно (существенный минус).
Также видим, что ответа на команду перезагрузки нет, а это неправильно. Сначала можно было бы отдать ответ на команду, а потом её исполнить (то есть с точки зрения программиста нужно просто ввести задержку на перезагрузку, чтобы модуль успел отправить ответ на «~B»).

К большому сожалению, обмен командами/ответами осуществляется не в формате AT, что не позволяет использовать функционал устройства из Микротик Роутер ОС в полном объеме. Из Роутер ОС можно передать команду устройству через стандартный ppp-out интерфейс в поле «dial-on-demand»:

/interface ppp-client add name=«USB-GPIO-EXTENDER» dial-on-demand=no port=$UGEport modem-init=«~S1» null-modem=yes disabled=no

Данный трюк я уже использовал ранее, например, при создании «Голосового роутера», но при этом невозможно получить ответ от модуля. Таким образом, во-первых, мы реально не знаем дошла ли команда до устройства и не можем использовать хотя бы имеющиеся команды считывания состояния IN-линий, а очень жаль – можно было бы подключить различные цифровые датчики. Очень надеюсь, что разработчики «Открытых разработок» услышат меня и в будущих версиях придут таки к поддержке AT-команд в USB GPIO EXTENDER раз уж сделали управление простыми текстовыми командами (спасибо хоть что не HEX-последовательностями байт – уже прогресс).

К чести разработчиков надо отметить, что модуль прекрасно определяется Linux и, соответственно, Router OS, которая в /system resourse usb адекватно показывает название модуля, по которому его легко идентифицировать в системе:

image

Рис. 2 Вывод в Терминал /system resourse usb print при подключенном модуле

Из-за указанных выше ограничений я реализовал только поддержку команд управления выходными (OUT) линиями и команду перезагрузки (пример подключения 4-х канального модуля реле 220В к USB GPIO EXTENDER представлен на Рис. 3 ниже).

image
Рис 3. Схема подключения линий ввода/вывода USB GPIO EXTENDER к 4-канальному блоку реле (для примера подключены линии 3 и 4)

Соответствующая скриптовая функция управления линиями вывода для роутера Микротик представлена под спойлером

OpenDevExt

#---------------------------------------------------------------------------- # Functon support OPEN Dev USB GPIO EXTENDER by Sertik 24/09/2024 version 1.0 #---------------------------------------------------------------------------- # check in ROS 6.49.10  # usage:   # $OpenDevExt list # $OpenDevExt logic [true/false] # $OpenDevExt reset # $OpenDevExt SetOut XXYXY [0-1] # $OpenDevExt OutOn X [1-5] # $OpenDevExt OutOff Y [1-5]  # все команды модуля: # ------------------- # ~Sx Установка выхода x в 1. # ~Rx Установка выхода x в 0. # ~Gx Чтение текущего значения входа x. # ~A Чтение значений всех входов в виде «xxxxx». Пример ответа «~A11001». # ~Pxxxxх Запись значений всех выходов в виде «xxxxx». Например «~P11001». # ~B Перезагрузка модуля. # ~I Запросить информация о версии прошивки.  # Поддерживаемые функцией в данной версии команды: # ------------------------------------------------ # ~Sx  # ~Rx # ~Pxxxxх # ~B Перезагрузка модуля. При перезагрузке все out-выходы устанавливаются в 0 !  # logic - чтение/установка логики out-выходов: true - прямая; false - обратная (для реле с прямой и обратной логикой включения/выключения выходов) # если logic не был задан функция устанавливает прямую логику работы, если был задан - запоминается в global $OpenDevReleLogic  # и команды SetOut OutOn и OutOff работают по ней.   :global  OpenDevExt do={  :local version "1.0 by Sertik 24/09/2024"  # установка переменных   :local ModuleType "OpenDevUsbGPIOExtender" :local portTypeUSB "usb" :global OpenDevModuleType $ModuleType :local USBresLinuxName "USB GPIO Extender" :global OpenDevReleLogic :local UsbGpioExtFlag false :local portUSB; :local BaudRate 9600 :local DataBits 8 :local Parity none :local StopBits 1 :local FlowControl none :local PppclientName $ModuleType  # массив имен команд и соответствующих им команд модуля :local ArrayCom {    "logic"="X"    "OutOn"="~S"    "OutOff"="~R"    "SetOut"="~P"    "reset"="~B"  }  # если имя команды не задано вернуть ошибку :if ([:len $1]=0) do={:return "Еrror: no set name command"}  # команда help в Терминал    :if ($1="help") do={       :put ""; :put "---- Function support for $OpenDevModuleType ----"                    :put "      version $version"                    :put  " usage:"  :terminal style "syntax-meta" :put "$0 help"  :put "$0 list" :put "$0 logic [true/false]" :put "$0 reset" :put "$0 SetOut XXYXY [0-1]" :put "$0 OutOn X [1-5]" :put "$0 OutOff Y [1-5]" :terminal style none   :return []}  # команда list в Терминал    :if ($1="list") do={       :put ""; :put "<---- Supported $OpenDevModuleType commands  ---->"           :foreach k,v in $ArrayCom do={:put ("  "."$k")}   :return []}  # команда logic    :if ($1="logic") do={        :if (($2="true") or ($2="false")) do={            :if ($2="true") do={:set OpenDevReleLogic true}            :if ($2="false") do={:set OpenDevReleLogic false}            :return OK      } else={:if ([:len $2]=0) do={          :if (($OpenDevReleLogic=true) or ($OpenDevReleLogic=false)) do={          :return $OpenDevReleLogic} else={:return "logic is not specified or incorrect"}                  }     :return ("Error"." $0"." $1")} }  # проверка определения модуля в USB прерываниях Linux ядра Router OS :local UsbGpioExtName :do { :set UsbGpioExtName [/system resource usb get [/system resource usb find name~$USBresLinuxName] name]     } on-error={} :if ($UsbGpioExtName=$USBresLinuxName) do={:set UsbGpioExtFlag true} :if ($UsbGpioExtFlag=false) do={:return "Error: Not find $OpenDevModuleType module in ROS system. Please, check device in USB port"}  # определение порта :global ODUsbGPIOExtPort :local NewPort :local NowPort $ODUsbGPIOExtPort; # сохранить текущий порт  :do {     :foreach portId in=[/port find name~$portTypeUSB !inactive] do={:set portUSB ([/port get $portId]->"name")}     } on-error={}        :set NewPort $portUSB  # если возможный порт так и не найден или изначально в $ODUsbGPIOExtPort установлен ошибочный порт, то выдать ошибку     :if (([:len $NewPort]=0) or ([:len [/port find name=$NewPort]]=0)) do={:return "Error: Not find port for $OpenDevModuleType module, port inactive or busy. Please, check /port"}  # если функцией был найден (определён) новый порт, а $ODUsbGPIOExtPort, который использовался функцией ранее,  инактивировался, то выбрать в качестве рабочего новый найденный порт    :if (($NowPort!=$NewPort) and ([/port find name=$NowPort and inactive=yes])) do={:set ODUsbGPIOExtPort $NewPort} else={:set ODUsbGPIOExtPort $NowPort}    :if ([:len $ODUsbGPIOExtPort]=0) do={:set ODUsbGPIOExtPort $NewPort}    # одна консоль может быть настроена только на один порт или консоли вообще может не быть в /system console !   :local consoleFlagOff false         if ([:len [/system console find port=$ODUsbGPIOExtPort and !disabled]]>0) do={                 :set consoleFlagOff true                 /system console set [/system console find port=$ODUsbGPIOExtPort] disable=yes         }  # установка параметров порта, выбранного для работы     do {              /port set [/port find name=$ODUsbGPIOExtPort] baud-rate=$BaudRate data-bits=$DataBits parity=$Parity stop-bits=$StopBits flow-control=$FlowControl           } on-error={:return "Error set port $ODUsbGPIOExtPort. Function $0 d`not work"}   # main function`s code # -------------------- # взять код команды из массива по имени команды    :local cmd ($ArrayCom->$1)     :if ([:len $cmd]=0) do={:return "Error: bad command"}                :put "Execute command $OpenDevModuleType: $1 $2"                :log warning "Execute command $OpenDevModuleType: $1 $2"  # проверить и подготовить параметры для команд в соответствии с логикой подключения к выходам  :if ((($1="OutOn") or ($1="OutOff")) and ([:len $2]!=1)) do={:return ("Error function: "."$0 "."$2 - there is incorrect data, set number in range [1-5]")}  :if (($1="SetOut") and ([:len $2]!=5)) do={:return ("Error function: "."$0 "."$2 - there is incorrect data, set the status of 5 outputs")}   :if ([:len $OpenDevReleLogic]=0) do={:set OpenDevReleLogic true} :if (($1="OutOn") && ($OpenDevReleLogic=false)) do={:set cmd ($ArrayCom->"OutOff")} :if (($1="OutOff") && ($OpenDevReleLogic=false)) do={:set cmd ($ArrayCom->"OutOn")}  :if (($1="SetOut") && ($OpenDevReleLogic=false)) do={ :local r ""     :for i from=0 to=([:len $2] -1) do={       :if ([:pick $2 $i (1 + $i)] = "1") do={:set r ($r . "0")} else={:set r ($r . "1")}     } :set $2 $r }  # удалить интерфейс ppp-клиента на всякий случай, если был оставлен ошибочным вызовом       :if ([/interface ppp-client find name=$PppclientName]) do={/interface ppp-client remove [/interface ppp-client find name=$PppclientName]}  # :put ("Send module "."$USBresLinuxName "."command: "."$cmd"."$2")  # передача команды устройству serial-MP3-player через ppp-client      /interface ppp-client add name=$PppclientName dial-on-demand=no port=$ODUsbGPIOExtPort modem-init=("$cmd"."$2") null-modem=yes disabled=no      :delay 1s      /interface ppp-client remove [/interface ppp-client find name=$PppclientName]  # вернуть порт консоли для использованного порта если она отключалась    :if ($consoleFlagOff) do={    :do {/system console set [/system console find port=$ODUsbGPIOExtPort] disable=no} on-error={}      } # конец работы вернуть "OK"    :return OK }

.
К сожалению, производитель поставляет устройство только без корпуса. При этом пины колодки подключения направлены вверх от платы, а не назад, что делает не удобным самостоятельный подбор корпуса к устройству, увеличивая его предполагаемую высоту, а не длину, что было бы компактнее и логичнее. Если же производитель планировал, что его устройство будет устанавливаться в корпус какого-либо изделия заказчика, то следовало бы чуть увеличить размер платы модуля и сделать в ней монтажные отверстия, которых также нет, а также вместо USB-разъема «fеmale» установить разъем «male», который заказчик мог бы вывести на панель своего корпуса.

При сбросе питания или команде перезагрузки модуль сбрасывает все выходные линии в «0». Если к ним подключена нагрузка, то в зависимости от типа релейной логики она будет при этом либо включаться либо выключаться. Опции сохранения состояния линий при холодном/горячем рестарте у модуля нет, хотя flash-память (учитывая наличие программируемой версии с TOIC с которым мне недосуг разбираться), в последней, вероятно, есть.
P/S Версия с TOIC (среда для создания прошивки, разработанная также в «Открытых разработках») кстати позволяет менять число входов/выходов перепрограммируя их, что позволило бы, например, подключать больше реле (до 10) для управления нагрузкой.

Учитывая удобное внешнее подключение к Микротик через USB-порт и принимая во внимание патриотизм (честно признаюсь, что импортных аналогов не то чтобы нет, но я точно никогда не видел), ставим производителю за устройство пока «четверку» и надеемся на внесение указанных необходимых доработок в план будущей версии прошивки модуля.

Все материалы представлены также в cоответствующем разделе автора на GitHub.


ссылка на оригинал статьи https://habr.com/ru/articles/846430/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *