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

Здесь выкладываем скрипты
pepelxl
Сообщения: 48
Зарегистрирован: 23 июл 2013, 18:47

29 июн 2020, 23:52

Здравствуйте Sertik, У вас скорее всего тот-же случай, что и у людей выше.
Вам надо попробовать добавить в вызовы внутри функции extractSmsModem аргумент wait.
Вот функция

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

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

# название интерфейса
:local nameIf lte1
:local mode
:local tmp
:local content [:toarray ""]
:if ($action = "read") do={
do {
# CMGF -  0 PDU mode (default value); 1 Text mode
:set $tmp [/interface lte at-chat $nameIf input="AT+CMGF\?" as-value wait=yes]
:set $tmp ($tmp->"output")
:if ([:pick $tmp 0 5] = "+CMGF") do={:set $tmp [:tonum [:pick $tmp 7]]} else={:set $content "function extractSmsModem; wrong answer to CMGF?"; throw;}
:if ($tmp = 0) do={:set $mode false} else={:set $mode true}
:if ($mode) do={/interface lte at-chat $nameIf input="AT+CMGF=0"}
# CMGL read sms
# 0 Received unread messages
# 1 Received read messages
# 2 Stored unsent messages
# 3 Stored sent messages
# 4 All messages
:set $tmp [/interface lte at-chat $nameIf input="AT+CMGL=4" as-value wait=yes]
:set $tmp ($tmp->"output")
: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;
} else={ 
:local flagEnd true
:local lineEnd
:local lineStart
:local line ""
:while ($flagEnd) do={
#ищем начало SMS
:set $lineStart [:find $tmp "+CMGL:" $lineStart]
# Проверяем что поиск завершился успешно
:if ([ typeof $lineStart ]="num") do={
# Ищем конец SMS
:set $lineEnd [:find $tmp "+CMGL:" $lineStart]
:if ([ typeof $lineEnd ] = "nil") do={
:set $lineEnd [:find $tmp "OK" $lineStart]}
# вынимаем сообщение
:set $line [:pick $tmp $lineStart ($lineEnd - 1)]
# вынимаем направление sms
:local stat [:tonum [:pick $line ([:find $line ","] + 1) [:find $line ",,"]]]
# поскольку флаги MTI в PDU для исходящих и входящих сообщений имеют разное значение, извлекать надо обязательно  ВХОДЯЩИЕ сообщения
# since the flags MTI in the PDU for outgoing and incoming messages have different meanings, it is necessary to extract INCOMING messages
:if (($stat = 0) or ($stat = 1)) do={
:local length [:tonum [ pick $line ([:find $line ",,"] + 2) ([:find $line "\n"] - 1)]]
:set $length (($length + 1 + [:tonum ("0x".[ pick $line ([:find $line "\n"] + 1) ([:find $line "\n"] + 3)])]) * 2)
:local pdu [:pick $line ([:find $line "\n"] + 1) ([:len $line] - 1)]
:if ($length != [:len $pdu]) do={:set $content "function extractSmsModem; wrong length in CMGL"; throw;}
:set $content ($content , $pdu)
}} else={ :set $flagEnd false}}}
} on-error={}
:if ($mode) do={/interface lte at-chat $nameIf input="AT+CMGF=1"}
:return $content
}
# удаляем прочитанные сообщения
:if ($action = "clear") do={:set $tmp [/interface lte at-chat $nameIf input="at+cmgd=1,1" as-value wait=yes]}
:set $tmp ($tmp->"output")
:if ($tmp = "OK") do={:return true} else={:return false}
}
Также напишите для статистики модель и производителя модема из вызова в терминале

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

:put [/interface lte info 0 once as-value]


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

29 июн 2020, 23:57

2- Тут я вас не понял; вы всегда получаете текст ошибки или после добавления wait на почту всё-таки приходят не разобранные PDU?
Всё понял, вы мне прислали несколько разных сообщений. с разными косяками.
У вас одно из них имеет не верную длину, перепроверьте пожалуйста, что это не ошибка отправки мне.
А в последнем сообщении заголовок пользователя составной, не хотел я этим заниматься и собирался оставить на закуску и оставил засечки в скрипте для этого, но придётся сделать ради вас в ближайшее время.


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

