На данную реализацию меня подтолкнул Александр Корюкин GeXoGeN своей публикацией "Удалённое включение компьютера бесплатно, без SMS и без облаков, с помощью Mikrotik".

И комментарий в одной из групп ВК Кирилла Казакова:
Да уж, совсем не секьюрно. Я бы лучше написал телеграм бота, который принимает только с моего аккаунта команды на включение.

Я решил написать такого бота.

Итак, первое, что нужно сделать – это создать бота в telegram.

  • Находим в поиске аккаунт с именем @botfather
  • Нажимаем на кнопку Start в нижней части экрана
  • После чего пишем ему команду /newbot

Потом отвечаем на 2 несложных вопроса:

  • Первый вопрос – имя создаваемого бота MyMikrotikROuter
  • Второй вопрос – ник создаваемого бота (должен оканчиваться на bot) MikrotikROuter_bot

В ответ получим токен нашего бота, в моём случае это:

Use this token to access the HTTP API: 265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4

image
Затем, нужно найти нашего бота в поиске по имени @MikrotikROuter_bot и нажать на кнопку Start.

После этого нужно открыть браузер и ввести следующую строку:

 https://api.telegram.org/botXXXXXXXXXXXXXXXXXX/getUpdates

Где XXXXXXXXXXXXXXXXXX – токен вашего бота.

Откроется страница примерно следующего вида:

image

Находим на ней следующий текст:

