Разборка SMS и отправка на e-mail

Здесь выкладываем скрипты
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Ответить
pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Уважаемый EagleNN, желание добить ни куда не пропало, как будет найдено время, обязательно доделаю.
Ваш пример я видел, он отличается тем, что ваш модем возвращает новую строку \r\n\r\n, а мой скрипт основан на \r\n, вы можете подправить в последней бэте сдвиг +2, тогда у вас он заработает. Вообще я давно перелопатил этот скрипт на работу с несколькими модемами, и привёл в божеский вид, но поскольку сменил тип возврата на вложенный массив для возможности оперировать исключениями, требуется серьёзно перелопатить основное тело.
Но вот отзыв snowleo244 опять заставил задуматься о проблеме того, что в ros нет хорошего инструмента гарантировано вернуть запрашиваемую команду. Всё думаю, что работать с логом будет более вернее. Но там свои подводные камни.


pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

В первом сообщении обновлены скрипты PDUtoEMAIL и extractSmsModem
Что изменено.
1) по скольку на каком то этапе была переработана логика сохранения смс, хранение сообщения в модеме, стало избыточно. По этому стирание смс из модема происходит сразу после чтения в один приём.
2) Переработан скрипт extractSmsModem на работу со множеством модемов.
3) extractSmsModem больше не принимает аргументов
4) extractSmsModem изменился тип возврата на вложенный массив

Переработана логика извлечения, по образцам присланным товарищем EagleNN.
Проблема озвученная snowleo244 не решена.


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

В помощь автору. Нароете 10$ и не надо ждать тексты ламеров. Сами всё отладите.
https://m2msupport.net/m2msupport/downl ... nd-tester/


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Обновлён скрипт extractSmsModem.
Функция заметно пожирнела. причина - у многих возникли проблемы с чтением больших массивов SMS за один приём.
Поскольку в ROS нет инструмента управлять задержкой извлечения, то дописал второй режим работы со штучным извлечением.
То-есть, если скрипт не может прочитать пачкой, то будет читать по одному. Время для lte модемов будет равняться трём секундам на смс. Например при заполненной SIM карте на 250 ячеек время чтения будет более 12 минут 39 секунд. Но по сути , это экстренная мера, как показали отзывы, R11E успевает пачкой выплюнуть 16 смс. Да и сим карт с такими объёмами сейчас днём с огнём не сыщешь.


Meteor
Сообщения: 7
Зарегистрирован: 27 июл 2018, 11:15

Добрый день.
Автор, очень нужен такой скрип, только рабочий. Хочу помочь чем смогу.
Есть тарелка Mikrotik с LNG-R с "R11e-LTE" на борту.
Столкнулся с проблемой, на почту приходят не обработанные данные, или не полные.
Строки:

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

Modem: manufacturer="MikroTik";model="R11e-LTE";name=lte1;revision="MikroTik_CP_2.160.000_v013";type=lte
Error: wrong answer to AT+CMGD=?
Returned:
+EEMLTESVC: XXX
+EEMLTEINTRA: XXX
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+MMSG: 0, 1
^SMMEMFULL: SM
+CMGD: (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30),(0-4)
OK
+MMSG: 0, 1
^SMMEMFULL: SM
Ради этого зарегался.

Красным затерт пароль 6-ти значный, и синим номер телефона. Может как то поможет в отладке.
Изображение


pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Хм, ответ от модема верен, не должен был скрипт спотыкнуться в этом месте, сейчас найду часок и разберусь что не так.
Вообще какая-то печаль в r11e с cmgd , уже не первый отзыв.


pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Обновлён скрипт extractSmsModem. исправлена ошибка.
Meteor , проверяйте, отпишите о результате.


Meteor
Сообщения: 7
Зарегистрирован: 27 июл 2018, 11:15

На почту пришло следующее:

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

Modem: manufacturer="MikroTik";model="R11e-LTE";name=lte1;revision="MikroTik_CP_2.160.000_v013";type=lte
Error: wrong answer in CMGD
Returned:
+CMS ERROR: 500


pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Meteor Проделайте следующее: откройте winbox
терминал , введите команду /system log add action=memory topics=lte
Далее перейдите на вкладку tools sms
активируйте галку receive enabled
нажмите кнопку inbox
удалите пару не смежных sms
если не была включена receive enabled , то можете отключить обратно
возвращайтесь в терминал
выполняйте команду /log print file=debug
переходите во вкладку files и присылайте файл debug.txt мне в личку или на почту supscriptpdu@mail.ru


pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Meteor пробуйте такой скрипт extract:

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