30 июн 2020, 00:07

Вот ответ на lte info

manufacturer="MikroTik";model="R11e-LTE";revision="MikroTik_CP_2.160.000_v015"

Сам перечитал пост, да у меня такая же проблема как и у человека Выше. Сам исправлял функцию - ничего не вышло. Потом пришел Ваш ответ, вставил Ваш вариант - результат тот же в логе запись No clear SMS, но в массиве по дебагу в лог весь разбор вываливается - по всем четырем SMS, но на почту ничего не приходит. Хотя раньше приходила ошибка Error extracted и пусто. Потом пришло вот это:
4
array
07919761980614F8040B919701747907F300000260421165432104F4F29C0E;4
array
07919730071111F1040B919756143297F400000260423144832118BA719B0C9A5A41F3B13C0DA783E069F7B95DD7A7C7;4
array
07919761980614F8040B919701747907F300000260529183422118BA719B0C9A5A41F3B13C0DA783E069F7B95DD7A7C7;4
array
07919730071111F1040B919756143297F40008026092220551211E041F04200418041204150422002C0020042104150420041A041E04280410

функция extractSMS всё прочитала - где то ошибка в основном скрипте, который отправляет на почту.
Последний раз редактировалось Sertik 30 июн 2020, 09:07, всего редактировалось 2 раза.


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

30 июн 2020, 00:33

Вот ответ на lte info
выхлоп подчистите в вашем сообщении, бог его знает кто этим может воспользоватся в своих целях.
No clear SMS,
Смотрите основной скрипт, там три строки

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

:local flagSend [$extractSmsModem action="clear"]
:if ($flagSend != true) do={:set $flagSend [$extractSmsModem action="clear"]}
:if ($flagSend != true) do={:log warning "NO clear SMS"; $exitFunctionPDU; :error}

Вызывается функция extractSmsModem которая должна вернуть булево true
если нет то ни чего на почту не шлём и останавливаем скрипт
Сделано это для защиты флеши роутера.
Посмотрите, в функцию на вызов

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

[/interface lte at-chat $nameIf input="at+cmgd=1,1" as-value]
Возможно модемы MikroTik принимают другую команду для удаления прочитанных смс.
У вас должно хватить знаний что бы разобраться. Выложите сюда результат для остальных участников форума.


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

30 июн 2020, 01:32

Перекачайте два скрипта PDUtoEMAIL и functionMTI временно разблокировал поддержку объединения по 0х08
Примера с семибитным алфавитом нет, но должно работать.
Потом перепишу этот кусок заново для поддержки составных заголовков
P.S. в коде был допущен совсем детский косяк в блоке проверки возможностей. Аж стыдно.


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

30 июн 2020, 09:16

У вас должно хватить знаний что бы разобраться.
Спасибо за столь лестную оценку моих знаний.

Так и не понял, Вы исправили ошибки в Ваших скриптах ? Можно их просто перекачать и будет работать ? Приятно, что Вы так пишите скрипты, чтобы ещё каждому пользователю разбираться с ними нужно было ...

Кстати, неплохо бы переписать скрипт, учитывая что модемов в роутере может быть несколько. У меня их, например, два. Больше, конечно, совсем редкая ситуация, но скрипт должен быть универсальным, ведь у Вас знаний достаточно. Скрипт должен искать модемы, определять типы их интерфейсов (lte, ppp) и со всех считывать SMS, ну если разобраться с ppp не сможете, то хотя бы с несколькими LTE-модемами скрипт должен четко работать.
в коде был допущен совсем детский косяк в блоке проверки возможностей. Аж стыдно.
А вот это хорошо, значит что для Вас еще не все потеряно.


Чего не знаем то нагуглим
EagleNN
Сообщения: 7
Зарегистрирован: 09 авг 2017, 19:45

30 июн 2020, 09:26

