Files
Alpine_5G/scripts/modem-status-at.sh
nearxos 9dc35a57a2 Enhance 5G modem management with integrated web GUI and connection control
- Introduced a web GUI for managing 5G connections, replacing the standalone 5g-router service.
- Updated scripts to ensure exclusive access to the AT port, preventing conflicts.
- Improved troubleshooting documentation in 5G_MODEM_TROUBLESHOOTING.md, adding checks for processes using the AT port.
- Enhanced connection management in the web app, including auto-connect and detailed status APIs.
- Updated installation scripts to reflect changes in service management and dependencies.
2026-02-02 10:34:25 +02:00

112 lines
4.4 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Alpine 5G Router modem status via AT commands (AT_COMMANDS_REFERENCE.md)
# Outputs JSON. Used by Web GUI /api/status.
# Rev: 3 (see REVISION in repo root)
CONFIG="/etc/5g-router.conf"
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
AT_LOCK="/var/lock/5g-at.lock"
[ -f "$CONFIG" ] && . "$CONFIG" || true
# Acquire exclusive lock on AT port to avoid conflicts with connect-5g.sh
exec 9>"$AT_LOCK"
flock -w 10 9 || { echo '{"error":"AT port busy"}'; exit 1; }
get_at() {
_cmd="$1"
_wait="${2:-1}"
timeout $((_wait + 2)) sh -c "
[ -c \"$AT_PORT\" ] || exit 1
cat $AT_PORT 2>/dev/null &
_p=\$!
sleep 0.3
echo -e '${_cmd}\r' > $AT_PORT
sleep $_wait
kill \$_p 2>/dev/null
" 2>/dev/null
}
json_str() { printf '"%s"' "$(echo "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' ' ')"; }
# Probe port: send AT, return 0 if we see OK
try_at_port() {
_port="$1"
[ ! -c "$_port" ] && return 1
_out=$(timeout 4 sh -c "
cat $_port 2>/dev/null &
_p=\$!
sleep 0.3
echo -e 'AT\r' > $_port
sleep 1
kill \$_p 2>/dev/null
" 2>/dev/null)
echo "$_out" | grep -q 'OK' && return 0 || return 1
}
# Use configured port if it exists and is a char device; else try common Fibocom AT ports
if [ ! -c "$AT_PORT" ]; then
for p in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2; do
if try_at_port "$p"; then
AT_PORT="$p"
break
fi
done
fi
[ ! -c "$AT_PORT" ] && echo '{}' && exit 0
# Disable command echo so we get only response lines (ATE0); avoids parsing "AT+CGMI" as manufacturer
get_at "ATE0" 1 >/dev/null 2>&1
sleep 0.2
# Query AT commands (reference: AT_COMMANDS_REFERENCE.md)
r_cgmi=$(get_at "AT+CGMI" 1)
r_cgmm=$(get_at "AT+CGMM" 1)
r_cgmr=$(get_at "AT+CGMR" 1)
r_cgsn=$(get_at "AT+CGSN" 1)
r_csq=$(get_at "AT+CSQ" 1)
r_creg=$(get_at "AT+CREG?" 1)
r_cereg=$(get_at "AT+CEREG?" 1)
r_usbmode=$(get_at "AT+GTUSBMODE?" 1)
r_ccid=$(get_at "AT+CCID" 1)
r_cops=$(get_at "AT+COPS?" 1)
r_cgpaddr=$(get_at "AT+CGPADDR=1" 1)
# Parse (skip echoed command lines: lines starting with AT or +)
manufacturer=$(echo "$r_cgmi" | grep -vE '^AT|^\+' | grep -oE '^[A-Za-z0-9 ].*' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
model=$(echo "$r_cgmm" | grep -vE '^AT|^\+' | grep -oE '^[A-Za-z0-9\-].*' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
revision=$(echo "$r_cgmr" | grep -vE '^(AT|OK|\+)' | head -1 | sed 's/\r$//; s/^ *//; s/ *$//')
imei=$(echo "$r_cgsn" | grep -oE '[0-9]{15}' | head -1)
csq=$(echo "$r_csq" | grep "+CSQ:" | grep -oE '[0-9]+' | head -1)
creg=$(echo "$r_creg" | grep "+CREG:" | head -1)
cereg=$(echo "$r_cereg" | grep "+CEREG:" | head -1)
usb_mode=$(echo "$r_usbmode" | grep "+GTUSBMODE:" | grep -oE '[0-9]+' | head -1)
iccid=$(echo "$r_ccid" | grep "+CCID:" | sed 's/+CCID:[[:space:]]*//; s/\r$//; s/"//g' | head -1)
cops=$(echo "$r_cops" | grep "+COPS:" | sed 's/+COPS:[[:space:]]*//; s/\r$//' | head -1)
modem_ip=$(echo "$r_cgpaddr" | grep "+CGPADDR:" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
# Registration: CREG 0,1 = registered home, 0,5 = registered roaming; CEREG same
creg_status=""
case "$creg" in *",1"*) creg_status="registered_home";; *",5"*) creg_status="registered_roaming";; *",2"*) creg_status="searching";; *",0"*) creg_status="not_registered";; *) creg_status="unknown";; esac
cereg_status=""
case "$cereg" in *",1"*) cereg_status="registered_home";; *",5"*) cereg_status="registered_roaming";; *",2"*) cereg_status="searching";; *",0"*) cereg_status="not_registered";; *) cereg_status="unknown";; esac
# Operator name from +COPS: 0,0,"Vodafone",7
operator_name=$(echo "$cops" | sed -n 's/.*"\([^"]*\)".*/\1/p')
# Build JSON (no jq)
printf '{\n'
printf ' "at_port": '; json_str "$AT_PORT"; printf ',\n'
printf ' "manufacturer": '; json_str "${manufacturer:-}"; printf ',\n'
printf ' "model": '; json_str "${model:-}"; printf ',\n'
printf ' "revision": '; json_str "${revision:-}"; printf ',\n'
printf ' "imei": '; json_str "${imei:-}"; printf ',\n'
printf ' "signal_csq": %s,\n' "${csq:-null}"
printf ' "creg_status": '; json_str "$creg_status"; printf ',\n'
printf ' "cereg_status": '; json_str "$cereg_status"; printf ',\n'
printf ' "usb_mode": '; json_str "${usb_mode:-}"; printf ',\n'
printf ' "iccid": '; json_str "${iccid:-}"; printf ',\n'
printf ' "operator": '; json_str "${operator_name:-}"; printf ',\n'
printf ' "modem_ip": '; json_str "${modem_ip:-}"; printf '\n'
printf '}\n'