:global extractSmsModem do={
# Функция не принимает аргументов.
# возвращает массив
# строку errorString текст ошибки, если таковая присутствует
# вложенный массив со значениями - pdu-name modem
# поддержка двух симочных моделей не реализована
# концепция скрипта подразумевает возможную потерю pdu при отсутствии поддержки команд модемом

# вложенная функция запросов
:local chat do={
:local t {"r"="";"f"=""}
:if ($1 = "lte") do={:set ($t->"r") ([/interface lte at-chat $2 input=$3 wait=yes as-value]->"output")}
:if ($1 = "ppp-client") do={:set ($t->"r") ([/interface ppp-client at-chat $2 input=$3 as-value]->"output")}
:if (($t->"r")~"(^|\n)OK(\$|\r)" != true) do={:set ($t->"f") true} else={:set ($t->"f") false}
:return $t
}
# массив с найдеными модемами
:local nameFind [:toarray ""]
# ищем модемы lte
:foreach i in=[/interface lte find] do={
if ([/interface lte get $i value-name=disabled] = false) do={
:local tmp [/interface lte info $i once as-value]
:set $nameFind ($nameFind , {{"name"=[/interface lte get $i value-name=name];"type"="lte";"manufacturer"=($tmp->"manufacturer");"model"=($tmp->"model");"revision"=($tmp->"revision")}})
}}
# ищем модемы ppp-client
:foreach i in=[/interface ppp-client find] do={
if ([/interface ppp-client get $i value-name=disabled] = false) do={
:local manufacturer 
:set $nameFind ($nameFind , {"name"=[/interface ppp-client get $i value-name=name];"type"="ppp-client"})
}}
:if ([:len $nameFind] = 0) do={:return "No found Modem"}

# объявляем возврат с обязательной инициализацией
:local output [[:parse "({\"errorStr\"=[:tostr \"\"];\"arr\"=[:toarray \"\"]})"]]

# опрашиваем все модемы по очереди
:foreach m in=$nameFind do={
:local tmp
:local tmp2
:local stStart
:local stEnd
:local mode
do {
# проверяем режим
:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGF?"]
:if (($tmp->"f")) do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $stStart [:find ($tmp->"r") "+CMGF"]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $tmp2 [:pick ($tmp->"r") ($stStart + 7)]
:if ($tmp2 = "0") do={:set $mode false} else={:set $mode true}
# устанавливаем режим PDU
:if ($mode) do={:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGF=0"]}
:if (($tmp->"f")) do={:set $tmp2 "wrong answer to AT+CMGF=0\r\n"; throw;}
# временное хранение
:local curStruct {"pdu"=[:toarray ""];"index"=[:toarray ""]}
# читаем
# CMGL read sms
# 0 Received unread messages
# 1 Received read messages
# 2 Stored unsent messages
# 3 Stored sent messages
# 4 All messages
:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGL=4"]
:if (!($tmp->"f")) do={
:local flagend true
# проверяем что sms есть
:set $stStart [:find ($tmp->"r") "+CMGL"]
:if ([:typeof $stStart] != "num") do={:set $flagend false;}
:set $stStart
# извлекаем строки из текста
:while ($flagend) do={
:set $stStart [:find ($tmp->"r") "+CMGL" $stStart]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick ($tmp->"r") $stStart $stEnd]
:local stat [:tonum [:pick $tmp2 ([:find $tmp2 ","] + 1)]]
:if (($stat = 0) or ($stat = 1)) do={
:local length [:tonum [ pick $tmp2 ([:find $tmp2 ",,"] + 2) [:len $tmp2]]]
:local index  [:tonum [ pick $tmp2 ([:find $tmp2 " "] + 1) [:find $tmp2 ","]]]
:set $stStart ($stEnd + 2)
:local coretka true
:while ($coretka) do={
:if (([:pick ($tmp->"r") $stStart] = "\r") or ([:pick ($tmp->"r") $stStart] = "\n")) do={
:set $stStart ($stStart + 1)} else={:set $coretka false}}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick ($tmp->"r") $stStart $stEnd]
:set $length (($length + 1 + [:tonum ("0x".[ pick $tmp2 0 2])]) * 2)
:if ($length != [:len $tmp2]) do={:set $tmp2 "wrong length in CMGL\r\n"; throw;}
:set ($curStruct->"pdu") (($curStruct->"pdu") , {{"pdu"=$tmp2;"name"=($m->"name");"mode"="sms"}})
:set ($curStruct->"index") (($curStruct->"index") , $index)
}
:set $tmp2 [:pick ($tmp->"r") $stEnd [:len ($tmp->"r")]]
:if (($tmp2~"\\+CMGL" != true) and ($tmp2~"(^|\n)OK(\$|\r)" = true)) do={:set $flagend false}
}
} else={:local simFill
do {
:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGD=?"]
:if (($tmp->"f")) do={throw;}
:set $stStart [:find ($tmp->"r") "+CMGD"]
:if ([:typeof $stStart] != "num") do={throw;}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={throw;}
:set $tmp2 [:pick ($tmp->"r") $stStart $stEnd]
:set $stStart [:find $tmp2 "("]
:if ([:typeof $stStart] != "num") do={throw;}
:set $stEnd [:find $tmp2 ")"]
:if ([:typeof $stEnd] != "num") do={throw;}
:set $simFill [:toarray [:pick $tmp2 ($stStart + 1) $stEnd]]
} on-error={:set $tmp2 "wrong answer to AT+CMGD=?\r\n"; throw;}
:foreach i in=$simFill do={do { 
:set $tmp [$chat ($m->"type") ($m->"name") ("AT+CMGR=".[:tostr $i])]
:if (($tmp->"f")) do={throw;}
:set $stStart [:find ($tmp->"r") "+CMGR"]
:if ([:typeof $stStart] != "num") do={throw;}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={throw;}
:set $tmp2 [:pick ($tmp->"r") $stStart $stEnd]
:local stat [:tonum [:pick $tmp2 ([:find $tmp2 " "] + 1)]]
:if (($stat = 0) or ($stat = 1)) do={
:local length [:tonum [ pick $tmp2 ([:find $tmp2 ",,"] + 2) [:len $tmp2]]]
:set $stStart ($stEnd + 2)
:local coretka true
:while ($coretka) do={
:if (([:pick ($tmp->"r") $stStart] = "\r") or ([:pick ($tmp->"r") $stStart] = "\n")) do={
:set $stStart ($stStart + 1)} else={:set $coretka false}}
:set $stEnd [:find ($tmp->"r") "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={throw;}
:set $tmp2 [:pick ($tmp->"r") $stStart $stEnd]
:set $length (($length + 1 + [:tonum ("0x".[ pick $tmp2 0 2])]) * 2)
:if ($length != [:len $tmp2]) do={throw;}
:set ($curStruct->"pdu") (($curStruct->"pdu") , {{"pdu"=$tmp2;"name"=($m->"name");"mode"="sms"}})
:set ($curStruct->"index") (($curStruct->"index") , $i)
}} on-error={:set $tmp2 ("wrong answer to AT+CMGR=$i; simfill=".[:tostr $simFill]."\r\n"); throw;}}
}
# стираем
:if ([:len ($curStruct->"index")] > 0) do={
:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGD=1,1"]
:if (($tmp->"f")) do={
:foreach i in=($curStruct->"index") do={
:delay 2s
:set $tmp [$chat ($m->"type") ($m->"name") ("AT+CMGD=".[:tostr $i])]
:if (($tmp->"f")) do={:set $tmp2 "wrong answer in CMGD\r\n"; throw;}}}}
# возвращаем режим обратно
:if ($mode) do={:set $tmp [$chat ($m->"type") ($m->"name") "AT+CMGF=1"]}
:if (($tmp->"f")) do={:set $tmp2 "wrong answer to AT+CMGF=1\r\n"; throw;}
# добавляем извлечённые pdu в возврат функции
:if ([:len ($curStruct->"index")] > 0) do={
:set ($output->"arr") (($output->"arr") , ($curStruct->"pdu"))}
} on-error={
# сохраняем значение в переменную, т.к. tmp является указателем 
:local es ($tmp->"r")
# опрашиваем идентификаторы модема
:if (($m->"type") = "ppp-client") do={
:local man [$chat ($m->"type") ($m->"name") "AT+GMI"]
:if (($man->"f")) do={:set $man [$chat ($m->"type") ($m->"name") "AT+CGMI"]}
:if (($man->"f")) do={:set $man "no information"} else={:set $man ($man->"r")}
:local mod [$chat ($m->"type") ($m->"name") "AT+GMM"]
:if (($mod->"f")) do={:set $mod [$chat ($m->"type") ($m->"name") "AT+CGMM"]}
:if (($mod->"f")) do={:set $mod "no information"} else={:set $mod ($mod->"r")}
:local rev [$chat ($m->"type") ($m->"name") "AT+GMR"]
:if (($rev->"f")) do={:set $rev [$chat ($m->"type") ($m->"name") "AT+CGMR"]}
:if (($rev->"f")) do={:set $rev "no information"} else={:set $rev ($rev->"r")}
:set $m ($m , {"manufacturer"=$man;"model"=$mod;"revision"=$rev})
}
:set ($output->"errorStr") (($output->"errorStr")."Modem: ".[:tostr $m]."\r\nError: ".$tmp2."Returned:\r\n$es\r\n")}
}
:return $output
}

Если не работает, то пришлите снова отладку на почту, после запуска скрипта.


Ответить