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

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

Проверил новый скрипт. Часть SMS прочиталась, часть PDU, которые не распарсились, отправились на почту автора.
Сегодня-завтра могу еще какую-нибудь проверку сделать.


EagleNN
Сообщения: 13
Зарегистрирован: 09 авг 2017, 19:45

В целом работает, но периодически валятся ошибки:

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

Modem: manufacturer="MikroTik";model="R11e-LTE6";name=lte1;revision=R11e-LTE6_V020;type=lte
Error: wrong answer to AT+CMGF
Returned:
+CSQ: 11,99
+CMGF: 0
+CESQ: 99,99,31,37,255,255
*CESQ: 99,99,31,37,255,255,0
OK
+CGREG: 1,"d7d3","01c4a32c",6,1
+CREG: 1,"d7d3","01c4a32c",6
$CREG: 1,"d7d3","01c4a32c",6,"051"

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

Modem: manufacturer="MikroTik";model="R11e-LTE6";name=lte1;revision=R11e-LTE6_V020;type=lte
Error: wrong answer to AT+CMGF
Returned:
+CMGF: 0
+CSQ: 11,99
+CESQ: 99,99,30,31,255,255
*CESQ: 99,99,30,31,255,255,0
OK
+CSQ: 11,99
+CESQ: 99,99,31,30,255,255
*CESQ: 99,99,31,30,255,255,0
+CSQ: 11,99
+CESQ: 99,99,30,29,255,255
*CESQ: 99,99,30,29,255,255,0


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

плохо что нет нормальной pdf по командам модема mikrotik. то что лежат на luat не предлагать, в них форматирование не определено точно. Беру выдержку от своего модема на at+cmgf:

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

<CR><LF>+CMGF: <mode><CR><LF><CR><LF>OK<CR><LF>
вроде как "OK" может быть оторвано от команды.
А в вызове cmgl не может:

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

[<CR><LF>+CMGL:
<index>,<stat>,[<reserved>],<length><CR><LF><pdu>[<CR><LF>+CMGL:
<index>,<stat>,[<reserved>],<length><CR><LF><pdu>[...]]<CR><LF>]<CR><LF>OK<
CR><LF>
Надеюсь это так, иначе скрипт развалится.
Закоментировал проверку "OK" в cmgf и поправил регулярку

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

:global extractSmsModem do={
# Функция принимает один аргумент со значениями “read” или “clear”.
# При “read” возвращать должна один из трёх вариантов:
# 1 - Строку “NO SMS” в случаи отсутствия sms
# 2 - Строку с текстом ошибки при сбоях в выполнении функции
# 3 - Массив из строк PDU
# При “clear” должно вернутся булево значение
# true - при удачном стирании sms из памяти
# false - если стереть sms не удалось


: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={
: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 [:toarray ""]
:local errorString
:local flagErrorExtract false
:local nosms false
:local clearSms true
:global storageMessageIndex
:if ($action = "read") do={:set $storageMessageIndex [:toarray ""]}

# опрашиваем все модемы по очереди
:foreach m in=$nameFind do={
:local tmp
:local tmp2
:local stStart
:local stEnd
:local mode
do {
# проверяем режим
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGF\?" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGF\?" as-value]->"output")}
:set $stStart [:find $tmp "+CMGF"]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
#:set $tmp2 [:pick $tmp ($stEnd + 2) ($stEnd + 4)]
#:if ($tmp2 != "OK") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $tmp2 [:pick $tmp ($stStart + 7)]
:if ($tmp2 = "0") do={:set $mode false} else={:set $mode true}
:if ($mode) do={
:if (($m->"type") = "lte") do={/interface lte at-chat ($m->"name") input="AT+CMGF=0"}
:if (($m->"type") = "ppp-client") do={/interface ppp-client at-chat ($m->"name") input="AT+CMGF=0"}}
# читаем
:if ($action = "read") do={

# CMGL read sms
# 0 Received unread messages
# 1 Received read messages
# 2 Stored unsent messages
# 3 Stored sent messages
# 4 All messages
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGL=4" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGL=4" as-value]->"output")}
:local flagend true
:local curStruct {"pdu"=[:toarray ""];"index"=[:toarray ""]}
:set $stStart [:find $tmp "+CMGL"]
:if ([:typeof $stStart] != "num") do={:if ($tmp~"(^|\n)OK(\$|\r)" = true) do={:set $flagend false; set $nosms true} else={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}}
:set $stStart
:if ($flagend) do={[:parse ":global storageMessageIndex; :set \$storageMessageIndex (\$storageMessageIndex , {$($m->"name")=[:toarray \"\"]})"]}
:while ($flagend) do={
:set $stStart [:find $tmp "+CMGL" $stStart]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick $tmp $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)
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick $tmp $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") , $tmp2)
:set ($curStruct->"index") (($curStruct->"index") , $index)
:if ([:pick $tmp ($stEnd + 2) ($stEnd + 4)] = "OK") do={:set $flagend false}
}
}
:set ($storageMessageIndex->($m->"name")) (($storageMessageIndex->($m->"name")) , ($curStruct->"index"))
:set $output ($output , ($curStruct->"pdu"))
}

# стираем
:if ($action = "clear") do={
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGD=1,1" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGD=1,1" as-value]->"output")}
:if ($tmp~"(^|\n)OK(\$|\r)" != true) do={
:foreach i in=($storageMessageIndex->($m->"name")) do={
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGD=$i" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGD=$i" as-value]->"output")}
:if ($tmp~"(^|\n)OK(\$|\r)" != true) do={:set $clearSms false}
}
}
}
} on-error={:set $flagErrorExtract true; :log info $m; :local na $m; :set $errorString ($errorString."Modem: ".[:tostr $m]."\r\nError: ".$tmp2."Returned:\r\n".$tmp."\r\n")}
:if ($mode) do={
:if (($m->"type") = "lte") do={/interface lte at-chat ($m->"name") input="AT+CMGF=1"}
:if (($m->"type") = "ppp-client") do={/interface ppp-client at-chat ($m->"name") input="AT+CMGF=1"}}
}
:if ($flagErrorExtract) do={
:set $storageMessageIndex
:if ([:len $output] > 0) do={:set $output ($errorString."Extracted from other modems:\r\n".[:tostr $output])
} else={:set $output $errorString}}
:if ($action = "clear") do={:set $storageMessageIndex
:if (!$clearSms) do={:set $output false} else={:set $output true}}
:if ($nosms and ([:len $output] = 0)) do={:set $output "NO SMS"; set $storageMessageIndex}
:return $output
}
В любом случаи модемы huawei себя так не ведут и отрабатывают всегда ожидаемо на заданные команды. Честно говоря после такого связываться с модемами mikrotik нет ни какого желания.


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

пересмотрел:

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