pepelxl писал(а):
29 июн 2020, 22:31
EagleNN спасибо вам большое за отзыв.
Давайте по порядку.
На SIM картах Beeline не работает этот скрипт. Выдает ошибку.
1- оператор и сим карта никакого отношения не имеет к скрипту модему и так далее.
Оператор имеет значение, т.к. именно он формирует тело PDU, т.к. все SMS у меня чисто сервисные.
pepelxl писал(а):
29 июн 2020, 22:31
PDU считываются не каждый раз, но если добавить параметр wait приемлемо.
2- Тут я вас не понял; вы всегда получаете текст ошибки или после добавления wait на почту всё-таки приходят не разобранные PDU?
Без Wait в буфер считывается от 0 до 3-4 PDU из 10 в Inbox в ответ на команду "AT+CMGL=4"
pepelxl писал(а):
29 июн 2020, 22:31
но и прикладывать PDU вызвавшее проблему.
3- На самом деле это так и реализовано, КРОМЕ самой функции извлечения. То-есть как можно слать не разобранное PDU если нет гарантии что оно вообще получено скриптом. Как только правильный массив вернулся в основной скрипт и не смог разобраться то отправится ошибка и само PDU в котором произошла ошибка.
Как мне кажется лучше послать хоть что-то, чем просто ошибку.
pepelxl писал(а):
29 июн 2020, 22:31
ещё раз повторю, у меня нет возможности проверить на всех модемах. функция extractSmsModem на данном этапе требует настройки под свой модем. Более ни чего трогать не надо.
Модем у меня вот такой: https://mikrotik.com/product/lhg_lte6_kit
В принципе кроме wait никакой настройки не требуется.
pepelxl писал(а):
29 июн 2020, 22:31
В модеме должно быть входящее смс
Пришлите в личку ответ от следующих команд из терминала:
:put [/interface lte at-chat lte1 input="AT+CMGL=4" as-value wait=yes]
:put [/interface lte info 0 once as-value]
Сейчас в процессе переделка функции extractSmsModem под автоматический поиск модемов и применения настроек из списков, Но вот списки смогут сформироваться благодаря таким людям как вы. Мне катастрофически не хватает времени заняться этим в плотную.
Если в письме вы увидете ошибку It is supported only by concatenated code 0x00 и тело PDU то функция извлечения заработала как надо.
Вывод AT+CMGL=4 присылал ранее в личку (там 9 разных PDU)

По модему информацию смогу прислать через неделю-две, т.к. доступа к модему пока нет.


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

30 июн 2020, 17:58

На это [/interface lte at-chat $nameIf input="at+cmgd=1,1" as-value]

имеем:

output=+CMS ERROR: 304

После "перекачки" обновленных PDUtoEMAIL и functionMTI всё равно ничего не работает. В лог вываливается:

NO clear SMS

Так то.


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

01 июл 2020, 10:35

Без Wait в буфер считывается от 0 до 3-4 PDU из 10 в Inbox в ответ на команду "AT+CMGL=4"
Понял, учту
Как мне кажется лучше послать хоть что-то, чем просто ошибку.
соглашусь, надо будет сделать что-бы высылался весь принятый мусор + отладочная информация
Кстати, неплохо бы переписать скрипт, учитывая что модемов в роутере может быть несколько.
Здесь мы с вами думаем одинаково, загнать опрос модемов в цикл не проблема, однако статус о том в какой модем(sim) пришло сообщение обработать этим скриптом не получится на данном этапе.
Так и не понял, Вы исправили ошибки в Ваших скриптах
После "перекачки" обновленных PDUtoEMAIL и functionMTI всё равно ничего не работает.
Нет, ошибка была в обработчике исключений, если тело основного скрипта не переписывать под себя, то на эту ошибку наткнутся не возможно.
output=+CMS ERROR: 304
Ну вот и ответ, почему скрипт затыкается.
А вообще интересно девки пляшут, эта команда стандартная, и оговорена ещё в gsm7.05
304 - invalid PDU mode parameter
Надо поиграться с методами, дайте команды в терминале:

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

:put [/interface lte at-chat lte1 input="AT+CMGF\?" as-value wait=yes]
:put [/interface lte at-chat lte1 input="at+cmgd\?" as-value wait=yes]
:put [/interface lte at-chat lte1 input="at+cmgd=\?" as-value wait=yes]
:put [/interface lte at-chat lte1 input="at+cmgd=0,1" as-value wait=yes]
где lte1 имя вашего модема
если ни чего не помогает, то придётся убивать смс индивидуально в цикле командой

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

