Страница 1 из 2

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

Добавлено: 24 янв 2023, 11:37
Sertik
Один похоже наш Чувак написал скрипт передачи SMS через WEB API прошивки Hlink модема Huawey E3372
https://forum.mikrotik.com/viewtopic.php?t=166859

Я проверял, у меня не работает. Надо бы проверить у кого есть такие модемы. В чём проблема, может у меня прошивка старая ...

Код: Выделить всё

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

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

Добавлено: 25 янв 2023, 12:53
Sertik
Просьба отписаться сюда у кого скрипт заработает.

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

Добавлено: 28 янв 2023, 21:04
SergeyN
Проверил, работает.
 
Изображение
С датой отправки только глюк
 
Изображение

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

Добавлено: 30 янв 2023, 13:34
Sertik
Сергей, спасибо, что ответили.

Какая у Вас версия прошивки модема ? Если можно прямо скрин киньте сюда из Web-интерфйса.
И какая у Вас версия РоутерОС ?

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

Добавлено: 30 янв 2023, 13:45
Sertik
А это функция для получения SMS:

Код: Выделить всё

: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 ];

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

Добавлено: 31 янв 2023, 08:40
SergeyN
Имя устройства: E3372h
Версия АО: CL2E3372HM
Версия ПО: 22.200.09.01.161
Версия веб-интерфейса: 17.100.17.00.143-Mod1.20
 
Изображение
RBD53GR-5HacD2HnD
6.49.2 (stable)
 
Изображение

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

Добавлено: 31 янв 2023, 12:07
Sertik
Спасибо, Сергей !

Соответственно Вашим данным, у меня получается версия ПО новее Вашей, а версия WEB-интерфейса более древняя ...

версия AO: CL2e3372HM
версия ПО: 22.333.01.00.00
версия WEB-интерфейса: 17.100.13.112.03 (17.100.13.01.03_Mod1.12)

Видимо надо попробовать проапгрейдить именно WEB-морду.

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

Добавлено: 09 фев 2023, 15:39
Sertik
Дело пошло. Один добрый человек создал уже много хороших скриптов для работы с CMC модемов Huawey 3372 из РоутерОС.
Вот ссылка https://forum.mikrotik.com/viewtopic.ph ... 59#p982972

Кстати у меня эти скрипты тоже заработали. Оказалось, что проблема была в установленном пароле WEB-интерфейса моего модема. Снес пароль - всё работает ! Видимо API не расчитано для доступа в защищенном режиме или скрипты не умеют авторизоваться при fetch. Будущее покажет, а пока можно пользоваться готовыми скриптами.

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

Добавлено: 10 фев 2023, 18:54
Sertik
Положу эту коллекцию скриптов сюда, тут надежнее.