[<CR><LF>+CMGL:
<index>,<stat>,[<reserved>],<length><CR><LF><pdu>[<CR><LF>+CMGL:
<index>,<stat>,[<reserved>],<length><CR><LF><pdu>[...]]<CR><LF>]<CR><LF>OK<
CR><LF>
тоже может быть оторвано, :-(


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

Ещё раз с учётом, что OK может быть оторвано

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

:global extractSmsModem do={
# Функция принимает один аргумент со значениями “read” или “clear”.
# При “read” возвращать должна один из трёх вариантов:
# 1 - Строку “NO SMS” в случаи отсутствия sms
# 2 - Строку с текстом ошибки при сбоях в выполнении функции
# 3 - Массив из строк PDU
# При “clear” должно вернутся булево значение
# true - при удачном стирании sms из памяти
# false - если стереть sms не удалось


: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={
: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 [:toarray ""]
:local errorString
:local flagErrorExtract false
:local nosms false
:local clearSms true
:global storageMessageIndex
:if ($action = "read") do={:set $storageMessageIndex [:toarray ""]}

# опрашиваем все модемы по очереди
:foreach m in=$nameFind do={
:local tmp
:local tmp2
:local stStart
:local stEnd
:local mode
do {
# проверяем режим
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGF\?" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGF\?" as-value]->"output")}
:set $stStart [:find $tmp "+CMGF"]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $tmp2 [:pick $tmp $stEnd [:len $tmp]]
:if ($tmp2~"(^|\n)OK(\$|\r)" != true) do={:set $tmp2 "wrong answer to AT+CMGF\r\n"; throw;}
:set $tmp2 [:pick $tmp ($stStart + 7)]
:if ($tmp2 = "0") do={:set $mode false} else={:set $mode true}
:if ($mode) do={
:if (($m->"type") = "lte") do={/interface lte at-chat ($m->"name") input="AT+CMGF=0"}
:if (($m->"type") = "ppp-client") do={/interface ppp-client at-chat ($m->"name") input="AT+CMGF=0"}}
# читаем
:if ($action = "read") do={

# CMGL read sms
# 0 Received unread messages
# 1 Received read messages
# 2 Stored unsent messages
# 3 Stored sent messages
# 4 All messages
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGL=4" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGL=4" as-value]->"output")}
:local flagend true
:local curStruct {"pdu"=[:toarray ""];"index"=[:toarray ""]}
:set $stStart [:find $tmp "+CMGL"]
:if ([:typeof $stStart] != "num") do={:if ($tmp~"(^|\n)OK(\$|\r)" = true) do={:set $flagend false; set $nosms true} else={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}}
:set $stStart
:if ($flagend) do={[:parse ":global storageMessageIndex; :set \$storageMessageIndex (\$storageMessageIndex , {$($m->"name")=[:toarray \"\"]})"]}
:while ($flagend) do={
:set $stStart [:find $tmp "+CMGL" $stStart]
:if ([:typeof $stStart] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick $tmp $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)
:set $stEnd [:find $tmp "\r\n" $stStart]
:if ([:typeof $stEnd] != "num") do={:set $tmp2 "wrong answer to AT+CMGL\r\n"; throw;}
:set $tmp2 [:pick $tmp $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") , $tmp2)
:set ($curStruct->"index") (($curStruct->"index") , $index)
}
:set $tmp2 [:pick $tmp $stEnd [:len $tmp]]
:if (($tmp2~"\\+CMGL" != true) and ($tmp2~"(^|\n)OK(\$|\r)" = true)) do={:set $flagend false}
}
:set ($storageMessageIndex->($m->"name")) (($storageMessageIndex->($m->"name")) , ($curStruct->"index"))
:set $output ($output , ($curStruct->"pdu"))
}

# стираем
:if ($action = "clear") do={
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGD=1,1" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGD=1,1" as-value]->"output")}
:if ($tmp~"(^|\n)OK(\$|\r)" != true) do={
:foreach i in=($storageMessageIndex->($m->"name")) do={
:if (($m->"type") = "lte") do={:set $tmp ([/interface lte at-chat ($m->"name") input="AT+CMGD=$i" wait=yes as-value]->"output")}
:if (($m->"type") = "ppp-client") do={:set $tmp ([/interface ppp-client at-chat ($m->"name") input="AT+CMGD=$i" as-value]->"output")}
:if ($tmp~"(^|\n)OK(\$|\r)" != true) do={:set $clearSms false}
}
}
}
} on-error={:set $flagErrorExtract true; :local na $m; :set $errorString ($errorString."Modem: ".[:tostr $m]."\r\nError: ".$tmp2."Returned:\r\n".$tmp."\r\n")}
:if ($mode) do={
:if (($m->"type") = "lte") do={/interface lte at-chat ($m->"name") input="AT+CMGF=1"}
:if (($m->"type") = "ppp-client") do={/interface ppp-client at-chat ($m->"name") input="AT+CMGF=1"}}
}
:if ($flagErrorExtract) do={
:set $storageMessageIndex
:if ([:len $output] > 0) do={:set $output ($errorString."Extracted from other modems:\r\n".[:tostr $output])
} else={:set $output $errorString}}
:if ($action = "clear") do={:set $storageMessageIndex
:if (!$clearSms) do={:set $output false} else={:set $output true}}
:if ($nosms and ([:len $output] = 0)) do={:set $output "NO SMS"; set $storageMessageIndex}
:return $output
}


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

В первом сообщении обновлены скрипты
/system script add name="PDUtoEMAIL"
/system script add name="functionPDU"
/system script add name="functionMTI"

