Mikrotik and Telegram

I’m a noob in Mikrotik and Scripting. But i got the same error as @irghost got.
However, if I try to run the tg_cmd_hi directly from terminal, then it would run without problems (lack of $from variable, of course)
So it seems that it’s not a tg_config problem, or it won’t run in that case…
Here’s what I got from terminal running tg_getUpdates:
[edit]: I’m using ROS ver 6.40.5, if that helps

tg: Load config

trusted=2312312312;trusted=12345678
botID=42123367:OOOOOOOOOOOOOOOOOOOOOlAQ
storage=
timeout=1
Reading updates...
>> /tool fetch dst-path="tg_get_updates.txt" url="https://api.telegram.org/bot42123367:OOOOOOOOOOOOOOOOOOOOOlAQ/getUpdates?timeout=1&limit=1&offset=1151
68289"
Finished to read updates.
message id=23
update id=115168289
from id=2312312312
first name=Joshua
last name=Huang
username=jhuang
name=Joshua Huang
in chat=2312312312
command=/hi
cmd=<hi>
params=<>
Try to invoke external script tg_cmd_hi

2312312312
Joshua Huang
tg: Load config
  status: failed

failure: closing connection: <400 Bad Request> 149.154.167.200:443 (5)

Before last command in tg_SendMessage insert debug command:

:put $url

(or :log $url) and check URL composed by this script.
As variant - wrong botID or chatID.

After send command /health to mybot, i have tracert my error log, :
/system script run tg_getUpdates
tg: Load config

trusted=263160993
botID=504794943:AAEyJkLCZljTmb-cKumVAKa1OtdvmbsnWaU
storage=
timeout=1
Reading updates…

/tool fetch dst-path=“tg_get_updates.txt” url=“https://api.telegram.org/bot504794943:AAEyJkLCZljTmb-cKumVAKa1OtdvmbsnWaU/getUpdates?timeout=1&limit=1&offset=790797188
Finished to read updates.
message id=149
update id=790797188
from id=263160993
first name=Fendi
last name=Kurniawan
username=
in chat=263160993
command=/health
cmd=
params=<>
Try to invoke external script tg_cmd_health

263160993
Fendi Kurniawan
ambiguous value of value-name, more than one possible value matches input

is it possible to send command via telegram then execute in RouterBOARD?