«chat»:{«id»:631290,

Итак, у нас есть вся необходимая информация для написания скриптов для Mikrotik'а, а именно:

Токен бота: 265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4

ID чата, куда он должен писать: 631290

Для проверки можем зайти через браузер:

https://api.telegram.org/bot265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4/sendmessage?chat_id=631290&text=test

Должны получить результат:

image

Для нашего удобства, сразу добавим команды для бота:

Находим аккаунт с именем @botfather
После чего пишем ему команду /setcommands

  • Он спросит какому боту

Пишем:
@MikrotikROuter_bot

Добавляем команды:

  • helloworld< — Test message on chat 1
  • itsworking — Test Message on chat 2
  • wolmypc — wake Up my PC

Теперь если набрать в чате "/", то должны получить:

image

Теперь переходим к MikroTik.

В RouterOS есть консольная утилита для копирования файлов через ftp или http/https, утилита называется fetch, именно ей мы и будем пользоваться.

Открываем terminal и вводим:

/tool fetch url="https://api.telegram.org/bot265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4/sendmessage\?chat_id=631290&text=test " keep-result=no

Обратите внимание в MikroTik необходим "\" для экранирования знака "?" в URL.

Должны получить результат:

image

Теперь переходим к сриптам:

helloworld
system script add name="helloworld" policy=read source={/tool fetch url="https://api.telegram.org/bot265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4/sendmessage\?chat_id=631290&text=Hello,world! " keep-result=no}


itsworking
system script add name="itsworking" policy=read source={/tool fetch url="https://api.telegram.org/bot265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4/sendmessage\?chat_id=631290&text=Test OK, it's Working " keep-result=no}


wolmypc
system script add name="wolmypc" policy=read source="/tool wol mac=XX:XX:XX:XX:XX:XX interface=ifname\r    \n/tool fetch url=\"https://api.telegram.org/boXXXXXXXXXXXXXXXXXXX\\?chat_id=631290&text=wol OK\" keep-resul    t=no"

Не забываем указать правильный mac и имя интерфейс, а так же bot-token и chat_id.

Сейчас немного поясню что они делаю:

Скрипт «helloworld» отправляет сообщение: " Hello,world!" в наш чат с ботом.
Скрипт «itsworking» отправляет сообщение: " Test OK, it's Working !" в наш чат с ботом.
Данные скрипты для демонстрации работы.
Скрипт «wolmypc» я добавил, как одну из возможных реализации.
По выполнению скрипта бот напишет в чат «wol OK».
По сути можно запускать абсолютно любой скрипт.

Создаем задание:



Telegram.src
/system scheduler
add interval=30s name=Telegram on-event=":tool fetch url=(\"https://api.telegr    am.org/\".\$botID.\"/getUpdates\") ;\r    \n:global content [/file get [/file find name=getUpdates] contents] ;\r    \n:global startLoc 0;\r    \n:global endLoc 0;\r    \n\r    \n:if ( [/file get [/file find name=getUpdates] size] > 50 ) do={\r    \n\r    \n:set startLoc  [:find \$content \"update_id\" \$lastEnd ] ;\r    \n:set startLoc ( \$startLoc + 11 ) ;\r    \n:local endLoc [:find \$content \",\" \$startLoc] ;\r    \n:local messageId ([:pick \$content \$startLoc \$endLoc] + (1));\r    \n:put [\$messageId] ;\r    \n:#log info message=\"updateID \$messageId\" ;\r    \n\r    \n:set startLoc  [:find \$content \"text\" \$lastEnd ] ;\r    \n:set startLoc ( \$startLoc  + 7 ) ;\r    \n:local endLoc [:find \$content \",\" (\$startLoc)] ;\r    \n:set endLoc ( \$endLoc - 1 ) ;\r    \n:local message [:pick \$content (\$startLoc + 2) \$endLoc] ;\r    \n:put [\$message] ;\r    \n:#log info message=\"message \$message \";\r    \n\r    \n:set startLoc  [:find \$content \"chat\" \$lastEnd ] ;\r    \n:set startLoc ( \$startLoc + 12 ) ;\r    \n:local endLoc [:find \$content \",\" \$startLoc] ;\r    \n:local chatId ([:pick \$content \$startLoc \$endLoc]);\r    \n:put [\$chatId] ;\r    \n:#log info message=\"chatID \$chatId \";\r    \n\r    \n:if ((\$chatId = \$myChatID) and (:put [/system script find name=\$messa    ge] != \"\")) do={\r    \n:system script run \$message} else={:tool fetch url=(\"https://api.teleg    ram.org/\".\$botID.\"/sendmessage\\\?chat_id=\".\$chatId.\"&text=I can't t    alk with you. \") keep-result=no} ;\r    \n:tool fetch url=(\"https://api.telegram.org/\".\$botID.\"/getUpdates\\\?    offset=\$messageId\") keep-result=no; \r    \n} \r    \n" policy=    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon     start-date=nov/02/2010 start-time=00:00:00
	
add name=Telegram-startup on-event=":delay 5\r    \n:global botID \"botXXXXXXXXXXXXXXXXXX\" ;\r    \n:global myChatID \"631290\" ;\r    \n:global startLoc 0;\r    \n:global endLoc 0;\r    \n:tool fetch url=(\"https://api.telegram.org/\".\$botID.\"/getUpdates\")     ;" policy=    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon     start-time=startup



Читаемый вид
непонятно почему но из рабочего скрипта не оглашает глобальные данные, добавил скрипт при загрузке системы.
Telegram-startup
:delay 5
:global botID "botXXXXXXXXXXXXXXXXXX" ;   token bot
:global myChatID "xxxxxx" ;                               chat_id
:global startLoc 0;
:global endLoc 0;
:tool fetch url=("https://api.telegram.org/".$botID."/getUpdates") ;


Telegram
:tool fetch url=("https://api.telegram.org/".$botID."/getUpdates") ;
:global content [/file get [/file find name=getUpdates] contents] ;
:global startLoc 0;
:global endLoc 0;

:if ( [/file get [/file find name=getUpdates] size] > 50 ) do={

:set startLoc  [:find $content "update_id" $lastEnd ] ;
:set startLoc ( $startLoc + 11 ) ;
:local endLoc [:find $content "," $startLoc] ;
:local messageId ([:pick $content $startLoc $endLoc] + (1));
:put [$messageId] ;
#:log info message="updateID $messageId" ;

:set startLoc  [:find $content "text" $lastEnd ] ;
:set startLoc ( $startLoc  + 7 ) ;
:local endLoc [:find $content "," ($startLoc)] ;
:set endLoc ( $endLoc - 1 ) ;
:local message [:pick $content ($startLoc + 2) $endLoc] ;
:put [$message] ;
#:log info message="message $message ";

:set startLoc  [:find $content "chat" $lastEnd ] ;
:set startLoc ( $startLoc + 12 ) ;
:local endLoc [:find $content "," $startLoc] ;
:local chatId ([:pick $content $startLoc $endLoc]);
:put [$chatId] ;
#:log info message="chatID $chatId ";

:if (($chatId = $myChatID) and (:put [/system script find name=$message] != "")) do={
:system script run $message} else={:tool fetch url=("https://api.telegram.org/".$botID."/sendmessage\?chat_id=".$chatId."&text=I can't talk with you. ") keep-result=no} ;
:tool fetch url=("https://api.telegram.org/".$botID."/getUpdates\?offset=$messageId") keep-result=no; 
} 




Как это работает


Скачиваем наши сообщения «getUpdates» каждые 30 сек., затем парсим, чтобы узнать update_id (номер сообщения) и text (наши команды) и chat_id . По умолчанию getUpdates выводит от 1 до 100 сообщений, для удобства после прочтения команды, сообщение удаляем. в Telegram api сказано, чтобы прочесть сообщение необходимо номер сообщения + 1

/getUpdates?offset=update_id + 1

Все проверено на Mikrotik rb915 RouterOS 6.37.1
Если отправить сразу много команд, они все по очереди будут выполняться с интервалом 30 сек.

P.S. Огромное спасибо Кириллу Казакову за идею и моему другу Александру за помощь со скриптами.

Ссылки


habrahabr.ru/post/313794
1spla.ru/index.php/blog/telegram_bot_for_mikrotik
core.telegram.org/bots/api
wiki.mikrotik.com/wiki/Manual:Scripting

upd:

03:11:16



Доработал скрипты:

Добавил проверку на chat_id
Проверка на дурака, если кто то напишет нашему боту, он ответит ему: " I can't talk with you. ", аналогично ответит нам, если не распознает команду.
По выполнению команды, бот отписывается в чат (см. Скрипт wolmypc)

UPD

Нашли с 7Stuntman7 что файл с выше ~ 14 сообщений, перестает обрабатываться командой find (ограничения Mikrotik). По этому в будущем скрипт переделаю на lua cпасибо 7Stuntman7 за это, про lua не знал.
Поделиться с друзьями
-->

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


  1. kolu4iy
    01.11.2016 11:47

    О. Вот это уже действительно удобно.


  1. dmitry_ch
    01.11.2016 12:28

    Очень интересно, спасибо! И необычно, и по делу!


  1. Klajnor
    01.11.2016 12:45

    Спасибо
    Хорошая идея.


  1. serafims
    01.11.2016 13:00
    +2

    А где взять Telegrem?


    1. bibliary
      01.11.2016 15:52

      https://telegram.org/


  1. umatrix
    01.11.2016 14:11

    https://api.telegram.org/bot<i><b>265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4</b></i>/sendmessage?chat_id=<i><b>631290</b></i>&text=<b>test</b>


    тэги как-то плохо отработались.


    1. dimonw
      01.11.2016 14:12

      Спасибо, поправил.



  1. ThirdWay
    01.11.2016 16:32
    +1

    А проверяется ли мой chat_id? Никак не найду этого момента в скрипте.


    1. dimonw
      01.11.2016 16:35

      на данный момент нет.


    1. dimonw
      03.11.2016 04:08

      добавил


  1. qwsj
    02.11.2016 01:34

    я тут понял что еще можно очень прикольно использовать netwatch, что позволяет легко мониторить нужные устройства в сети, юзая запросы с /tool fetch


  1. faloot
    02.11.2016 11:34

    А что веб хук перестал работать? с помощью веб хука сразу же отправляется сообщения


    1. dimonw
      02.11.2016 11:56

      К сожалению, на данный момент существует ограничение на использование webHook — он работает только по https и только с валидным сертификатом, что, например для меня пока критично за счет отсутствия поддержки сертифицирующими центрами динамических днс.


  1. andsons
    02.11.2016 17:51

    скажите, а для чего $endLoc в скрипте, его нигде не попадается в качестве переменной
    на rb951 не заработал скрипт. переменные endLoc, startLoc пустые


    1. dimonw
      03.11.2016 04:09

      поправил, видимо ночью потерял, пока оформлял тему :)


  1. 7Stuntman7
    02.11.2016 17:58

    Я что-то не понимаю, куда уже копать, но при выполнение скрипта у меня пустая переменная content, следовательно дальнейшая работа сводится на нет.
    Файл скачивает и данные в нем есть.
    Ткните носом куда копнуть :)


    1. dimonw
      02.11.2016 18:03

      В выхлопе > system script environment print что то есть?, добавил в конце темы.


      1. 7Stuntman7
        02.11.2016 22:53

        Вот выхлоп:
        0 botID bot##### (Здесь ID бота)
        1 content [/file get [/file find name=getUpdates] contents]
        2 endLoc 0
        3 startLoc 11

        Я так понимаю сыпется после момента присвоения startLoc+11

        В общем снова не работает.
        V6.37.1 RB2011UiAS


  1. andsons
    03.11.2016 00:57

    так же само и у меня. как выяснил переменная content пустая и после :set startLoc ( $startLoc + 11 ); только 11 в переменной startLoc. Девайс rb951


  1. dimonw
    03.11.2016 03:14

    немного переделал скрипты + добавил функционал, смотреть в теме.


    1. 7Stuntman7
      03.11.2016 07:48

      Поставил обновленный скрипт. Все так же. Судя по всему скрипт доходит до :find $content и высыпается. Так как меняется переменная startLoc на 11. До логирования он не доходит.


      1. dimonw
        03.11.2016 12:52

        хм… даже не знаю уже куда капнуть… перезагружать девайс пробовали?
        просто проверил и сам код, и железку перезагружал раза 10.


  1. dimonw
    03.11.2016 13:03

    возможно старые параметры в environment остались.

    сделайте выгрузку,

    system script export file=1
    system scheduler export file=2

    можете в личку с затертым token-bot отправить, может символы какие то бьются при переносе.


    1. Tr0janec
      03.11.2016 13:17

      a что за не объявленная переменная $lastEnd?


  1. dimonw
    03.11.2016 13:23

    можете ей 0 присвоить
    :global lastEnd 0;
    либо вписать в место нее 0 вписать


  1. Tr0janec
    03.11.2016 16:15

    Выяснил, что переменная content пустая так как файл getUpdates большой. Как только размер переваливает за 1Кб, содержимое файла ей не присваивается.


    1. dimonw
      03.11.2016 16:27

      да, увы ограничения Mikrotik. команда find свыше не обрабатывает… у меня предел это 14 сообщений.


  1. dimonw
    03.11.2016 16:26

    если в логе выдает

    script,info updateID 1

    это значит что файл getUpdate слишкоми жирный.


  1. Klajnor
    04.11.2016 12:56
    +1

    С LUA не понимаю. Вроде нет поддержки уже