Ранее, я писал несколько статей о возможности управления реле непосредственно из Роутер ОС Микротик таких устройств как 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.

Комментарии (29)


  1. Gudd-Head
    27.09.2024 10:11

    Интересный девайс. Под виндовс нужна ихняя прога для управления?


    1. AiR_WiZArD
      27.09.2024 10:11
      +1

      Устройство общается по виртуальному COM порту, ОС не имеет значения, отличаются только способы взаимодействия с ним, на питоне скрипт +-одинаковый будет


  1. AiR_WiZArD
    27.09.2024 10:11
    +3

    Как отладочная плата - сойдет, но никаких защит нет, ни ESD, ни от перенапряжения, ни даже механической в виде корпуса. На нижней стороне платы ничего нет? Вероятно да, тогда и подтяжка по входам обеспечивается микроконтроллером, а там как правило в районе сотни кОм. За шильдик "отечественное" + 200% к цене, комплектующих тут вряд ли даже на 1$ наберется


    1. vladimir_open-dev
      27.09.2024 10:11
      +1

      Вы же свой микшер по цене комплектующих будете продавать в случае выхода на рынок?


    1. Sertik13 Автор
      27.09.2024 10:11

      Да, цена у них не 300р., но с учётом наших условий, роста цен в стране, развивающейся компании, как им выживать ? Если бы они реализовали мои замечания (в статье), я бы с удовольствием платил им и 1.500р. за устройство.


      1. Sertik13 Автор
        27.09.2024 10:11

        Вот нечто похожее у китайцев, цена чуть выше даже - MCP2221A (легко гуглиться, продаётся на Ali, ссылку сюда почему то не могу вставить)


        1. sami777
          27.09.2024 10:11

          Так MCP2221A - это микрочиповская микросхема со всеми санкционными, для нас, проблемами. Поэтому и цена выше.


  1. karacurt
    27.09.2024 10:11

    Для реализации функций лучше написать в поддержку на open-dev.

    По исполнению девайсов к ним вопросов нет - использовал когда-то watchdog на фермах с Linux ОС, прекрасно себя проявили.


  1. lex899
    27.09.2024 10:11
    +1

    У вас на схеме "рис 3" 5V релейный блок подключён к выходу GPO на 3.3V если я правильно понимаю? Или есть версия платы с 5V логикой?

    Если плата на 3.3 - следует вероятно снять джампер с модуля реле и подать 3.3V и 5V раздельно.

    Отдельный вопрос - в документации не указано сколько можно с пятаков 5V и 3.3V забрать по току, предполагаю что 5V заведена напрямую (500mA) а 3.3 в одном бюджете с выходами (80mA общего), в любом случае релейные модули такого типа имеют очень разные аппетиты.


    1. Sertik13 Автор
      27.09.2024 10:11

      У меня на схеме блок реле с управляющим напряжением +5В подключён к выходами +5В и GNDмодуля (там рядом обозначения). +3.3V не подключён


      1. lex899
        27.09.2024 10:11
        +1

        Давайте ещё раз попробуем.

        1. Релейный модуль подключен к +5V и GND от usb модуля

        2. на всех входах релейного модуля появляется +5V, при замыкании IN1-4 на GND щёлкает нужная релюшка.

        3. IN4 c +5V на борту вы подключаете на GPO4 usb модуля

        4. Напряжение gpio usb модуля по даташиту 3.3V

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


        1. Sertik13 Автор
          27.09.2024 10:11

          Насчет грязного хака не знаю, я не аппаратчик, но в руководстве к модулю нигде не написано, что "напряжение gpio usb модуля 3,3 V" а написано дословно следующее "Диапазон допустимых напряжений на входах" 0 - +3.3V". Может это тоже самое, если авторы под входами понимают любые пины, но у нас есть пины настроенные на вход, а есть настроенные на выход. Обычно во всех китайских контроллерах подобного типа допустимо напряжение от +3,3 до +5В. Если разработчик оставил для чего то на плате +5В значит о чём то думал и о чём лучше спросить бы у него ...


          1. lex899
            27.09.2024 10:11
            +1

            В руководстве написано "уровень выхода «1», В 3,3", мне кажется эта формулировка не допускает двойного толкования.

            Я повторюсь, разработчик ни слова не написал про использование пятаков +5V 3.3V, или gnd на плате для подключения какой-то периферии (а именно - сколько с них можно снять по току). Быть может они вообще отладочные. И то что с одним китайскийм контроллером сегодня сработало завтра может привести к выгоранию платы или порта. При этом релейная плата допускает работу логики от 3.3 при условии отдельной подачи 5V на питание реле.


          1. lex899
            27.09.2024 10:11
            +1

            Возможно подобная схема будет правильнее

            При условии что пятак 5V идет напрямую с USB-VCC.


            1. Sertik13 Автор
              27.09.2024 10:11

              Приму к сведению Ваш совет. Ещё раз повторюсь, я не аппаратчик, моё хобби - программирование, так что Вам виднее.


              1. Sertik13 Автор
                27.09.2024 10:11

                Спасибо !


                1. Sertik13 Автор
                  27.09.2024 10:11

                  Но, когда я использовал устройство с моей схемой включения и замерял напряжение на выходных GPIO-пинах при установки их в "1", то там было +3,3V, а не +5V.


                  1. Sertik13 Автор
                    27.09.2024 10:11

                    Хотя, пардон, это я не о том. Отвлёкся.


                    1. Sertik13 Автор
                      27.09.2024 10:11

                      При Вашей схеме для реле может не хватить управляющего питания 3,3V. При Вашей схеме в качестве управляющего питания нужно также +5V подавать от пятака +5V (то есть его раздвоить надо)


  1. serafims
    27.09.2024 10:11

    Жаль, нет готовых команд на выдачу импульса заданной длины обратной или положительной полярности.


  1. black_list_man
    27.09.2024 10:11
    +2

    Чем это лучше любого мк на отладочной плате с кучей ног, шимом, ацп и множеством интерфейсов за 500 рублей? Почти все они со встроенными usb- tty адаптерами, протокол обмена можно написать какой нужен, пусть будет AT. Странный девайс если честно.


    1. Sertik13 Автор
      27.09.2024 10:11

      Один плюс в нём - для пользователя он полностью готов к использованию и ничего не нужно программировать.


      1. igrunov
        27.09.2024 10:11
        +1

        И добавляется пласт проблем в связи с отсутствием желаемых функций как информирование о принятии запроса на перезагрузку, продолжительности импульса, ответа по текущему состоянию I/O подсистемы, имплементации собственного протокола вместо AT. В общем, идея написать собственную прошивку и в самом деле красива, Но 2К...


        1. Sertik13 Автор
          27.09.2024 10:11

          Так в том то и дело, что это у них собственный протокол, а для меня нужен AT


  1. cidlik
    27.09.2024 10:11

    Мне вместо такого попался GPIO Extender-T (перепутал при покупке). Вроде то же самое, только не запрограммирован. Вот тогда-то я наматюкался, конечно. На сайте производителя есть IDE, один примерчик, скудная документация и все... Часть ссылок вообще битая была. Пришлось ознакамливаться с их диалектом Си, особенностями библиотеки и пытаться впихнуть функционал обычного extender'а в 2К. Был интересный челлендж, но повторять его не хочется.


    1. Sertik13 Автор
      27.09.2024 10:11
      +1

      А мне хотелось бы повторить, так как очень хочется впихнуть в их прошивку "правильный" возврат данных из модуля, чтобы его можно было получать Микротиком через /ppp-client at-chat. Сейчас пытаюсь вести переговоры с разработчиками, может откликнуться, а может куплю версию T и сам сделаю.


      1. Sertik13 Автор
        27.09.2024 10:11

        Часть ссылок у них битая и сейчас ... Видимо интерес у публики не большой.


  1. Maks_K2
    27.09.2024 10:11
    +1

    Вопрос цены!!!!

    За 200-300 рублей уже можно купить ESP32-C3


    1. Sertik13 Автор
      27.09.2024 10:11

      Да, тут спору нет, нашим до этого очень далеко ... Импортозамещение не работает.