Send SMS messages via Huawei LTE modem API (tested with E3372)

Hi,

This script will send SMS via Huawei USB lte modem API with tool/fetch (tested with E3372)
I hope can be helpful :slight_smile:

github: https://github.com/NikolayDachev/RouterOS/blob/master/ros_scripts/sendSMS.txt

:global sendSMS do={
	# Send SMS messages via Huawei LTE modem API (tested with  E3372)
	# global vars:
	# 	lteIP - lte modem ip address (api)
	# 	phone - sms destination phone number
	#	sms - sms text message
	# usage example
	#	:global sendSMS
	#	:put [$sendSMS lteIP="192.168.8.1" phone="+35912345678" sms="test sms via lte api"]
	#

	:local getBetween do={
		# "CuriousKiwi - mikrotik forum" 
		# This is a basic parser, can be used for XML
		# It takes three parameters:
		# inputString - The main string
		# betweenStart - Text AFTER this point will be returned
		# betweenEnd - Text BEFORE this point will be returned
		:local posStart 0;
		:if ([:len $betweenStart] > 0) do={
		:set posStart [:find $inputString $betweenStart]
			:if ([:len $posStart] = 0) do={
				:set posStart 0
			} else={
				:set posStart ($posStart + [:len $betweenStart])
			}
		}

		:local posEnd 9999;
		:if ([:len $betweenEnd] > 0) do={
		:set posEnd [:find $inputString $betweenEnd];
		:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
		}

		:local result [:pick $inputString $posStart $posEnd];
		:return $result;
	}

	# get SessionID and Token via LTE modem API
	:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo";
	:local api [/tool fetch $urlSesTokInfo output=user as-value]; 
	:local apiData  ($api->"data");

	# pars SessionID and Token from API session data 
	:local apiSessionID [$getBetween inputString=$apiData betweenStart="<SesInfo>" betweenEnd="</SesInfo>"];
	:local apiToken [$getBetween inputString=$apiData betweenStart="<TokInfo>" betweenEnd="</TokInfo>"];

	# header and data config
	:local apiHead "Content-Type:application/x-www-form-urlencoded,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken";
	:local sendData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Sca></Sca><Content>$sms</Content><Length>-1</Length><Reserved>1</Reserved><Date>-1</Date></request>";

	# send SMS via LTE modem API with fetch
	/tool fetch  http-method=post output=user  \
	http-header-field=$apiHead \
	url="http://$lteIP/api/sms/send-sms" \
	http-data=$sendData;
}

Will try it with B715 next year :slight_smile:

Works great! Do you also have a script for receiving SMS ?

No I do not need such script, but I think will be somtihing similar.

Probably you need to read for new sms recv on lte and do something on routeros, just if you try to do that be sure to have additionally check for sender phone number aka to lock it to single number .. I think there is no need to explain why .,:grinning_face:

Hi.
I’m starting to deal with scripts. Can’t figure out what I need to change (uncomment) to make it work?

Found solution in another author’s script :sunglasses:

Could someone handle script to read SMS from LTE modem?

I’ve tested bash script to get SMS xml content:

#!/bin/bash

DATA=`curl http://192.168.8.1/api/webserver/SesTokInfo`
SESSION_ID=`echo "$DATA" | grep "SessionID=" | cut -b 10-147`
TOKEN=`echo "$DATA" | grep "TokInfo" | cut -b 10-41`

curl http://192.168.8.1/api/sms/sms-list -H "Cookie: $SESSION_ID" -H "__RequestVerificationToken: $TOKEN" --data \
"<?xml version='1.0' encoding='UTF-8'?> \
<request> \
<PageIndex>1</PageIndex> \
<ReadCount>20</ReadCount> \
<BoxType>1</BoxType> \
<SortType>0</SortType> \
<Ascending>0</Ascending> \
<UnreadPreferred>0</UnreadPreferred> \
</request>"

Result:

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   277  100   277    0     0   3186      0 --:--:-- --:--:-- --:--:--  3220
<?xml version="1.0" encoding="utf-8"?>
<response>
        <Count>1</Count>
        <Messages>
                <Message>
                        <Smstat>1</Smstat>
                        <Index>40002</Index>
                        <Phone>lifecell</Phone>
                        <Content>SMS TEXT.... </Content>
                        <Date>2022-10-18 22:02:41</Date>
                        <Sca></Sca>
                        <SaveType>4</SaveType>
                        <Priority>0</Priority>
                        <SmsType>2</SmsType>
                </Message>
        </Messages>
</response>

And trying to reproduce the same in mikrotik terminal:

