Віддалене включення скриптів Mikrotik із Telegram

На цю реалізацію мене підштовхнув Олександр Корюкін GeXoGeN своєю публікацією «Увімкнення комп'ютера безкоштовно, без SMS і без хмар, за допомогою Mikrotik".

І коментар в одній із груп ВК Кирила Казакова:

Так, зовсім не сек'юрно. Я б краще написав телеграм бота, який приймає тільки з мого облікового запису команди на включення.

Я вирішив написати такого бота.

Отже, перше, що потрібно зробити, - це створити бота в telegram.

  • Знаходимо в пошуку обліковий запис з ім'ям @botfather
  • Натискаємо на кнопку Start у нижній частині екрану
  • Після чого пишемо йому команду / Newbot

Потім відповідаємо на 2 нескладні питання:

  • Перше питання – ім'я створюваного бота MyMikrotikRouter
  • Друге питання – нік створюваного бота (має закінчуватися на bot) MikrotikROuter_bot

У відповідь отримаємо токен нашого бота, в моєму випадку це:

Використовуйте цей дзвінок для використання HTTP API: 265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4

Віддалене включення скриптів Mikrotik із Telegram
Потім, потрібно знайти нашого бота в пошуку на ім'я @MikrotikROuter_bot і натиснути кнопку Start.

Після цього потрібно відкрити браузер та ввести наступний рядок:

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

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

Відкриється сторінка приблизно такого вигляду:

Віддалене включення скриптів Mikrotik із Telegram

Знаходимо на ній наступний текст:

"chat": {"id":631290,

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

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

ID чату, куди він повинен писати: 631290

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

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

Повинні отримати результат:

Віддалене включення скриптів Mikrotik із Telegram

Для нашої зручності, одразу додамо команди для бота:

Знаходимо обліковий запис з ім'ям @botfather
Після чого пишемо йому команду / setcommands

  • Він запитає якого боту

Пишемо:
@MikrotikROuter_bot

Додаємо команди:

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

Тепер якщо набрати в чаті «/», то маємо отримати:

Віддалене включення скриптів Mikrotik із Telegram

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

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

Відкриваємо термінал і вводимо:

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

Зверніть увагу в MikroTik необхідний» для екранування знака «?» в URL.

Повинні отримати результат:

Віддалене включення скриптів Mikrotik із Telegram

Тепер переходимо до сриптів:

Привіт Світ

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}

їїпрацювання

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=ifnamer
    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
    nr
    n:if ( [/file get [/file find name=getUpdates] size] > 50 ) do={r
    nr
    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
    nr
    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
    nr
    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
    nr
    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 5r
    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 (номер повідомлення) та текст (наші команди) та chat_id . За замовчуванням getUpdates виводить від 1 до 100 повідомлень, для зручності після прочитання команди повідомлення видаляємо. в Telegram api сказано, щоб прочитати повідомлення необхідно номер повідомлення + 1

/getUpdates?offset=update_id + 1

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

PS Велике дякую Кирилу Казакову за ідею та моєму другу Олександру за допомогу зі скриптами.

Посилання

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

оновлено:

03:11:16

Доопрацював скрипти:

Додав перевірку на chat_id
Перевірка на дурня, якщо хтось напише нашому боту, він відповість йому: » I can't talk with you. «, аналогічно відповість нам, якщо не розпізнає команду.
За виконання команди бот відписується в чат (див. Скрипт wolmypc)

UPD

Знайшли з 7Stuntman7 що файл з вище ~ 14 повідомлень перестає оброблятися командою find (обмеження Mikrotik). Тому в майбутньому скрипт перероблю на lua спасибі 7Stuntman7 за це про lua не знав.

UPD 08.12.2016

в Telegram мабуть трохи змінили "вихлоп" getUpdate. тепер в основному скрипт потрібно поправити зміщення повідомлення з 2 на 1

зміни

:local message [:pick $content ($startLoc + 2) $endLoc] ;

заменить на :

:local message [:pick $content ($startLoc + 1) $endLoc] ;

Джерело: habr.com