Skip to content

Instantly share code, notes, and snippets.

@odevodyssey
Created February 27, 2024 12:55
Show Gist options
  • Save odevodyssey/52ff8daf2ea8aa40ecee4c798789b7ca to your computer and use it in GitHub Desktop.
Save odevodyssey/52ff8daf2ea8aa40ecee4c798789b7ca to your computer and use it in GitHub Desktop.
Scripts to monitor cellular connection for 4G LTE RPi on OpenWrt
#!/bin/sh
# Internet Monitoring Script for QMI Modem
# Modem: Quectel EG25-G
# Script inspired from conmon.sh in ROOter project.
# https://www.ofmodemsandmen.com/
# What is most likely to happen in my experience is modem gets a new IP from ISP, randomly, and interface does not update, therefore outbound traffic stops
# This script will cover both scenarios
# Scenario 1: Obtain new IP by forcing udhcpc to get new address. Verify address with AT command IP. If not the same, repeat until IP is the same
# Scenario 2: IPs are the same, outbound traffic not working, reset modem
# But so far, easier to only implement Scenario 2, and by that, resetting the modem when there is any connection issue
# At worst case scenario, router restart
# Define variables
GCOM_DIR="/etc/gcom"
CPORT=2
RST_CNT=0
RST_CNT_FLR=2
PKT_LOSS_FLR=40
SLEEP_TIME=30
SLEEP_PLUS=10
SLEEP_CNT=0
SLEEP_CNT_FLR=3
TRCK_IP="8.8.8.8"
# Define functions
# unused function, for now
restart_udhcpc() {
udhcpc_pid=$(pidof udhcpc)
/bin/kill -SIGUSR2 $(udhcpc_pid)
/bin/kill -SIGUSR1 $(udhcpc_pid)
}
log() {
logger -t "conmond" "$@"
}
get_modem_ip() {
# run gcom script
export ATCMD="AT+CGPADDR"
local ATRES=$(comgt -d "/dev/ttyUSB$CPORT" -s $GCOM_DIR/run-at.gcom)
# parse variable output, return modem IP
local modem_ip=$(echo $ATRES | cut -d "," -s -f2 | cut -d "\"" -s -f2)
log "Obtained Modem IP: $modem_ip using command $ATCMD"
unset ATCMD
echo $modem_ip
}
get_wwan0_ip() {
local wwan0_ip=$(ip addr show wwan0 | grep 'inet ' | cut -d' ' -f6 | cut -d "/" -s -f1)
log "Obtained wwan0 IP: $wwan0_ip"
echo $wwan0_ip
}
reset_modem() {
export ATCMD="AT+CFUN=4;+CFUN=1,1"
comgt -d "/dev/ttyUSB$CPORT" -s $GCOM_DIR/run-at.gcom
log "Modem reset with command $ATCMD"
unset ATCMD
}
check_rsts_reboot() {
if [ "$RST_CNT" -gt "$RST_CNT_FLR" ]; then
log "Modem Reset $RST_CNT times failed to restart internet. Rebooting now ..."
reboot -f
fi
}
check_internet() {
# Perform Ping Test to check for connectivitiy issues
# Ping Test Fails > Obtain IP (v4) of interface and check against IP from AT command
initial_wwan0_ip=$(get_wwan0_ip)
pkt_loss=$(ping -c 5 $TRCK_IP | tail -2 | head -1 | awk '{print $7}' | sed 's/.$//')
if [ -z $pkt_loss ]; then
pkt_loss=100
fi
if [ "$pkt_loss" -gt "$PKT_LOSS_FLR" ]; then
check_rsts_reboot
RST_CNT=$((RST_CNT+1))
log "$pkt_loss% is greater than $PKT_LOSS_FLR%, Internet Down"
log "Initiate modem reset $RST_CNT"
reset_modem
sleep $SLEEP_TIME
modem_ip=$(get_modem_ip)
wwan0_ip=$(get_wwan0_ip)
while [ -z "$modem_ip" ] && [ "$SLEEP_CNT" -lt "$SLEEP_CNT_FLR" ]
do
log "Sleep $SLEEP_PLUS until Modem IP resolves"
sleep $SLEEP_PLUS
modem_ip=$(get_modem_ip)
SLEEP_CNT=$((SLEEP_CNT+1))
done
SLEEP_CNT=0
while [ -z "$wwan0_ip" ] && [ "$SLEEP_CNT" -lt "$SLEEP_CNT_FLR" ]
do
log "Sleep $SLEEP_PLUS until wwan0 IP resolves"
sleep $SLEEP_PLUS
wwan0_ip=$(get_wwan0_ip)
SLEEP_CNT=$((SLEEP_CNT+1))
done
if [ -z "$modem_ip" ] || [ -z "$wwan0_ip" ]; then
check_rsts_reboot
RST_CNT=$((RST_CNT+1))
log "Modem IP: $modem_ip or wwan0 IP: $wwan0_ip is empty | Initiate subsequent modem reset $RST_CNT"
reset_modem
sleep $SLEEP_TIME
check_internet
elif [ "$modem_ip" = "$wwan0_ip" ]; then
log "Modem IP: $modem_ip and wwan0 IP: $wwan0_ip match | Retest with ping"
check_internet
else
check_rsts_reboot
RST_CNT=$((RST_CNT+1))
log "Modem IP: $modem_ip and wwan0 IP $wwan0_ip do not match | Initiate subsequent modem reset $RST_CNT"
reset_modem
sleep $SLEEP_TIME
check_internet
fi
else
log "Internet operational with IP: $initial_wwan0_ip"
exit 0
fi
}
check_internet
# be sure to write number of reconnects to file (append latest reconnect with timestamp, regardless of reconnect method used)
*/5 * * * * /etc/conmon.sh
opengt
set com 115200n81
set comecho off
set senddelay 0.05
waitquiet 1 0.2
:start
let f=25
let $x=$env("ATCMD")
if $x="" goto error
send $x
send "^m"
let t=time()+f
gosub getresult
if $s="^mTIMEOUT ERROR" print $s
:continue
exit 0
:error
print "No ATCMD var set"
exit 1
:getresult
get 1 "^m" $s
let x=len($s)
if x=0 let $s="^mTIMEOUT ERROR"
else print $s
if $s="^jOK" return
if $mid($s,0,6)="^jERROR" return
if $mid($s,0,8)="^jCOMMAND" return
if $mid($s,0,11)="^j+CME ERROR" return
if time()>t return
goto getresult
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment