⬆️ ⬇️

Remotely enable Mikrotik scripts from Telegram

Alexander Koryukin GeXoGeN pushed me to this realization with his publication “ Remotely turning on the computer for free, without SMS and without clouds, using Mikrotik ”.



And a comment in one of the VK groups of Kirill Kazakov:

Yeah, not at all. I would rather write a telegram bot, which only accepts commands from my account for inclusion.


I decided to write such a bot.



So, the first thing to do is to create a telegram bot.





Then we answer 2 simple questions:

')



In response, we will get our bot token, in my case it is:



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



image

Then, you need to find our bot in the search by name @ MikrotikROuter_bo t and click on the Start button.



After that, you need to open a browser and enter the following line:



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


Where XXXXXXXXXXXXXXXXXXX is your bot's token.



A page like this will open:



image



We find on it the following text:



"Chat": {"id": 631290 ,



So, we have all the necessary information for writing scripts for Mikrotik, namely:



Bot Token: 265373548: AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4



Chat ID where he should write: 631290



To check, we can go through the browser:



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


Must get the result:



image



For our convenience, we immediately add the commands for the bot:



Find an account with the name @botfather

Then we write him the command / setcommands





We write:

@MikrotikROuter_bot



Add commands:





Now if you type in the chat "/", you should get:



image



Now go to MikroTik.



In RouterOS, there is a console utility for copying files via ftp or http / https, a utility called fetch, which is what we will use.



Open the terminal and enter:



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


Note in MikroTik you need " \ " to escape the " ? " In the URL.



Must get the result:



image



Now go to the scripts:



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" 


Do not forget to specify the correct mac and interface name, as well as bot-token and chat_id.



Now I will explain a little what they do:



The “helloworld” script sends a message: "Hello, world!" in our chat with the bot.

Script "itsworking" sends a message: "Test OK, it's Working!" in our chat with the bot.

These scripts to demonstrate the work.

I added the wolmypc script as one of the possible implementations.

Upon execution of the script, the bot will write in the chat “wol OK”.

In fact, you can run absolutely any script.



Create a task:





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 






Readable view
It is not clear why but from the working script it does not announce the global data, added the script when the system boots.

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; } 






How it works



We download our “getUpdates” messages every 30 seconds, then a parsim to find out update_id (message number) and text (our commands) and chat_id . By default, getUpdates displays from 1 to 100 messages, for convenience after reading the command, the message is deleted. in Telegram api said, to read the message you need the message number + 1



 /getUpdates?offset=update_id + 1 


Everything is checked on the Mikrotik rb915 RouterOS 6.37.1

If you send many commands at once, they will all be executed in turn at intervals of 30 seconds.



PS Many thanks to Kirill Kazakov for the idea and to my friend Alexander for helping me with the scripts.



Links



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





Modified scripts:



Added check on chat_id

Checking for a fool, if someone writes to our bot, he will answer him: "I can't talk with you.", The same way he will answer us if he does not recognize the command.

Upon execution of the command, the bot writes to the chat (see Script wolmypc)



UPD



Found with 7Stuntman7 that the file with above ~ 14 messages is no longer processed by the find command (Mikrotik restrictions). Therefore, in the future, I will alter the script to lua. Thanks to 7Stuntman7 for this, I did not know about lua.



UPD 12/08/2016



in Telegram, it seems that the getUpdate “exhaust” changed a bit. now in the main script you need to correct the offset of the message from 2 to 1



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


Source: https://habr.com/ru/post/314108/



All Articles