:global recvSMS do={

:local getBetween do={
	# This is a basic parser, can be used for XML
	# It takes three parameters:
	# inputString - The main string
	# betweenStart - Text AFTER this point will be returned
	# betweenEnd - Text BEFORE this point will be returned
	:local posStart 0;
	:if ([:len $betweenStart] > 0) do={
	:set posStart [:find $inputString $betweenStart]
		:if ([:len $posStart] = 0) do={
			:set posStart 0
		} else={
			:set posStart ($posStart + [:len $betweenStart])
		}
	}

	:local posEnd 9999;
	:if ([:len $betweenEnd] > 0) do={
	:set posEnd [:find $inputString $betweenEnd];
	:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
	}

	:local result [:pick $inputString $posStart $posEnd];
	:return $result;
}

# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo";
:local api [/tool fetch $urlSesTokInfo output=user as-value]; 
:local apiData  ($api->"data");

:local lteIP "192.168.8.1";

# pars SessionID and Token from API session data 
:local apiSessionID [$getBetween inputString=$apiData betweenStart="<SesInfo>" betweenEnd="</SesInfo>"];
:local apiToken [$getBetween inputString=$apiData betweenStart="<TokInfo>" betweenEnd="</TokInfo>"];

# header and data config
:local apiHead "Content-Type:application/x-www-form-urlencoded,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken";
:local recvData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>1</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>0</UnreadPreferred></request>";

# recv SMS via LTE modem API with fetch
/tool fetch  http-method=post output=user  \
http-header-field=$apiHead \
url="http://$lteIP/api/sms/sms-list" \
http-data=$recvData;
}

:local arrData [ :toarray $recvSMS ];
:local varData ( $arrData->"data" );
:put [ $varData ];

And getting nothing:

[admin@gateway] > system/script/run recvSMS1

[admin@gateway] >

What I missed ?

also tried

# recv SMS via LTE modem API with fetch
:put ([/tool fetch  http-method=post output=user \
http-header-field=$apiHead \
url="http://$lteIP/api/sms/sms-list" \
http-data=$recvData as-value]->"data");
}

and delete bottom block, still display nothing

works with addiing new line at the end after last bracket

[$recvSMS lteIP="192.168.8.1"];

Now I want to write output to file for futher parse to separate message content and use it as script name run command

By adding new script:

{
:local a [/system script get recvSMS1 source]
:local outFile "recvSMS1.xml"
execute script=$a file=$outFile
}

I got file recvSMS1.xml.txt with wanted content like in bash script

Could someone help me do script to parse xml to get text inside wol_pc and put in command /script/run/ wol_pc (script with name “wol_pc” already exists)

Third script:

:local getBetween do={
	:local posStart 0;
	:if ([:len $betweenStart] > 0) do={
	:set posStart [:find $inputString $betweenStart]
		:if ([:len $posStart] = 0) do={
			:set posStart 0
		} else={
			:set posStart ($posStart + [:len $betweenStart])
		}
	}

	:local posEnd 9999;
	:if ([:len $betweenEnd] > 0) do={
	:set posEnd [:find $inputString $betweenEnd];
	:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
	}

	:local result [:pick $inputString $posStart $posEnd];
	:return $result;
}

:local statusXML [/file get recvSMS1.xml.txt contents];

:if ([:len $statusXML] > 50) do={
	:local script ([$getBetween inputString=$statusXML betweenStart="<Content>" betweenEnd="</Content>"]);
	
	system/script/run $script
}

but it get only last message because I set in recvData parametr:

<ReadCount>1</ReadCount>

I dont know how to parse all messages in xml

Would be great to implement additionally to parse all file and check for sender phone number and parse only his content with that no older system time than 1 minute that equal scheduler time of script execution

Hi all,

I have a Huawei B311s-220 router compatible with the API to fully manage it. I have tested it on Linux Debian with Python+Pip according to info circulating on the internet and I get a lot of information.

So, my idea is to use that router/modem as a WAN backup connection (failover type) and also use the API functionality to be able to read and send SMS by other means (Telegram, WhatsApp or Email).

In this post I am not very clear on how to use it, since I need to first receive the SMS (checking by scheduler) and then forward them by another way. And if it is possible, to send them also from my Mikrotik router.

@notanial, have you solved the script to analyze the received SMS?


Has anyone experimented with this issue?

Thanks.
BR.

I have tried sending SMS and it does not work:

BR.

I confirm. I have the same script error.

Modem Huawei E3372 Hlink
software version: 22.333.01.00.00
WEB interface version: 17.100.13.112.03 (17.100.13.01.03_Mod 1.12)

