Задача:
Такая же как в
предыдущей заметке о iRZ RUH2x , только с использованием новой серии оборудования, указанной в теме.
Само устроство - это роутер с процессором MIPS, mini-PCIE радио-модулем QUECTEL EC20 и прошивкой Openwrt 15.05.1 с набором различных скриптов от производителя.
Скорее всего радио-модуль, установленный в устройство может отличаться от того, что используется в моем случае.
[ RL01w ]
Quectel
EC20
Revision: EC20EQAR02A12E2G
Данная серия устройств уже может полноценно отдавать уровень GSM-сигнала и прочие нужные нам параметры по SNMP, т.е. фактически реализована поддержка скриптов в snmpd.
root@3gr0:~# opkg list-installed | grep snmp
irz-snmp-scripts - 1.0.0-1
libnetsnmp - 5.4.4-1
snmpd - 5.4.4-1
Этими скриптами я и постарался максимально воспользоваться для написания своих утилит, позволяющих единообразно собирать статистику работы совместно с устройствами серии iRZ RUH2x.
Для начала из /usr/libexec/snmp/irz-mobile-snmp.sh выбираем нужные функции, исключая код поиска ОID и помещаем в файл, который будем подключать в собственных скриптах.
1. /root/share/irz-functions.sh
# Functions
# iRZ SNMPd script functions ( /usr/libexec/snmp )
# PATH
PATH="$PATH:$HOME/bin"
# Get number of radio modules
mobileNumModule() {
echo $(cat /tmp/sysinfo/capabilities | grep BOARD_MODULES | tr '=' '\n' | tail -n1)
}
# Get number of active SIM-card
mobileCard () {
local device=$1
local SIM_SWITCH="$(cat /tmp/sysinfo/capabilities | grep SIM_SWITCH | tr '=' '\n' | tail -n1)"
[ "$SIM_SWITCH" = "n" ] && {
echo "$device"
} || {
x=$(ubus call sim_switch get)
json_load "$x" &> /dev/null
json_get_var result result
[ "$result" = "DISABLED" ] && {
echo "-1"
} || {
echo "$result"
}
}
}
# Check network registaration
mobileRegistration () {
local device=$1
local x=$(wait_registration /dev/ttyMODEM${device}_AUX 1 2>/dev/null)
[ ! -z "$x" ] && {
case "$x" in
'NOT REGISTERED') echo "0";;
HOME) echo "1";;
DENIED) echo "3";;
ROAMING) echo "5";;
*) echo "-1";;
esac
} || echo "-1"
}
# Get working mode
mobileTechnology() {
local device=$1
local x=$(_modem /dev/ttyMODEM${device}_AUX 'AT+COPS?' 10 '^\+COPS:' 2>/dev/null | tr ',' '\n' | tail -n1)
[ ! -z "$x" ] && {
case "$x" in
0|1) echo "edge";;
2) echo "umts";;
7) echo "lte";;
*) echo "not-connected";;
esac
} || echo "not-connected"
}
# Get signal parameters
mobileSignalStrength() {
local device=$1
local CSQ=$(_modem /dev/ttyMODEM${device}_AUX at+csq 1 2>/dev/null | tr ' ,' '\n' | head -n2 | tail -n1)
sStrength=$(expr -113 + $CSQ * 2 2>/dev/null)
[ ! -z "$sStrength" ] && echo "$sStrength" || echo "0"
}
mobileCSQ () {
local device=$1
local csq=$(get_csq /dev/ttyMODEM${device}_AUX)
echo "integer"
[ ! -z "$csq" ] && {
echo "$csq"
} || echo "-1"
}
# Get network operator name / MNC
get_PLMN() {
local x=$(ubus call network.interface.$1 status 2>/dev/null)
json_load "$x" &>/dev/null || return 1
if json_select 'data' &> /dev/null; then
if json_select 'info' &> /dev/null; then
json_get_var network network
[ ! -z "$network" ] && {
echo "$network"
}
json_select ..
fi
json_select ..
fi
}
mobilePLMN() {
local device=$1
ifaces=$(ubus call uci get "{'config': 'network', 'type': 'interface', 'match': {'device_number': '$device'}}")
json_load "$ifaces" &> /dev/null
json_select values &> /dev/null
json_get_keys interfaces
for ifname in $interfaces; do
json_select "$ifname"
json_get_var proto proto
if [ "$proto" = "3g" ]; then
r=$(get_PLMN "$ifname")
[ ! -z "$r" ] && {
echo "$r"
return 0
}
fi
json_select ..
done
echo "none"
}
get_operator () {
local x=$(ubus call network.interface.$1 status 2>/dev/null)
json_load "$x" &>/dev/null || return 1
if json_select 'data' &> /dev/null; then
if json_select 'info' &> /dev/null; then
json_get_var operator operator
[ ! -z "$operator" ] && {
echo "$operator"
}
fi
json_select ..
fi
json_select ..
}
mobileOperator () {
local device=$1
ifaces=$(ubus call uci get "{'config': 'network', 'type': 'interface', 'match': {'device_number': '$device'}}")
json_load "$ifaces" &> /dev/null
json_select values &> /dev/null
json_get_keys interfaces
for ifname in $interfaces; do
json_select "$ifname"
json_get_var proto proto
if [ "$proto" = "3g" ]; then
r=$(get_operator "$ifname")
[ ! -z "$r" ] && {
echo "$r"
return 0
}
fi
json_select ..
done
echo "none"
}
# End
Далее, в системе отсутсвует единая утилита для работы с sms (она используется при опеределении номера SIM-карты) - пришлось релизовать похожий функционал в виде скрипта.
2. /root/bin/sms
#!/bin/sh -f
# SMS tools (send/read/list)
# Include
. /lib/irz/gsm_utils.sh
. $HOME/share/irz-functions.sh
# Static variables
VERBOSE=0
# Functions
printUsage () {
echo "Usage:"
echo "`basename $0` { -v | -l | -r | -s
}"
echo " -v - verbose output;"
echo " -l - list messages;"
echo " -r - read message;"
echo " -s - send message."
}
# Send sms using system utility
smsSend () {
if [ $# -ge 2 ]; then
PHONE_NUM=$1
MSG_TEXT=$2
if [ -x `which send-sms` ]; then
echo "${PHONE_NUM}" | grep -E "^[0-9]{11}$" > /dev/null 2>&1
if [ $? -eq 0 ]; then
registred=$(mobileRegistration ${MODNUM})
if [ ${registred} -eq 1 ] || [ ${registred} -eq 5 ] ; then
send-sms $1 "$2" > /dev/null 2>&1
if [ $? -eq 0 ]; then
[ ${VERBOSE} -eq 1 ] && echo "[INF]: Message sent to ${PHONE_NUM} successfullly"
logger -t user-sms -p daemon.info "Message sent to ${PHONE_NUM} successfullly"
return 0
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: Message sending to ${PHONE_NUM} is failed"
logger -t user-sms -p daemon.error "Message sending to ${PHONE_NUM} is failed"
return 1
fi
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: SIM-card is not registred in operator's network"
logger -t user-sms -p daemon.error "SIM-card is not registred in operator's network"
return 1
fi
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: Phone number is not valid"
logger -t user-sms -p daemon.error "Phone number is not valid"
return 1
fi
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: Executable not found (send-sms)"
logger -t user-sms -p daemon.error "Executable not found (send-sms)"
return 1
fi
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: You should supply phone number & message text"
logger -t user-sms -p daemon.error "You should supply phone number & message text"
return 1
fi
}
# List sms using AT-commands
smsList () {
return_status=0
_modem /dev/ttyMODEM${MODNUM}_AUX 'AT+CMGL=4' 2 '+CMGL:' > /tmp/irz-sms.$$.out
exit_status=$?
case ${exit_status} in
0) cat /tmp/irz-sms.$$.out | awk '{ print $2 }' | awk -F "," '{ print $1 }' ;;
1) [ ${VERBOSE} -eq 1 ] && echo "[WRN]: There is no SMS in active message storage"
return_status=1 ;;
*) [ ${VERBOSE} -eq 1 ] && echo "[ERR]: SMS list reading is failed"
logger -t user-sms -p daemon.error "SMS list reading is failed"
return_status=1 ;;
esac
rm -rf /tmp/irz-sms.$$.out
return ${return_status}
}
# Read sms using AT-commands
smsRead () {
MSG_IDX=$1
_modem /dev/ttyMODEM${MODNUM}_AUX "AT+CMGR=${MSG_IDX}" 5 '+CMGR:' > /dev/null 2>&1
exit_status=$?
case ${exit_status} in
0) _modem /dev/ttyMODEM${MODNUM}_AUX "AT+CMGR=${MSG_IDX}" 5 | grep -v '+CMGR:'
return 0 ;;
1) [ ${VERBOSE} -eq 1 ] && echo "[ERR]: There is no SMS with number ${MSG_IDX}"
logger -t user-sms -p daemon.error "There is no SMS with number ${MSG_IDX}"
return 1 ;;
*) [ ${VERBOSE} -eq 1 ] && echo "[ERR]: Reading SMS with number ${MSG_IDX} is failed"
logger -t user-sms -p daemon.error "SMS list reading is failed"
retrun 1 ;;
esac
}
# Dynamic variables
modnum=$(mobileNumModule)
if [ ${modnum} -ne 0 ];
then
[ ${modnum} -ge 2 ] && [ ${VERBOSE} -eq 1 ] && echo "[WRN]: Number of radio modules is greater than one. Assuming first one is active"
# Ugly hack
MODNUM=1
else
[ ${VERBOSE} -eq 1 ] && echo "[ERR]: There's no radio modules on board";
logger -t user-sms -p daemon.error "There's no radio modules on board"
exit 1
fi
# Main
# Reading command-line arguments
while getopts :r:s:lv optname
do
case $optname in
l) smsList
exit $? ;;
r) smsRead ${OPTARG}
exit $? ;;
s) phone_num="${OPTARG}"
eval "msg_text=\${$OPTIND}"
move=0; nxt_or_end=0;
while [ ${nxt_or_end} -ne 1 ];
do
move=`expr ${move} + 1`
position=`expr $OPTIND + ${move}`
eval "arg=\${$position}"
if [ ${#arg} -eq 0 -o "${arg}" = "-r" -o "${arg}" = "-l" -o "${arg}" = "-v" ]; then
nxt_or_end=1
else
msg_text="${msg_text} ${arg}"
fi
done
smsSend ${phone_num} "${msg_text}"
exit $? ;;
v) VERBOSE=1 ;;
?) printUsage
exit 1 ;;
esac
done
shift $((OPTIND - 1))
# Check if script invoked with no command-line args.
[ $# -eq "0" ] && printUsage
# End
И в заключение необходимы немного модифицированные по сравнению с серией iRZ RUH2x скрипты опеределения уровня сигнала и номера SIM-карты, запускаемые по cron:
3. /root/bin/irz-signal
#!/bin/sh -f
# Signal info in SNMP-description (cron script)
# Include
. /usr/share/libubox/jshn.sh
. /lib/irz/gsm_utils.sh
. $HOME/share/irz-functions.sh
# Dynamic variables
# Unitname
uci get system.@system[0].unitname > /dev/null 2>&1
if [ $? -eq 0 ] ; then
HOST=$(uci get system.@system[0].unitname)
else
logger -t user-signal -p daemon.error "Can't read unitname - uci get query failed";
exit -1
fi
# Device type
if [ -r /tmp/sysinfo/model ]; then
MODEL=$(cat /tmp/sysinfo/model)
else
logger -t user-signal -p daemon.error "Can't find out device model - file is missing (/tmp/sysinfo/model)";
exit -1
fi
# Main
# Check number of radio modules
modnum=$(mobileNumModule)
if [ ${modnum} -ne 0 ];
then
[ ${modnum} -ge 2 ] && logger -t user-signal -p daemon.warn "Number of radio modules is greater than one. Assuming first one is active"
# Ugly hack
MODNUM=1
# Check network registration
registred=$(mobileRegistration ${MODNUM})
if [ ${registred} -eq 1 ] || [ ${registred} -eq 5 ] ; then
time_stamp=$(date +"%d.%m.%y-%H:%M:%S")
# Get signal & working mode of radio module
csq=$(echo "$(mobileSignalStrength ${MODNUM})dbm")
mode=$(mobileTechnology ${MODNUM})
# Mobile operator
mop=$(mobileOperator ${MODNUM} | awk '{ print $1 }')
# Phone number
if [ -r /tmp/phonenumber ]; then
number=$(cat /tmp/phonenumber);
logger -t user-signal -p daemon.info "$HOST,$MODEL,$mop,$csq,$mode,$number,$time_stamp"
DESC_STRING=$(echo -n "$HOST,$MODEL,$mop,$csq,$mode,$number,$time_stamp" | tr '[A-Z]' '[a-z]')
else
logger -t user-signal -p daemon.info "$HOST,$MODEL,$mop,$csq,$mode,$time_stamp"
DESC_STRING=$(echo -n "$HOST,$MODEL,$mop,$csq,$mode,$time_stamp" | tr '[A-Z]' '[a-z]')
fi
else
time_stamp=$(date +"%d.%m.%y-%H:%M:%S")
logger -t user-signal -p daemon.info "$HOST,$MODEL,not-registred,$time_stamp"
DESC_STRING=$(echo -n "$HOST,$MODEL,not-registred,$time_stamp" | tr '[A-Z]' '[a-z]')
fi
else
logger -t user-signal -p daemon.err "There's no radio modules on board";
exit -1
fi
# Update SNMPD description
uci set snmpd.@system[0].sysDescr="${DESC_STRING}" && uci commit snmpd
[ $? -eq 0 ] && /etc/init.d/snmpd reload
# End
4. /root/bin/irz-getnumber
#!/bin/ash -
# Get phone number via USSD
# Include
. /usr/share/libubox/jshn.sh
. /lib/irz/gsm_utils.sh
. $HOME/share/irz-functions.sh
# Dynamic variablels
modnum=$(mobileNumModule)
if [ ${modnum} -ne 0 ];
then
[ ${modnum} -ge 2 ] && logger -t user-signal -p daemon.warn "Number of radio modules is greater than one. Assuming first one is active"
# Ugly hack
MODNUM=1
DEV="/dev/ttyMODEM${MODNUM}_AUX"
fi
# Operator number
OPMNC=$(mobilePLMN ${MODNUM})
if [ $? -ne 0 ]; then
logger -t user-getnumber -p daemon.err "Can't find mobile network code";
exit -1
fi
# Functions
pdunums2string () {
number=""
i=0
# Debug:
# echo "pdu: $1"
while [ $i -lt ${#1} ];
do
symbol=`echo -en "\x"${1:$i:2}`
if [ -n "${symbol}" ]; then
echo ${symbol} | grep -E "^[0-9]$" > /dev/null 2>&1
if [ $? -eq 0 -a ${#number} -lt 11 ]; then
number="${number}${symbol}"
# Debug:
# echo "symbol: ${symbol} / number: ${number}"
else
[ ${#number} -ge 10 ] || number=''
fi
fi
let "i += 2"
done
if [ ${#number} -lt 10 ]; then
logger -t user-getnumber -p daemon.warn "USSD-reply or SMS doesn't contain phone number";
exit 0 ;
else
[ ${#number} -eq 11 ] && number=${number:1}
logger -t user-getnumber -p daemon.info "Phone number is detected (${number})";
echo -n "${number}" > /tmp/phonenumber
exit 0 ;
fi
}
getpdufromsms () {
USSD_QRY=$1
USSD_WAIT=15
PDU_READ=0
RETRY_NUM=4
ussd_try=1
talk -t ${DEV} -c +CMGD=0,4 &&
while [ ${PDU_READ} -ne 1 -a $ussd_try -le ${RETRY_NUM} ]
do
ussd ${DEV} ${USSD_QRY} > /dev/null 2>&1
for sms_try in `seq ${RETRY_NUM}`; do
# SMS number may be starting from 0 or 1
sms_num=`sms -l | head -n 1 | tr -d " \n"`
sms -r ${sms_num} > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo -n 'PDU=' && sms -r ${sms_num}
PDU_READ=1
break
else
sleep ${USSD_WAIT}
fi
done
ussd_try=`expr $ussd_try + 1`
done
}
getpdufromussd () {
USSD_QRY=$1
USSD_WAIT=15
PDU_READ=0
RETRY_NUM=4
ussd_try=1
CHAT_FILE="/tmp/irz-getnumber.$$.chat"
echo "ABORT ERROR" > ${CHAT_FILE}
echo "ABORT BUSY" >> ${CHAT_FILE}
echo "REPORT CUSD:" >> ${CHAT_FILE}
echo "'' AT\+CUSD=1,${USSD_QRY},15" >> ${CHAT_FILE}
echo "TIMEOUT ${USSD_WAIT}" >> ${CHAT_FILE}
echo "CUSD:" >> ${CHAT_FILE}
TMP_FILE="/tmp/irz-getnumber.$$.out"
opname=$2
while [ ${PDU_READ} -ne 1 -a $ussd_try -le ${RETRY_NUM} ]
do
chat -v -r ${TMP_FILE} -t 5 -f ${CHAT_FILE} > ${DEV} < ${DEV}
exsts=$?
if [ ${exsts} -eq 0 ]; then
PDU_READ=1
cat ${TMP_FILE} | grep 'CUSD:' | awk -F"," '{ print $2 }' | tr -d "\""
break
else
logger -t user-getnumber -p daemon.err "Chat script to ${DEV} failed with err-code ${exsts} - attempt ${ussd_try}/${RETRY_NUM}";
fi
ussd_try=`expr $ussd_try + 1`
sleep ${USSD_WAIT}
done
[ ${PDU_READ} -ne 1 ] && logger -t user-getnumber -p daemon.err "USSD sending or reply receiving failed due previous errors ($opname)";
rm -rf ${TMP_FILE} ${CHAT_FILE}
}
# Main
# Operator
case $OPMNC in
25099) OPNAME="beeline";
output=$( getpdufromsms "*110*10#" );
echo ${output} | grep "PDU" > /dev/null 2>&1 ;
if [ $? -eq 0 ]; then
pdu=`echo $output | awk -F "=" '{ print $2 }'` ;
pdunums2string "${pdu}";
else
logger -t user-getnumber -p daemon.err "USSD has been sent, but no SMS recieved ($OPNAME)";
exit 0 ;
fi ;;
25002) OPNAME="megafon";
pdu=$( getpdufromussd "*205#" "${OPNAME}" );
[ ${#pdu} -ne 0 ] && pdunums2string "${pdu}";;
25001) OPNAME="mts-rus";
output=$( getpdufromsms "*111*0887#" );
echo ${output} | grep "PDU" > /dev/null 2>&1 ;
if [ $? -eq 0 ]; then
pdu=`echo $output | awk -F "=" '{ print $2 }'` ;
pdunums2string "${pdu}";
else
logger -t user-getnumber -p daemon.err "USSD has been sent, but no SMS recieved ($OPNAME)";
exit 0 ;
fi ;;
*) OPNAME="unknown";
logger -t user-getnumber -p daemon.err "Sorry, code to work with this operator not emplemented yet ($OPMNC)";
exit 0 ;;
esac
# End
Рабочий пример /etc/config/crontabs:
config crontab
option enabled '1'
option minutes '*/30'
option hours '*'
option days '*'
option months '*'
option weekdays '*'
option command '[ ! -f /tmp/startup.check ] && /root/bin/irz-signal'
config crontab
option enabled '1'
option minutes '15'
option hours '*/2'
option days '*'
option months '*'
option weekdays '*'
option command '[ ! -f /tmp/startup.check ] && /root/bin/irz-getnumber'
Полный список скриптов доступен по ссылке (
irz-rl01x-scripts).