:put [/interface lte at-chat lte1 input="at+cmgd=X" as-value wait=yes]
где X номер ячейки


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

04 июл 2020, 23:35

Немного доработал скрипт extractSmsModem

содержимое extractSmsModem

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

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

# название интерфейса
:local nameIf lte1
:local mode
:local tmp
:local content [:toarray ""]
:if ($action = "read") do={
do {
# CMGF -  0 PDU mode (default value); 1 Text mode
:set $tmp [/interface lte at-chat $nameIf input="AT+CMGF\?" as-value wait=yes]
:set $tmp ($tmp->"output")
:if ([:pick $tmp 0 5] = "+CMGF") do={:set $tmp [:tonum [:pick $tmp 7]]} else={:set $content "function extractSmsModem; wrong answer to CMGF?"; throw;}
:if ($tmp = 0) do={:set $mode false} else={:set $mode true}
:if ($mode) do={/interface lte at-chat $nameIf input="AT+CMGF=0" wait=yes}
# CMGL read sms
# 0 Received unread messages
# 1 Received read messages
# 2 Stored unsent messages
# 3 Stored sent messages
# 4 All messages
:set $tmp [/interface lte at-chat $nameIf input="AT+CMGL=4" as-value wait=yes]
:set $tmp ($tmp->"output")
: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;
} else={ 
:local flagEnd true
:local lineEnd
:local isLineEnd
:local lineStart
:local line ""
:while ($flagEnd) do={
#ищем начало SMS
:set $lineStart [:find $tmp "+CMGL:" $lineStart]
# Проверяем что поиск завершился успешно
:if ([ typeof $lineStart ]="num") do={
# Ищем конец SMS
:set $lineEnd [:find $tmp "+CMGL:" $lineStart]
:if ([ typeof $lineEnd ] = "nil") do={
:set $lineEnd [:find $tmp "OK" $lineStart]}
# вынимаем сообщение
:set $line [:pick $tmp $lineStart ($lineEnd - 1)]
# вынимаем направление sms
:local stat [:tonum [:pick $line ([:find $line ","] + 1) [:find $line ",,"]]]
# поскольку флаги MTI в PDU для исходящих и входящих сообщений имеют разное значение, извлекать надо обязательно  ВХОДЯЩИЕ сообщения
# since the flags MTI in the PDU for outgoing and incoming messages have different meanings, it is necessary to extract INCOMING messages
:if (($stat = 0) or ($stat = 1)) do={
:local length [:tonum [ pick $line ([:find $line ",,"] + 2) ([:find $line "\n"] - 1)]]
:set $length (($length + 1 + [:tonum ("0x".[ pick $line ([:find $line "\n"] + 1) ([:find $line "\n"] + 3)])]) * 2)
:local pdu [:pick $line ([:find $line "\n"] + 1) ([:len $line] - 1)]
:set $isLineEnd [:find $pdu "\n"]
:if ( $isLineEnd  >= 0 ) do={
:log warning "Correct PDU length to $isLineEnd"
:set $pdu [:pick $pdu 0 ($isLineEnd - 1)]}
:if ($length != [:len $pdu]) do={:set $content "function extractSmsModem; wrong length in CMGL"; throw;}
:set $content ($content , $pdu)
}} else={ :set $flagEnd false}}}
} on-error={}
:if ($mode) do={/interface lte at-chat $nameIf input="AT+CMGF=1" wait=yes}
:return $content
}
# удаляем прочитанные сообщения
:if ($action = "clear") do={:set $tmp [/interface lte at-chat $nameIf input="at+cmgd=1,1" as-value wait=yes]}
:set $tmp ($tmp->"output")
:if ($tmp = "OK") do={:return true} else={:return false}
}
Теперь парсинг сообщений начинается, но выдает ошибки от 1 до 4-х раз на каждое SMS

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

error parse in functionMTI:
 Error parse, this script supports only one user header
И в конце "NO clear SMS"

Периодически на запуск скрипта приходят ошибки

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

function extractSmsModem; wrong answer to CMGL;


Ответить