Analyzing the code:


{
:local getBetween do={
	# This is a basic parser, can be used for XML
	# It takes three parameters:
	# inputString - The main string
	# betweenStart - Text AFTER this point will be returned
	# betweenEnd - Text BEFORE this point will be returned
	:local posStart 0;
	:if ([:len $betweenStart] > 0) do={
	:set posStart [:find $inputString $betweenStart]
		:if ([:len $posStart] = 0) do={
			:set posStart 0
		} else={
			:set posStart ($posStart + [:len $betweenStart])
		}
	}

	:local posEnd 9999;
	:if ([:len $betweenEnd] > 0) do={
	:set posEnd [:find $inputString $betweenEnd];
	:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
	}

	:local result [:pick $inputString $posStart $posEnd];
	:return $result;
}

:local lteIP "192.168.8.1";

# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo";
:local api [/tool fetch $urlSesTokInfo output=user as-value]; 
:local apiData  ($api->"data");

# pars SessionID and Token from API session data 
:local apiSessionID [$getBetween inputString=$apiData betweenStart="<SesInfo>" betweenEnd="</SesInfo>"];
:local apiToken [$getBetween inputString=$apiData betweenStart="<TokInfo>" betweenEnd="</TokInfo>"];

:put $apiSessionID
:put " "
:put $apiToken
}

# Result:
4pO9ltivvOQXURfVlfVrHL8hUJ06Z5UBMnYNHNXXXXXXXXXXXXXXXXXXXXXXXXXvA8PerIyT0rJDBUpYtghj9BFjWVuAA7fE0N2IePPjD76Nef0zcCDLVU

aJCem0vXXXXXXXXXXXXXFJcjDiij

So far so good, it extracts Session and Token correctly.

The problem comes when it tries to validate with those data introduced in the http headers (following code), something happens that does not start the session correctly and returns the error 100003.


# header and data config
:local apiHead "Content-Type:application/x-www-form-urlencoded,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken";
:local sendData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Sca></Sca><Content>$sms</Content><Length>-1</Length><Reserved>1</Reserved><Date>-1</Date></request>";

# send SMS via LTE modem API with fetch
/tool fetch  http-method=post output=user  \
http-header-field=$apiHead \
url="http://$lteIP/api/sms/send-sms" \
http-data=$sendData;

Let’s see if anyone has had this experience with Huawei LTE/4G modems.

BR.

Well, I have already received my Huawei E3372h-320 modem that incorporates an API that allows to manage some functions of the modem.

I have tested the following script and it works correctly:


:global sendSMS do={
	# Send SMS messages via Huawei LTE modem API (tested with  E3372)
	# global vars:
	# 	lteIP - lte modem ip address (api)
	# 	phone - sms destination phone number
	#	sms - sms text message
	# usage example
	#	:global sendSMS
	#	:put [$sendSMS lteIP="192.168.8.1" phone="+35912345678" sms="test sms via lte api"]
	#

	:local getBetween do={
		# "CuriousKiwi - mikrotik forum" 
		# This is a basic parser, can be used for XML
		# It takes three parameters:
		# inputString - The main string
		# betweenStart - Text AFTER this point will be returned
		# betweenEnd - Text BEFORE this point will be returned
		:local posStart 0;
		:if ([:len $betweenStart] > 0) do={
		:set posStart [:find $inputString $betweenStart]
			:if ([:len $posStart] = 0) do={
				:set posStart 0
			} else={
				:set posStart ($posStart + [:len $betweenStart])
			}
		}

		:local posEnd 9999;
		:if ([:len $betweenEnd] > 0) do={
		:set posEnd [:find $inputString $betweenEnd];
		:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
		}

		:local result [:pick $inputString $posStart $posEnd];
		:return $result;
	}

	:local lteIP "192.168.8.1"

	# get SessionID and Token via LTE modem API
	:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo";
	:local api [/tool fetch $urlSesTokInfo output=user as-value]; 
	:local apiData  ($api->"data");

	# pars SessionID and Token from API session data 
	:local apiSessionID [$getBetween inputString=$apiData betweenStart="<SesInfo>" betweenEnd="</SesInfo>"];
	:local apiToken [$getBetween inputString=$apiData betweenStart="<TokInfo>" betweenEnd="</TokInfo>"];

	# header and data config
	:local apiHead "Content-Type:application/x-www-form-urlencoded,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken";
	:local sendData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Sca></Sca><Content>$sms</Content><Length>-1</Length><Reserved>1</Reserved><Date>-1</Date></request>";

	# send SMS via LTE modem API with fetch
	/tool fetch  http-method=post output=user  \
	http-header-field=$apiHead \
	url="http://$lteIP/api/sms/send-sms" \
	http-data=$sendData;
}