Have you use the last version (see http://forum.mikrotik.com/t/mikrotik-and-telegram/114540/1 )?

yes

I tried the script, Nice job. But I have got problem with updates, It’s seems like tgGetkey not working well…

I’m allways getting:
command=
cmd=<>
params=<>

When I’m opening the file I see the incoming message (“Hi” in this example)…

{“ok”:true,“result”:[{“update_id”:44584376,
“message”:{“message_id”:10,“from”:{“id”:542535389,“is_bot”:false,“first_name”:“Metal”,“last_name”:“Jef”,“username”:“mjef”,“language_code”:“en-US”},“chat”:{“id”:542535389,“first_name”:“Metal”,“last_name”:“Jef”,“username”:“mjef”,“type”:“private”},“date”:1518475137,“text”:“Hi”}}]}

Any idea why tgGetkey not working well ?

Command must start from /,
i.e “/hi” but not “hi”.
Also this command should be set for you bot via @BotFarther’s /setcommands.
PS: sample commands done in lowercase, i.e “/hi”, not “/Hi”. Case makes difference too.

Great, Thanks. I’m new with telegram :slight_smile:

More question how I’m sending $cmd and $params in message?

I’m trying to make telegram available by global (enviroment), This is the complete script:

:global tgBotAPI "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
:global tgDefaultChatID "AAAAAAAA,BBBBBBBB,CCCCCCC";
:global tgTrusted "AAAAAAAA,BBBBBBBB,CCCCCCC";
:global tgStorage "";
:global tgTimeout 1;

:global tgSendMessage do={
	:global tgBotAPI;
	:global tgStorage;
	:global tgDefaultChatID;
	:local tgID $tgDefaultChatID

	:if ([:len $chat]>0) do={ set tgID $chat }

	:foreach chatID in=[:toarray $tgID] do={
		:local fail false;
		:local url "https://api.telegram.org/bot$tgBotAPI/sendmessage\?chat_id=$chatID&text=$text"
		:if ([:len $mode]>0) do={:set url ($url."&parse_mode=$mode")}
		:do {
			/tool fetch url=$url keep-result=no
		} on-error={
			:log error "failed to send telegram message to '$chatID'."
			:set fail true;
		}
		:if (!$fail) do={
			:log info "telegram message has been sent to '$chatID'"
		}
	}
}

:global tgGetUpdates do={
	:global tgLastMsgID
	:global tgLastUPDID

	:local tgGetkey do={
		:local cur 0
		:local lkey [:len $key]
		:local res ""
		:local p

		:if ([:len $block]>0) do={
 			:set p [:find $text $block $cur]
 			:if ([:type $p]="nil") do={
	  			:return $res
 			}
 			:set cur ($p+[:len $block]+2)
		}

		:set p [:find $text $key $cur]
		:if ([:type $p]!="nil") do={
 			:set cur ($p+lkey+2)
 			:set p [:find $text "," $cur]
 			:if ([:type $p]!="nil") do={
   				:if ([:pick $text $cur]="\"") do={
    				:set res [:pick $text ($cur+1) ($p-1)]
   				} else={
    				:set res [:pick $text $cur $p]
   				}
			}
		}
		:return $res	
	}

	:local http do={
		:local res "fetchresult.txt"
		:if ([:len $resfile]>0) do={:set res $resfile}
		#:put $res

		:local cmd "/tool fetch"
		:if ([:len $mode]>0) do={:set cmd "$cmd mode=$mode"}
		:if ([:len $upload]>0) do={:set cmd "$cmd upload=$upload"}
		:if ([:len $user]>0) do={:set cmd "$cmd user=\"$user\""}
		:if ([:len $password]>0) do={:set cmd "$cmd password=\"$password\""}
		:if ([:len $address]>0) do={:set cmd "$cmd address=\"$address\""}
		:if ([:len $host]>0) do={:set cmd "$cmd host=\"$host\""}
		:if ([:len $"http-data"]>0) do={:set cmd "$cmd http-data=\"$"http-data"\""}
		:if ([:len $"http-method"]>0) do={:set cmd "$cmd http-method=\"$"http-method"\""}
		:if ([:len $"check-certificate"]>0) do={:set cmd "$cmd check-certificate=\"$"check-certificate"\""}
		:if ([:len $"src-path"]>0) do={:set cmd "$cmd src-path=\"$"src-path"\""}
		:if ([:len $"dst-path"]>0) do={:set cmd "$cmd dst-path=\"$"dst-path"\""}
		:if ([:len $ascii]>0) do={:set cmd "$cmd ascii=\"$ascii\""}
		:if ([:len $url]>0) do={:set cmd "$cmd url=\"$url\""}

		:put ">> $cmd"

		:global FETCHRESULT
		:set FETCHRESULT "none"

		:local script "\
	 	:global FETCHRESULT;\
	 	:do {\
	   		$cmd;\
	   		:set FETCHRESULT \"success\";\
	 	} on-error={\
	  		:set FETCHRESULT \"failed\";\
	 	}\
		"
		:execute script=$script file=$res
		:local cnt 0
		#:put "$cnt -> $FETCHRESULT"
		:while ($cnt<100 and $FETCHRESULT="none") do={ 
	 		:delay 1s
	 		:set $cnt ($cnt+1)
	 		#:put "$cnt -> $FETCHRESULT"
		}
		:local content [/file get [find name=$res] content]
		#:put $content
		if ($content~"finished") do={:return "success"}
		:return $FETCHRESULT
	}

	:global tgTrusted [:toarray $tgTrusted];
	:global tgBotAPI;
	:global tgStorage;
	:global tgTimeout;

	:put "cfg=$cfg"
	:put "trusted=$tgTrusted"
	:put "botID=$tgBotAPI"
	:put "storage=$tgStorage"
	:put "timeout=$tgTimeout"

	:local file ($tgStorage."tg_get_updates.txt")
	:local logfile ($tgStorage."tg_fetch_log.txt")
	#get 1 message per time
	:local url ("https://api.telegram.org/bot".$tgBotAPI."/getUpdates?timeout=$tgTimeout&limit=1")
	:if ([:len $tgLastUPDID]>0) do={
		:set url "$url&offset=$($tgLastUPDID+1)"
	}

	:put "Reading updates..."
	:local res [$http dst-path=$file url=$url resfile=$logfile]
	:if ($res!="success") do={
		:put "Error getting updates"
		:return "Failed get updates"
	}
	:put "Finished to read updates."

	:local content [/file get [/file find name=$file] contents]

	:local msgid [$tgGetkey key="message_id" text=$content]
	:if ($msgid="") do={ 
		:put "No new updates"
		:return 0 
	} else={
		:set tgLastMsgID $msgid
		:local updid [$tgGetkey key="update_id" text=$content]
		:set tgLastUPDID $updid

		:local tgFromID [$tgGetkey block="from" key="id" text=$content]
		:local tgUsername [$tgGetkey block="from" key="username" text=$content]
		:local tgFirstName [$tgGetkey block="from" key="first_name" text=$content]
		:local tgLastName [$tgGetkey block="from" key="last_name" text=$content]
		:local tgID [$tgGetkey block="chat" key="id" text=$content]
		:local tgMessage [$tgGetkey block="chat" key="text" text=$content]
		:local tgName "$tgFirstName $tgLastName"

		:put "message id=$msgid"
		:put "update id=$updid"
		:put "from id=$tgFromID"
		:put "first name=$tgFirstName"
		:put "last name=$tgLastName"
		:put "username=$tgUsername"
		:if ([:len $tgName]<2) do {
			:if  ([:len $tgUsername]>0) do={
				:set tgName $tgUsername
			} else={
				:set tgName "Unknown"
			}
		}
		:put "name=$tgName"
		:put "in chat=$tgID"
		:put "command=$tgMessage"

		:local allowed ( [:type [:find $tgTrusted $tgFromID]]!="nil" or [:type [:find $tgTrusted $tgID]]!="nil")
		:if (!$allowed) do={
			:put "Unknown sender, keep silence"
			:return -1
		} else={
			:local cmd ""
			:local params ""
			:local ltext [:len $tgMessage]

			:local pos [:find $tgMessage " "]
			:if ([:type $pos]="nil") do={
				:set cmd [:pick $tgMessage 1 $ltext]
			} else={
				:set cmd [:pick $tgMessage 1 $pos]
				:set params [:pick $tgMessage ($pos+1) $ltext]
			}

			:local pos [:find $cmd "@"]
			:if ([:type $pos]!="nil") do={
				:set cmd [:pick $cmd 0 $pos]
			}

			:put "cmd=<$cmd>"
			:put "params=<$params>"
			:put $tgMessage;

			:global tgLastCmd $cmd

			:put "Try to invoke external script tg_cmd_$cmd"
			:local script [:parse [/system script get "tg_cmd_$cmd" source]]
			$script params=$params chatid=$tgID from=$tgName
		}
	}
}

tgSendMessage work from mikrotik’s terminal command line, But from another script it’s not running :\ Any idea why?

From mikrotik command line I wrote (this is work):

 [$tgSendMessage chat=XXXXXXXXX text="test message"]

From another script I wrote (this is not working :frowning: ):

:global tgSendMessage
 [$tgSendMessage chat=XXXXXXXXX text="test message"]

How do you call another script - from terminal manualy or , for example, via scheduler?
If from terminal you should see error messages to get issue why it happens.
PS: calling from another script are you 100% sure that needed globals exist? Due to globals live only by next reboot. It is the reason why I use “config” script.

Everything working… I modified your script, now it’s create scheduler every 15mins check telegram updates and if telegram’s global not exists create it…
integrated all command into one “telegram” global, commands:
Receive messages (get updates): $telegram / $telegram action=receive
Send messages: $telegram action=send chat= text= mode=

BTW- Added “if tg_cmd script not found, create temporary script running the incoming message as command”, for example: if income message is “/interface disable ether1” the script will do it. -not sure how much it’s secured, I’m still work on limitations

About the config script, you right. I’ll move back to config script. about “telegram” global it’s not problem, as I said the scheduler recreate global if not exists and check for updates.

:global tgBotAPI "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
:global tgDefaultChatID "AAAAAAAAA,BBBBBBBBB,CCCCCCCC"
:global tgTrusted "AAAAAAAAA,BBBBBBBBB,CCCCCCCC"
:global tgStorage ""
:global tgTimeout 1

/system scheduler add name=telegram interval=15m on-event="
:if ([:len [/system script environment find name=telegram]]=0) do={
	:global telegram do={
		#send message
		:local tgSendMessage do={
			:global tgBotAPI;
			:global tgStorage;
			:global tgDefaultChatID;
			:local tgID \$tgDefaultChatID

			:if ([:len \$chat]>0) do={ set tgID \$chat }

			:foreach chatID in=[:toarray \$tgID] do={
				:local fail false;
				:local url \"https://api.telegram.org/bot\$tgBotAPI/sendmessage\?chat_id=\$chatID&text=\$text\"
				:if ([:len \$mode]>0) do={:set url (\$url.\"&parse_mode=\$mode\")}
				:do {
					/tool fetch url=\$url keep-result=no
				} on-error={
					:log error \"failed to send telegram message to '\$chatID'.\"
					:set fail true;
				}
				:if (!\$fail) do={
					:log info \"telegram message has been sent to '\$chatID'\"
				}
			}
		}
		#receive message
		:local tgReceiveMessage do={
			:global tgLastMsgID
			:global tgLastUPDID

			:local tgGetkey do={
				:local cur 0
				:local lkey [:len \$key]
				:local res \"\"
				:local p

				:if ([:len \$block]>0) do={
	 				:set p [:find \$text \$block \$cur]
	 				:if ([:type \$p]=\"nil\") do={
			  			:return \$res
	 				}
	 				:set cur (\$p+[:len \$block]+2)
				}

				:set p [:find \$text \$key \$cur]
				:if ([:type \$p]!=\"nil\") do={
	 				:set cur (\$p+lkey+2)
	 				:set p [:find \$text \",\" \$cur]
	 				:if ([:type \$p]!=\"nil\") do={
	   					:if ([:pick \$text \$cur]=\"\\\"\") do={
	    					:set res [:pick \$text (\$cur+1) (\$p-1)]
	   					} else={
	    					:set res [:pick \$text \$cur \$p]
   						}
					}
				}
				:return \$res	
			}

			:local http do={
				:local res \"fetchRESULT.txt\"
				:if ([:len \$resfile]>0) do={:set res \$resfile}
				#:put \$res

				:local cmd \"/tool fetch\"
				:if ([:len \$mode]>0) do={:set cmd \"\$cmd mode=\$mode\"}
				:if ([:len \$upload]>0) do={:set cmd \"\$cmd upload=\$upload\"}
				:if ([:len \$user]>0) do={:set cmd \"\$cmd user=\\\"\$user\\\"\"}
				:if ([:len \$password]>0) do={:set cmd \"\$cmd password=\\\"\$password\\\"\"}
				:if ([:len \$address]>0) do={:set cmd \"\$cmd address=\\\"\$address\\\"\"}
				:if ([:len \$host]>0) do={:set cmd \"\$cmd host=\\\"\$host\\\"\"}
				:if ([:len \$\"http-data\"]>0) do={:set cmd \"\$cmd http-data=\\\"\$\"http-data\"\\\"\"}
				:if ([:len \$\"http-method\"]>0) do={:set cmd \"\$cmd http-method=\\\"\$\"http-method\"\\\"\"}
				:if ([:len \$\"check-certificate\"]>0) do={:set cmd \"\$cmd check-certificate=\\\"\$\"check-certificate\"\\\"\"}
				:if ([:len \$\"src-path\"]>0) do={:set cmd \"\$cmd src-path=\\\"\$\"src-path\"\\\"\"}
				:if ([:len \$\"dst-path\"]>0) do={:set cmd \"\$cmd dst-path=\\\"\$\"dst-path\"\\\"\"}
				:if ([:len \$ascii]>0) do={:set cmd \"\$cmd ascii=\\\"\$ascii\\\"\"}
				:if ([:len \$url]>0) do={:set cmd \"\$cmd url=\\\"\$url\\\"\"}

				:put \">> \$cmd\"

				:global fetchRESULT
				:set fetchRESULT \"none\"

				:local script \"\
	 			:global fetchRESULT;\
	 			:do {\
	   				\$cmd;\
	   				:set fetchRESULT \\\"success\\\";\
	 			} on-error={\
	  				:set fetchRESULT \\\"failed\\\";\
	 			}\
				\"
				:execute script=\$script file=\$res
				:local cnt 0
				#:put \"\$cnt -> \$fetchRESULT\"
				:while (\$cnt<100 and \$fetchRESULT=\"none\") do={ 
	 				:delay 1s
	 				:set \$cnt (\$cnt+1)
	 				#:put \"\$cnt -> \$fetchRESULT\"
				}
				:local content [/file get [find name=\$res] content]
				#:put \$content
				if (\$content~\"finished\") do={:return \"success\"}
				:return \$fetchRESULT
			}

			:global tgTrusted [:toarray \$tgTrusted];
			:global tgBotAPI;
			:global tgStorage;
			:global tgTimeout;

			:put \"cfg=\$cfg\"
			:put \"trusted=\$tgTrusted\"
			:put \"botID=\$tgBotAPI\"
			:put \"storage=\$tgStorage\"
			:put \"timeout=\$tgTimeout\"

			:local file (\$tgStorage.\"tg_get_updates.txt\")
			:local logfile (\$tgStorage.\"tg_fetch_log.txt\")
			#get 1 message per time
			:local url (\"https://api.telegram.org/bot\".\$tgBotAPI.\"/getUpdates?timeout=\$tgTimeout&limit=1\")
			:if ([:len \$tgLastUPDID]>0) do={
				:set url \"\$url&offset=\$(\$tgLastUPDID+1)\"
			}

			:put \"Reading updates...\"
			:local res [\$http dst-path=\$file url=\$url resfile=\$logfile]
			:if (\$res!=\"success\") do={
				:put \"Error getting updates\"
				:return \"Failed get updates\"
			}
			:put \"Finished to read updates.\"

			:local content [/file get [/file find name=\$file] contents]

			:local msgid [\$tgGetkey key=\"message_id\" text=\$content]
			:if (\$msgid=\"\") do={ 
				:put \"No new updates\"
				:return 0 
			} else={
				:set tgLastMsgID \$msgid
				:local updid [\$tgGetkey key=\"update_id\" text=\$content]
				:set tgLastUPDID \$updid

				:local tgFromID [\$tgGetkey block=\"from\" key=\"id\" text=\$content]
				:local tgUsername [\$tgGetkey block=\"from\" key=\"username\" text=\$content]
				:local tgFirstName [\$tgGetkey block=\"from\" key=\"first_name\" text=\$content]
				:local tgLastName [\$tgGetkey block=\"from\" key=\"last_name\" text=\$content]
				:local tgID [\$tgGetkey block=\"chat\" key=\"id\" text=\$content]
				:local tgMessage [\$tgGetkey block=\"chat\" key=\"text\" text=\$content]
				:local tgName \"\$tgFirstName \$tgLastName\"

				:put \"message id=\$msgid\"
				:put \"update id=\$updid\"
				:put \"from id=\$tgFromID\"
				:put \"first name=\$tgFirstName\"
				:put \"last name=\$tgLastName\"
				:put \"username=\$tgUsername\"
				:if ([:len \$tgName]<2) do {
					:if  ([:len \$tgUsername]>0) do={
						:set tgName \$tgUsername
					} else={
						:set tgName \"Unknown\"
					}
				}
				:put \"name=\$tgName\"
				:put \"in chat=\$tgID\"
				:put \"command=\$tgMessage\"

				:local allowed ( [:type [:find \$tgTrusted \$tgFromID]]!=\"nil\" or [:type [:find \$tgTrusted \$tgID]]!=\"nil\")
				:if (!\$allowed) do={
					:put \"Unknown sender, keep silence\"
					:return -1
				} else={
					:local cmd \"\"
					:local params \"\"
					:local ltext [:len \$tgMessage]

					:local pos [:find \$tgMessage \" \"]
					:if ([:type \$pos]=\"nil\") do={
						:set cmd [:pick \$tgMessage 1 \$ltext]
					} else={
						:set cmd [:pick \$tgMessage 1 \$pos]
						:set params [:pick \$tgMessage (\$pos+1) \$ltext]
					}

					:local pos [:find \$cmd \"@\"]
					:if ([:type \$pos]!=\"nil\") do={
						:set cmd [:pick \$cmd 0 \$pos]
					}

					:put \"cmd=<\$cmd>\"
					:put \"params=<\$params>\"

					:global tgLastCmd \$cmd

					:if ([:len [/system script find name=\"tgCmd_\$cmd\"]]>0) do={
						:put \"Try to invoke external script tg_cmd_\$cmd\"
						:local script [:parse [/system script get \"tg_cmd_\$cmd\" source]]
						\$script params=\$params chatid=\$tgID from=\$tgName
					} else={
						:log warning \"command (\$tgMessage) has been received from '\$tgName' (\$tgID) via telegram\";
						:local tgScriptFile \"tgTemp\";
						:local tgScriptSource (\"
							:global tgSendMessage
							:local tgSend \\\$tgSendMessage

							:do {
								:local fail false;
								\$tgMessage
							} on-error={
								:set \\\$fail true;
							}

							:if (!\\\$fail) do={
								\\\$tgSend chat=\$tgID text=\\\"Command '\$tgMessage' has been done.\\\"
								:log warning \\\"telegram command '\$tgMessage' received from '\$tgName' (\$tgID) has been done.\\\"
							} else={
								\\\$tgSend chat=\$tgID text=\\\"Error command '\$tgMessage'.\\\"
								:log error \\\"telegram command '\$tgMessage' received from '\$tgName' (\$tgID) has been failed.\\\"
							}
							/system script remove [/system script find name=\\\"\$tgScriptFile\\\"]
						\")
						/system script add name=\$tgScriptFile source=\$tgScriptSource;
						/system script run \$tgScriptFile;
					}
				}
			}
			/system script environment remove [/system script environment find name=\"fetchRESULT\"];
		}

		:if (([:len \$action]=0) or (\$action=\"receive\")) do={
			\$tgReceiveMessage;
		} else={
			:if (\$action=\"send\") do={
				\$tgSendMessage chat=\$chat text=\$text;
			}
		}
	}
}

:global telegram
\$telegram
"
:execute script=[/system scheduler get value-name=on-event telegram]

Any idea how to build string for telegram message (new line and etc,..), for example I would like to do foreach on every hotspot active connection create $str and send it by telegram message…


Attached example code that I would like to send, I’m getting failed when I’m trying to send $mailBody via telegram message…
I’m think that because I used ‘\n’ for newline… anything I can do to send it? any alternative to ‘\n’ ?

:foreach userIndex in=[/ip hotspot user find profile=generated and server=guests] do={
  :local loginName [/ip hotspot user get value-name=name $userIndex];
  :local loginPass [/ip hotspot user get value-name=password $userIndex];
  :local loginMAC [/ip hotspot user get value-name=mac-address $userIndex];
  :local loginComment [/ip hotspot user get value-name=comment $userIndex];
  :if ([:len [:find [/ip hotspot user get value-name=comment $userIndex] "last connection was at"]]>0) do={
    :local loginLastTime [:pick [/ip hotspot user get value-name=comment $userIndex] ([:find [/ip hotspot user get value-name=comment $userIndex] "last connection was at"]+23) ([:find [/ip hotspot user get value-name=comment $userIndex] "last connection was at"]+23+11)];
    :local loginDaysAgo [$calcDays $loginLastTime [/system clock get date]];
    :set loginComment [:pick [/ip hotspot user get value-name=comment $userIndex] 0 ([:find [/ip hotspot user get value-name=comment $userIndex] "last connection was at"]-2)];
    :if ($loginDaysAgo>30) do={
      /ip hotspot user remove $userIndex;
      :log warning "The user '$loginName' was removed. The account not being use more then 30 days.";
      :set loginComment "<expired>";
      :set mailSend true;
    }
    :set loginComment ($loginComment."\nLast seen: $loginLastTime ($loginDaysAgo days ago)");
  }
  :if ([:len $loginMAC]>0) do={
    :set mailBody ($mailBody."\nUsername: $loginName\nPassword: $loginPass\nMAC Address: $loginMAC\nComment: $loginComment\n");
  } else={
    :set loginMAC "<unsigned>";
    :set mailBody ("\nUsername: $loginName\nPassword: $loginPass\nMAC Address: $loginMAC\nComment: $loginComment\n".$mailBody);
  }
}

This forum needs “Like” button %) Good job!

Check tg_cmd_health code for multi-line.
If shortly - new line is coded as “%0A” not “\n”. It is from URL encoding rules.
Also check https://core.telegram.org/bots/api#markdown-style (markdown style) for simplified formatting in Telegram.

Great thanks ! Started to work on addons (cmd): https://forum.mikrotik.com/viewtopic.php?f=9&t=130984

Hi,

Script is work.
When I run script from terminal I get message in Telegram.
But when I reply /hi and /health, bot not respond.
Please someone help me :slight_smile:

Hi!
Have tested the script and got an answer on Hi command from bot:
Hi \u0421\u0435\u0440\u0433\u0435\u0439 , how are you?

Hi,
if i try to run script tg_cmd_xxxx separately they works fine…
when i send /message from telegram to bot, run tg_getUpdates in telnet and i receive “no such item”

tg: Load config

trusted=xxxxxxxx;trusted=yyyyyyyy
botID=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
storage=/disk1/
timeout=1
Reading updates...
>> /tool fetch dst-path="/disk1/tg_get_updates.txt" ....................
no such item

any idea??
Thank you

Try this:
“storage”=“flash/”;
instead of disk