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

Здесь выкладываем скрипты
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Один похоже наш Чувак написал скрипт передачи 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;
}


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Просьба отписаться сюда у кого скрипт заработает.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
SergeyN
Сообщения: 20
Зарегистрирован: 04 ноя 2021, 10:00

Проверил, работает.
 
Изображение
С датой отправки только глюк
 
Изображение


Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Сергей, спасибо, что ответили.

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

А это функция для получения 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 ];


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
SergeyN
Сообщения: 20
Зарегистрирован: 04 ноя 2021, 10:00

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


Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Спасибо, Сергей !

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

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

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

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

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Положу эту коллекцию скриптов сюда, тут надежнее.

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
martiniman
Сообщения: 4
Зарегистрирован: 27 ноя 2017, 19:09

Есть способ отправить SMS на русском? Перекодировать может?


Ответить