Collection of Huawei API scripts for use with MikroTik
(Tested on a Huawei E3372h-320 & E3372h-153 modems
by pkt & diamuxin
https://forum.mikrotik.com/viewtopic.ph ... 59#p982972

Token Parser Library
(Main Script base)

Код: Выделить всё

# TOKEN PARSER LIBRARY
# v1.0.0 pkt

# :put [($tokenParser->"getTag") source=$xml tag="SessionInfo"]

# ($tokenParser->"getBetween")
#  get delimited value
#    source - source string
#    fromTok - (optional) text AFTER this token (or from source beginning) will be returned
#    toTok - (optional) text BEFORE this token (or until source finish) will be returned
#    startPos - (optional) start position (default 0 = beginning)
#  returns an array with fields data and pos
# 
# ($tokenParser->"getTag")
#  get value for XML tag
#    source - xml string
#    tag - tag which value is to be returned
#    startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
#  returns the tag content
# 
# ($tokenParser->"getTagDetailed")
#  get value and end position for XML tag
#    source - xml string
#    tag - tag which value is to be returned
#    startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
#  returns an array with fields "data" (tag content) and "pos" (where tag ends)
# 
# ($tokenParser->"getTagList")
#  get a list with the content of each appearance of tag
#    source - xml string
#    tag - tag which value is to be returned
#  returns an array with tag contents
# 
# ($tokenParser->"forEachTag")
#  incremental parser that calls the callback with the content of each appearance of tag
#    source - xml string
#    tag - tag which value is to be returned
#    callback - callback (with param content) to be called for each appearance of tag
#    callbackArgs - callback will be called passing this value in param args


:global tokenParser ({})

:set ($tokenParser->"getBetween") do={ # get delimited value
  # source - source string
  # fromTok - (optional) text AFTER this token (or from source beginning) will be returned
  # toTok - (optional) text BEFORE this token (or until source finish) will be returned
  # startPos - (optional) start position (default 0 = beginning)
  
  # returns an array with fields data and pos
  # if fromTok and/or toTok are specified and neither of them appear in source, empty string "" will be returned as data

  # based on function getBetween by CuriousKiwi, modified by pkt

  :local posStart
  if ([:len $startPos] = 0) do={
    :set posStart -1
  } else={
    :set posStart ($startPos-1)
  }

  :local found true
  :local data 

  :local resultStart
  :if ([:len $fromTok] > 0) do={
    :set resultStart [:find $source $fromTok $posStart]
    :if ([:len $resultStart] = 0) do={ # start token not found
      :set found false
      :set data ""
    }
    :set resultStart ($resultStart + [:len $fromTok])
  } else={
    :set resultStart 0
  }

  :local resultEnd
  :if (found = true && [:len $toTok] > 0) do={
    :set resultEnd [:find $source $toTok ($resultStart-1)]
    :if ([:len $resultEnd] = 0) do={ # end token not found
      :set found false
      :set data ""
    }
  } else={
    :set resultEnd [:len $source]
  }

  :if ($found = true) do={ :set data [:pick $source $resultStart $resultEnd] }

  :return { data=$data; pos=$resultEnd }
}

:set ($tokenParser->"getTag") do={ # get value for XML tag
  # source - xml string
  # tag - tag which value is to be returned
  # startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)

  # returns the tag content

  :global tokenParser
  :return ([($tokenParser->"getBetween") source=$source fromTok=("<$tag>") toTok=("</$tag>") startPos=$startPos]->"data")
}

:set ($tokenParser->"getTagDetailed") do={ # get value and end position for XML tag
  # source - xml string
  # tag - tag which value is to be returned
  # startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)

  # returns an array with fields "data" (tag content) and "pos" (where tag ends)

  :global tokenParser
  :return [($tokenParser->"getBetween") source=$source fromTok=("<$tag>") toTok=("</$tag>") startPos=$startPos]
}

:set ($tokenParser->"getTagList") do={ # get a list with the content of each appearance of tag
  # source - xml string
  # tag - tag which value is to be returned

  # returns an array with tag contents

  :global tokenParser

  :local result ({})
  :local doneTags false
  :local startPos 0

  :do {
    :local tagContent [($tokenParser->"getTagDetailed") source=$source tag=$tag startPos=$startPos]

    :local content ($tagContent->"data")
    :if ($content != "") do={
      :set ($result->[:len $result]) $content

      # advance start pos to search for next tag
      :set startPos ($tagContent->"pos")
    } else={
      :set doneTags true
    }
  } while=($doneTags = false)

  :return $result
}

:set ($tokenParser->"forEachTag") do={ # incremental parser that calls the callback with the content of each appearance of tag
  # source - xml string
  # tag - tag which value is to be returned
  # callback - callback (with param content) to be called for each appearance of tag
  # callbackArgs - callback will be called passing this value in param args

  :global tokenParser

  :local doneTags false
  :local startPos 0

  :do {
    :local tagContent [($tokenParser->"getTagDetailed") source=$source tag=$tag startPos=$startPos]

    :local content ($tagContent->"data")
    :if ($content != "") do={
      [$callback tagContent=$content args=$callbackArgs]

      # advance start pos to search for next tag
      :set startPos ($tagContent->"pos")
    } else={
      :set doneTags true
    }
  } while=($doneTags = false)
}
Function to get a list of SMS messages

Код: Выделить всё

:global recvSMS do={
  :local lteIP "192.168.8.1"

  :global tokenParser

  # 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")

  # parse SessionID and Token from API session data 
  :local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
  :local apiToken [($tokenParser->"getTag") source=$apiData tag="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
  :return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/sms-list" http-data=$recvData output=user as-value]
}

Function to delete SMS messages (Inbox)

Код: Выделить всё

:global delSMS do={
  :local lteIP "192.168.8.1"

  :global tokenParser

  # 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")

  # parse SessionID and Token from API session data 
  :local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
  :local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]

  # header and data config
  :local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
  :local delData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>$index</Index></request>"

  # delete SMS via LTE modem API with fetch
  :return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/delete-sms" http-data=$delData output=user as-value]
}

Function to delete SMS messages (Sentbox)

Код: Выделить всё

:global recvSMSsentbox do={
  :local lteIP "192.168.8.1"

  :global tokenParser

  # 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")

  # parse SessionID and Token from API session data 
  :local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
  :local apiToken [($tokenParser->"getTag") source=$apiData tag="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>2</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>1</UnreadPreferred></request>"

  # delete SMS via LTE modem API with fetch
  :return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/sms-list" http-data=$recvData output=user as-value]
}

:global tokenParser
:global delSMS
:local xmlSmsList ([$recvSMSsentbox]->"data")
:local smsList [($tokenParser->"getTagList") source=$xmlSmsList tag="Message"]
:local smsCount [:tonum [($tokenParser->"getTag") source=$xmlSmsList tag="Count"]]

:if ($smsCount > 0) do={

:delay 5s
:foreach tagContent in=$smsList do={
  :local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
  [$delSMS index=$index]
}
}
Function to send SMS messages

Код: Выделить всё

:global sendSMS do={
	# Example:	
	# :put [$sendSMS lteIP="192.168.8.1" phone="+34XXXXXXXXX" sms="test sms via lte api"]

    :local lteIP "192.168.8.1"

    :global tokenParser

    # 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")
      
    # parse SessionID and Token from API session data 
    :local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
    :local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]

	# header and data config
	:local apiHead "Content-Type:text/xml,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
    :return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/send-sms" http-data=$sendData output=user as-value]
}

Script to get a list of SMS messages from Inbox, forward them by email and SMS, then delete them.

Код: Выделить всё

:global tokenParser
:global recvSMS
:global delSMS
:global sendSMS
:local xmlSmsList ([$recvSMS]->"data")
:local smsList [($tokenParser->"getTagList") source=$xmlSmsList tag="Message"]
:local smsCount [:tonum [($tokenParser->"getTag") source=$xmlSmsList tag="Count"]]

:if ($smsCount > 0) do={

:foreach tagContent in=$smsList do={

  :local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
  :local date [($tokenParser->"getTag") source=$tagContent tag="Date"]
  :local phone [($tokenParser->"getTag") source=$tagContent tag="Phone"]
  :local content [($tokenParser->"getTag") source=$tagContent tag="Content"]
  :local read ([($tokenParser->"getTag") source=$tagContent tag="Smstat"] = 1)

  :if ($content != "") do={
    :put "$index $read $date $phone $content"    
    /tool e-mail send to=user@mail.com subject="SMS $phone" body="$index $read $date $phone $content"    
    :execute [$sendSMS lteIP="192.168.8.1" phone="+34XXXXXXXXX" sms="$phone $content"]
  }
}

:delay 5s
:foreach tagContent in=$smsList do={
  :local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
  [$delSMS index=$index]
}
}
script for keep sms in file (Rextended)

Код: Выделить всё

{
:local SMSfolder "SMS" ; # must already exist, do not count "flash", is added automatically if is needed
:local SMSfileend "backup_sms.txt" ; # only .txt file, the date and the time is added automatically at the start

:local arrMonths {an="01";eb="02";ar="03";pr="04";ay="05";un="06";ul="07";ug="08";ep="09";ct="10";ov="11";ec="12"}
/system clock ; # instead of use local date and time, if can be obtained, the SMS date and time can be used.
:local date [get date]
:local time [get time]
:local SMSfntime  "$[:pick $date 7 11]$($arrMonths->[:pick $date 1 3])$[:pick $date 4 6]$[:pick $time 0 2]$[:pick $time 3 5]"
:local SMSfpath   "$SMSfolder/$SMSfntime_$SMSfileend"
:local SMSnumber  "+18005551234567890"
:local SMSmessage "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
/file
:put $SMSfpath
:if ([:len [find where name="flash" and type="disk"]] = 1) do={:set SMSfpath "flash/$SMSfpath"}
:put $SMSfpath
:if ([:len [find where name=$SMSfpath]] = 0) do={print file=$SMSfpath; :delay 5s; set $SMSfpath contents=""}
:put $SMSfpath
:delay 2s
set $SMSfpath contents="$[get $SMSfpath contents]$SMSnumber $SMSmessage\r\n"
}

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

Добавлено: 17 дек 2023, 14:26
martiniman
Есть способ отправить SMS на русском? Перекодировать может?