Добавлена поддержка sms которые содержат более одного заголовка, проверяйте и обязательно отписывайтесь.
В functionPDU временно введено исключение которое приводило к зависанию скрипта, когда файл для сохранения превышает 4КБ. (сейчас оно просто не сохраняется)


snowleo244
Сообщения: 10
Зарегистрирован: 29 дек 2019, 16:26

Здравствуйте! Попробовал скрип из первого сообщения на связке 951G-2HnD + E367.
1. В модеме может быть включено эхо, и соответственно парсинг не будет работать. Его нужно отключить: 2. При активном соединении в порт будут сыпаться отладочные сообщения, что тоже будет мешать парсингу. Их вывод тоже нужно отключить:

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

AT^CURC=0
При сбросе модема команды придется повторять (хотя наверное можно записать настройку в энергонезависимую память модема)

3. Перед выводом ответа на команду у меня присутствуют символы <CR><LF>, соответственно пришлось переписать:
c

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

:if ([:pick $tmp 0 5] = "+CMGF") do={:set $tmp [:tonum [:pick $tmp 7]]} else={:set $content "function extractSmsModem; wrong answer to CMGF?"; throw;}
на

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

:if ([:pick $tmp 2 7] = "+CMGF") do={:set $tmp [:tonum [:pick $tmp 9]]} else={:set $content "function extractSmsModem; wrong answer to CMGF?"; throw;}
и с

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

:if ($tmp = "OK") do={:set $content "NO SMS"; throw;}
:if ([:pick $tmp 0 5] != "+CMGL") do={:set $content "function extractSmsModem; wrong answer to CMGL"; throw;
на

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

:if ([:pick $tmp 2 4] = "OK") do={:set $content "NO SMS"; throw;}
:if ([:pick $tmp 2 7] != "+CMGL") do={:set $content "function extractSmsModem; wrong answer to CMGL"; throw;
4. Теперь скрип останавливается на:

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

function extractSmsModem; wrong length in CMGL
Если смотреть в SMS -> Inbox, то видно что одно СМС из двух частей и они полные.
Однако по команде

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

/interface ppp-client at-chat ppp-out1 input="AT+CMGL=4"
получается обрезанное второе сообщение:

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

  output: +CMGL: 0,1,,157 7919712690000F16007D0D92735080008028081323285218C050003D70201041704340440043004320441044204320443043904420435002E0020041204300448002004310430043B0430043D0441003A0020003700300020044004430431002E002C0020043E0441044204300442043E043A0020043C0438043D04430442002004320020043F0430043A04350442043500200441043E0441044204300432043B044F0435 +CMGL: 1,1,,157 07919712690000F16407D0D92735080008028081323285218C050003D702020442002000300020043C0438043D002E00200414043E0020043E043A043E043D04470430043D
Хотя если зайти в терминал (/system serial-terminal usb1 channel=3) и вручную ввести AT+CMGL=4 видно что все прекрасно считывается полностью:

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

[Ctrl-A is the prefix key]



+CMGL: 0,1,,157
07919712690000F16007D0D92735080008028081323285218C050003D70201041704340440043004320441044204320443043904420435002E0020041204300448002004310430043B0430043D0441003A0020003700300020044004430431002E002C0020043E04410442
04300442043E043A0020043C0438043D04430442002004320020043F0430043A04350442043500200441043E0441044204300432043B044F0435
+CMGL: 1,1,,157
07919712690000F16407D0D92735080008028081323285218C050003D702020442002000300020043C0438043D002E00200414043E0020043E043A043E043D04470430043D0438044F0020043F0430043A0435044204300020043E044104420430043B043E0441044C0020
0032003900200434043D04350439002004380020003100300020044704300441043E0432002E000A041204300448043000200059006F00740061

OK


Куда копать?


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

Wait=yes


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

Ааа, Семён Семеныч. В ppp-client нет wait. Тогда только по очереди читать каждое.


EagleNN
Сообщения: 13
Зарегистрирован: 09 авг 2017, 19:45

Уважаемый автор,
Я скидывал в личку набор ошибок которые возвращает модем микротика.
Надо дорабатывать скрипты. Есть ли какой-то прогноз, когда можно ожидать доработку?


Ответить