To use it, I type from Terminal the following command:


:put [$sendSMS lteIP="192.168.8.1" phone="+35912345678" sms="test sms via lte api"]

All correct, it sends the SMS without errors.

Now, like my colleague @notanial I am trying to figure out how I can get the list of received SMS and be able to forward them by email or save them in a file.

Using this script:


:global recvSMS do={

	:local lteIP "192.168.8.1"
	:local getBetween do={

		:local posStart 0;
		:if ([:len $betweenStart] > 0) do={
			:set posStart [:find $inputString $betweenStart]
			:if ([:len $posStart] = 0) do={
				:set posStart 0
			} else={
				:set posStart ($posStart + [:len $betweenStart])
			}
		}

		:local posEnd 9999;
		:if ([:len $betweenEnd] > 0) do={
			:set posEnd [:find $inputString $betweenEnd]
			:if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
		}

		:local result [:pick $inputString $posStart $posEnd]
		:return $result
	}

	# get SessionID and Token via LTE modem API
	:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
	:local api [/tool fetch $urlSesTokInfo output=user as-value]
	:local apiData  ($api->"data")

	# pars SessionID and Token from API session data 
	:local apiSessionID [$getBetween inputString=$apiData betweenStart="<SesInfo>" betweenEnd="</SesInfo>"]
	:local apiToken [$getBetween inputString=$apiData betweenStart="<TokInfo>" betweenEnd="</TokInfo>"]

	# header and data config
	:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
	:local recvData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>1</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>1</UnreadPreferred></request>"

	# recv SMS via LTE modem API with fetch
	/tool fetch  http-method=post output=user \
    http-header-field=$apiHead \
    url="http://$lteIP/api/sms/sms-list" \
    http-data=$recvData;
}

:local arrData [ :toarray $recvSMS ]
:local varData ( $arrData->"data" )
:put [ $varData ]

I execute with

:put [$recvSMS]

and I get the following result:



With a message received:

status: finished
downloaded: 0KiBC-z pause]
data: <?xml version="1.0" encoding="UTF-8"?> 1 0
40001 +34XXXXXXXXX SMS test from my Mobile 2023-01-11
13:20:26 0 0 1


\

With 3 messages received:

status: finished
downloaded: 0KiBC-z pause]
data: <?xml version="1.0" encoding="UTF-8"?> 3 1
40003 +34XXXXXXXXX SMS test from my Mobile3 2023-01-11
17:02:05 0 0 1
1 40002 +34XXXXXXXXX SMS test from my
Mobile2 2023-01-11 16:59:48 0 0
1 1 40001 +34XXXXXXXXX
SMS test from my Mobile 2023-01-11 13:20:26 0
0 1

There is a function that allows you to extract certain data from XML:


:global getBetween do={

      :local posStart 0;
      :if ([:len $betweenStart] > 0) do={
            :set posStart [:find $inputString $betweenStart]
            :if ([:len $posStart] = 0) do={
                  :set posStart 0
            } else={
                  :set posStart ($posStart + [:len $betweenStart])
            }
      }

      :local posEnd 9999;
      :if ([:len $betweenEnd] > 0) do={
            :set posEnd [:find $inputString $betweenEnd]
            :if ([:len $posEnd] = 0) do={ :set posEnd 9999 }
      }

      :local result [:pick $inputString $posStart $posEnd]
      :return $result
}

The idea is to extract the content of and of each SMS using the previous function and save it to give those values to local variables in order to resend those messages or save them in a file. But I don’t know how to do it. :frowning:

I have tried this without success:


{
:global getBetween
:execute {$recvSMS} file=sms-list.xml
:local ExtractedXML [/file get sms-list.xml.txt contents]
:local phon [$getBetween inputString=$ExtractedXML betweenStart="<Phone>" betweenEnd="</Phone>"]
:local mens [$getBetween inputString=$ExtractedXML betweenStart="<Content>" betweenEnd="</Content>"]
:put "$phon\t$mens"
}

Any help please??

BR.

diamuxin,

Not sure if you contact me over email, unfortunately I incidentally delete it (sorry about that!)
I have a lot of personal tasks this days, however when I have a free time will check If I can help here

Quick question: You want to get the a list of recv sms or you want to get the content as well ?

Regards,
Nikolay

Yes, also the content, thank you.

The idea is that the content of the SMS received (phone number and message) can be forwarded by email or sms, for example.

BR.