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.
This commit is contained in:
nearxos
2026-02-02 10:34:25 +02:00
parent 78f7ccc6db
commit 9dc35a57a2
14 changed files with 1224 additions and 115 deletions

View File

@@ -20,17 +20,32 @@ WATCHDOG_INTERVAL="0"
LOG_SIGNAL="yes"
WEAK_SIGNAL_CSQ="10"
[ -f "$CONFIG" ] && . "$CONFIG"
[ -f "$CONFIG" ] && . "$CONFIG" || true
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" 2>/dev/null || echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }
# Lock file for exclusive AT port access (shared with modem-status-at.sh)
AT_LOCK="/var/lock/5g-at.lock"
exec 9>"$AT_LOCK"
flock -n 9 || { echo "Another process is using the AT port, waiting..." >&2; flock 9; }
# Log to file; also to stdout only when running in a terminal (avoids duplicate lines when service redirects stdout to log)
log() {
_m="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
echo "$_m" >> "$LOG_FILE" 2>/dev/null || true
[ -t 1 ] && echo "$_m" || true
}
# Fix broken /dev/ttyUSB* node (if it is a regular file instead of char device - e.g. after modem reconnect)
# Also remove stray /dev/ttyUSB (no digit) which can appear and steal the name from real devices
fix_ttyusb_if_needed() {
# Remove stray /dev/ttyUSB (no number) if it's a regular file
if [ -e /dev/ttyUSB ] && [ -f /dev/ttyUSB ] && [ ! -c /dev/ttyUSB ]; then
rm -f /dev/ttyUSB
fi
case "$AT_PORT" in
/dev/ttyUSB[0-9]*) ;;
*) return 0 ;;
esac
[ ! -e "$AT_PORT" ] && return 0
[ ! -e "$AT_PORT" ] && return 0 || true
if [ -f "$AT_PORT" ] && [ ! -c "$AT_PORT" ]; then
_num="${AT_PORT#/dev/ttyUSB}"
log "Fixing $AT_PORT (was regular file, recreating as char device)"
@@ -41,10 +56,12 @@ fix_ttyusb_if_needed() {
fi
}
# Never write to AT_PORT unless it is a character device; otherwise a redirect would create a regular file and break the port
get_at_response() {
_cmd="$1"
_wait="${2:-2}"
timeout $((_wait + 4)) sh -c "
[ -c \"$AT_PORT\" ] || exit 1
cat $AT_PORT 2>/dev/null &
_pid=\$!
sleep 0.5
@@ -80,14 +97,28 @@ do_connect() {
# eth1 (RNDIS) does NOT provide DHCP. We get IP (and DNS) only via AT commands
# and configure the interface manually. Do not run dhclient on eth1.
check_usb_mode || return 1
# Modem can take 35s to respond after boot; use 5s so service (started at boot) gets OK
get_at_response "AT" 5 | grep -q "OK" || { log "AT not OK (try longer wait or different AT port)"; return 1; }
# Modem can take 515s to respond after port appears at boot; retry initial AT up to 3 times
_at_ok=0
for _try in 1 2 3; do
if get_at_response "AT" 5 | grep -q "OK"; then
_at_ok=1
break
fi
if [ $_try -lt 3 ]; then
log "AT not OK, retry $_try/3 in 5s..."
sleep 5
fi
done
if [ $_at_ok -eq 0 ]; then
log "AT not OK (try longer wait or different AT port)"
return 1
fi
# Signal (optional log)
_resp=$(get_at_response "AT+CSQ" 1)
_csq=$(echo "$_resp" | grep "+CSQ:" | grep -oE '[0-9]+' | head -1)
[ -n "$_csq" ] && [ "$LOG_SIGNAL" = "yes" ] && echo "$(date -Iseconds) CSQ=$_csq" >> "$LOG_FILE" 2>/dev/null || true
[ -n "$_csq" ] && [ -n "$WEAK_SIGNAL_CSQ" ] && [ "$WEAK_SIGNAL_CSQ" -gt 0 ] && [ "$_csq" -lt "$WEAK_SIGNAL_CSQ" ] && log "WARN weak signal CSQ=$_csq"
[ -n "$_csq" ] && [ -n "$WEAK_SIGNAL_CSQ" ] && [ "$WEAK_SIGNAL_CSQ" -gt 0 ] && [ "$_csq" -lt "$WEAK_SIGNAL_CSQ" ] && log "WARN weak signal CSQ=$_csq" || true
log "Configuring APN: $APN"
get_at_response "AT+CGDCONT=1,\"IP\",\"$APN\"" 2 | grep -q "OK" || true
@@ -98,25 +129,35 @@ do_connect() {
for _retry in 1 2 3 4 5; do
_resp=$(get_at_response "AT+CGPADDR=1" 2)
_ip=$(echo "$_resp" | grep "+CGPADDR:" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
[ -n "$_ip" ] && break
[ $_retry -lt 5 ] && log "No IP yet, retry $_retry/5 in 3s..." && sleep 3
if [ -n "$_ip" ]; then break; fi
if [ $_retry -lt 5 ]; then
log "No IP yet, retry $_retry/5 in 3s..."
sleep 3
fi
done
[ -z "$_ip" ] && log "Could not get modem IP (check signal/registration: AT+CSQ, AT+CEREG?)" && return 1
if [ -z "$_ip" ]; then
log "Could not get modem IP (check signal/registration: AT+CSQ, AT+CEREG?)"
return 1
fi
# Get DNS from modem (AT+CGCONTRDP=1); modem does not provide DHCP, only IP/DNS via AT
_dns1=""; _dns2=""
_contrdp=$(get_at_response "AT+CGCONTRDP=1" 2)
_allips=""
for _a in $(echo "$_contrdp" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'); do
[ "$_a" = "$_ip" ] && continue
[ "$_a" = "$_ip" ] && continue || true
_allips="${_allips} ${_a}"
done
for _a in $_allips; do [ -z "$_a" ] && continue; _dns2="$_dns1"; _dns1="$_a"; done
for _a in $_allips; do
[ -z "$_a" ] && continue || true
_dns2="$_dns1"
_dns1="$_a"
done
[ -z "$_dns1" ] && [ -n "$DNS_SERVERS" ] && _dns1=$(echo "$DNS_SERVERS" | cut -d',' -f1 | tr -d ' ') && _dns2=$(echo "$DNS_SERVERS" | cut -d',' -f2 | tr -d ' ')
if [ -n "$_dns1" ]; then
: > /etc/resolv.conf
echo "nameserver $_dns1" >> /etc/resolv.conf
[ -n "$_dns2" ] && echo "nameserver $_dns2" >> /etc/resolv.conf
[ -n "$_dns2" ] && echo "nameserver $_dns2" >> /etc/resolv.conf || true
log "DNS set (from modem or config)"
fi
@@ -137,7 +178,7 @@ do_connect() {
}
do_failover() {
[ "$FAILOVER_ENABLED" != "yes" ] && return 0
[ "$FAILOVER_ENABLED" != "yes" ] && return 0 || true
# Ensure there is a default route via failover interface (higher metric so 5G wins when up)
ip route add default dev "$FAILOVER_IF" metric "$FAILOVER_METRIC" 2>/dev/null || true
}