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:
@@ -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 3–5s 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 5–15s 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
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
# Alpine 5G Router – install/deploy scripts and config to this device
|
||||
# Run from repo root: ./scripts/install.sh
|
||||
# Or from scripts/: ./install.sh (uses script dir to find repo root)
|
||||
# Rev: 1 (see REVISION in repo root)
|
||||
# Rev: 2 (see REVISION in repo root)
|
||||
#
|
||||
# NOTE: As of Rev 2, 5g-webgui handles both Web GUI AND 5G connection management.
|
||||
# The standalone 5g-router service is kept for manual/fallback use but is
|
||||
# NOT enabled by default. Use 5g-webgui instead.
|
||||
|
||||
set -e
|
||||
|
||||
@@ -27,7 +31,7 @@ else
|
||||
echo "Keeping existing $CONFIG"
|
||||
fi
|
||||
|
||||
# Scripts
|
||||
# Scripts (kept for manual use and diagnostics)
|
||||
install -m 755 "$SCRIPTS/connect-5g.sh" "$BIN/connect-5g.sh"
|
||||
install -m 755 "$SCRIPTS/status-5g.sh" "$BIN/status-5g.sh"
|
||||
install -m 755 "$SCRIPTS/modem-status-at.sh" "$BIN/modem-status-at.sh"
|
||||
@@ -45,9 +49,9 @@ if [ -f "$ROOT/configure_fm350_5g.sh" ]; then
|
||||
echo "Installed configure_fm350_5g.sh"
|
||||
fi
|
||||
|
||||
# OpenRC service
|
||||
# Legacy 5g-router service (kept for manual/fallback use, NOT enabled by default)
|
||||
install -m 755 "$ETC/init.d/5g-router" "$INITD/5g-router"
|
||||
echo "Installed $INITD/5g-router"
|
||||
echo "Installed $INITD/5g-router (legacy – use 5g-webgui instead)"
|
||||
|
||||
# iptables rules (restore at boot – ensure iptables-restore service exists)
|
||||
mkdir -p "$IPTABLES_SAVE"
|
||||
@@ -57,17 +61,12 @@ if [ -d /etc/init.d ] && [ ! -f /etc/init.d/iptables-restore ]; then
|
||||
echo "Tip: enable iptables restore at boot: rc-update add iptables-restore"
|
||||
fi
|
||||
|
||||
# Log file
|
||||
# Log files
|
||||
touch "$LOG_DIR/5g-router.log" 2>/dev/null && chmod 644 "$LOG_DIR/5g-router.log" || true
|
||||
touch "$LOG_DIR/speedtest-5g.log" 2>/dev/null && chmod 644 "$LOG_DIR/speedtest-5g.log" || true
|
||||
touch "$LOG_DIR/5g-webgui.log" 2>/dev/null && chmod 644 "$LOG_DIR/5g-webgui.log" || true
|
||||
|
||||
# Enable 5g-router at boot
|
||||
if command -v rc-update >/dev/null 2>&1; then
|
||||
rc-update add 5g-router default 2>/dev/null || true
|
||||
echo "Added 5g-router to default runlevel"
|
||||
fi
|
||||
|
||||
# Web GUI (optional)
|
||||
# Web GUI with integrated 5G connection management
|
||||
WEBGUI_SRC="$ROOT/web"
|
||||
WEBGUI_DEST="/usr/local/share/5g-webgui"
|
||||
if [ -d "$WEBGUI_SRC" ] && [ -f "$WEBGUI_SRC/app.py" ]; then
|
||||
@@ -75,14 +74,36 @@ if [ -d "$WEBGUI_SRC" ] && [ -f "$WEBGUI_SRC/app.py" ]; then
|
||||
cp -r "$WEBGUI_SRC"/* "$WEBGUI_DEST/"
|
||||
chmod 755 "$WEBGUI_DEST/run.sh" 2>/dev/null || true
|
||||
install -m 755 "$ETC/init.d/5g-webgui" "$INITD/5g-webgui"
|
||||
echo "Installed Web GUI at $WEBGUI_DEST. Enable with: rc-update add 5g-webgui default"
|
||||
echo " Then: apk add python3 py3-flask && service 5g-webgui start"
|
||||
|
||||
# Enable 5g-webgui at boot (this now handles connection management)
|
||||
if command -v rc-update >/dev/null 2>&1; then
|
||||
rc-update add 5g-webgui default 2>/dev/null || true
|
||||
echo "Added 5g-webgui to default runlevel"
|
||||
|
||||
# Disable old 5g-router if it was enabled
|
||||
rc-update del 5g-router default 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Installed Web GUI with 5G connection management at $WEBGUI_DEST"
|
||||
echo " Install dependencies: apk add python3 py3-flask && pip install pyserial"
|
||||
echo " Start service: service 5g-webgui start"
|
||||
echo " Login at http://<device-ip>:5000 (default: admin/admin, support/support – change passwords)"
|
||||
else
|
||||
echo "Web GUI source not found; skipping."
|
||||
echo "Enabling legacy 5g-router service instead..."
|
||||
if command -v rc-update >/dev/null 2>&1; then
|
||||
rc-update add 5g-router default 2>/dev/null || true
|
||||
echo "Added 5g-router to default runlevel"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Done. Edit $CONFIG if needed, then: service 5g-router start"
|
||||
echo "Or run once: $BIN/connect-5g.sh"
|
||||
echo "Status: $BIN/status-5g.sh"
|
||||
echo "Done. Edit $CONFIG if needed."
|
||||
echo ""
|
||||
echo "To start:"
|
||||
echo " service 5g-webgui start (recommended: includes Web GUI + 5G connection)"
|
||||
echo " OR"
|
||||
echo " service 5g-router start (legacy: 5G connection only, no Web GUI)"
|
||||
echo ""
|
||||
echo "Status: Visit http://<device-ip>:5000 or run: $BIN/status-5g.sh"
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
#!/bin/sh
|
||||
# Alpine 5G Router – modem status via AT commands (AT_COMMANDS_REFERENCE.md)
|
||||
# Outputs JSON. Used by Web GUI /api/status.
|
||||
# Rev: 2 (see REVISION in repo root)
|
||||
# Rev: 3 (see REVISION in repo root)
|
||||
|
||||
CONFIG="/etc/5g-router.conf"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
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
|
||||
|
||||
@@ -8,8 +8,13 @@ CONFIG="/etc/5g-router.conf"
|
||||
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
|
||||
WAN_IF="${WAN_IF:-eth1}"
|
||||
LOG_FILE="/var/log/5g-router.log"
|
||||
AT_LOCK="/var/lock/5g-at.lock"
|
||||
|
||||
[ -f "$CONFIG" ] && . "$CONFIG"
|
||||
[ -f "$CONFIG" ] && . "$CONFIG" || true
|
||||
|
||||
# Acquire lock on AT port so we don't conflict with connect-5g.sh or modem-status-at.sh
|
||||
exec 9>"$AT_LOCK"
|
||||
flock -w 15 9 || echo "Warning: could not acquire AT lock (another process using port)"
|
||||
|
||||
echo "=============================================="
|
||||
echo " Alpine 5G Router – Full Troubleshoot"
|
||||
@@ -59,10 +64,29 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 5) AT port test (with longer wait like connect-5g.sh) ---
|
||||
echo "--- 5) AT command test on $AT_PORT (wait 3s) ---"
|
||||
# --- 5) Processes using the AT port (can block or conflict) ---
|
||||
echo "--- 5) Processes using $AT_PORT (lsof) ---"
|
||||
if [ -e "$AT_PORT" ]; then
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
_lsof=$(lsof 2>/dev/null | grep -F "$AT_PORT")
|
||||
if [ -n "$_lsof" ]; then
|
||||
echo "$_lsof" | sed 's/^/ /'
|
||||
else
|
||||
echo " No process has $AT_PORT open (good)"
|
||||
fi
|
||||
else
|
||||
echo " (lsof not installed – install with: apk add lsof)"
|
||||
fi
|
||||
else
|
||||
echo " Port does not exist (nothing to list)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 6) AT port test (with longer wait like connect-5g.sh) ---
|
||||
echo "--- 6) AT command test on $AT_PORT (wait 3s) ---"
|
||||
if [ -c "$AT_PORT" ]; then
|
||||
out=$(timeout 8 sh -c "
|
||||
[ -c \"$AT_PORT\" ] || exit 1
|
||||
cat $AT_PORT 2>/dev/null &
|
||||
_p=\$!
|
||||
sleep 0.5
|
||||
@@ -82,11 +106,11 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 6) AT probe on all ttyUSB (which port responds) ---
|
||||
echo "--- 6) AT probe on each ttyUSB port ---"
|
||||
# --- 7) AT probe on all ttyUSB (which port responds) ---
|
||||
echo "--- 7) AT probe on each ttyUSB port ---"
|
||||
for port in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3; do
|
||||
[ -c "$port" ] || continue
|
||||
out=$(timeout 5 sh -c "cat $port 2>/dev/null & _p=\$!; sleep 0.3; echo -e 'AT\r' > $port; sleep 2; kill \$_p 2>/dev/null" 2>/dev/null)
|
||||
out=$(timeout 5 sh -c "[ -c \"$port\" ] || exit 1; cat $port 2>/dev/null & _p=\$!; sleep 0.3; echo -e 'AT\r' > $port; sleep 2; kill \$_p 2>/dev/null" 2>/dev/null)
|
||||
if echo "$out" | grep -q 'OK'; then
|
||||
echo " $port: OK (use this as AT_PORT if different from config)"
|
||||
else
|
||||
@@ -95,8 +119,8 @@ for port in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3; do
|
||||
done
|
||||
echo ""
|
||||
|
||||
# --- 7) 5g-router service ---
|
||||
echo "--- 7) 5g-router service ---"
|
||||
# --- 8) 5g-router service ---
|
||||
echo "--- 8) 5g-router service ---"
|
||||
if command -v rc-service >/dev/null 2>&1; then
|
||||
rc-service 5g-router status 2>&1 | sed 's/^/ /'
|
||||
else
|
||||
@@ -104,8 +128,8 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 8) WAN interface and routing ---
|
||||
echo "--- 8) WAN interface ($WAN_IF) and default route ---"
|
||||
# --- 9) WAN interface and routing ---
|
||||
echo "--- 9) WAN interface ($WAN_IF) and default route ---"
|
||||
if ip link show "$WAN_IF" >/dev/null 2>&1; then
|
||||
ip link show "$WAN_IF" 2>/dev/null | sed 's/^/ /'
|
||||
ip -4 addr show "$WAN_IF" 2>/dev/null | sed 's/^/ /'
|
||||
@@ -115,8 +139,8 @@ fi
|
||||
ip route show default 2>/dev/null | sed 's/^/ /'
|
||||
echo ""
|
||||
|
||||
# --- 9) Full 5g-router log ---
|
||||
echo "--- 9) Full 5g-router log (last 60 lines of $LOG_FILE) ---"
|
||||
# --- 10) Full 5g-router log ---
|
||||
echo "--- 10) Full 5g-router log (last 60 lines of $LOG_FILE) ---"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -60 "$LOG_FILE" 2>/dev/null | sed 's/^/ /'
|
||||
else
|
||||
@@ -124,12 +148,12 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 10) Optional: modem status script ---
|
||||
# --- 11) Optional: modem status script ---
|
||||
if [ -x "/usr/local/bin/modem-status-at.sh" ]; then
|
||||
echo "--- 10) modem-status-at.sh (registration, signal) ---"
|
||||
echo "--- 11) modem-status-at.sh (registration, signal) ---"
|
||||
/usr/local/bin/modem-status-at.sh 2>&1 | head -30 | sed 's/^/ /'
|
||||
else
|
||||
echo "--- 10) modem-status-at.sh ---"
|
||||
echo "--- 11) modem-status-at.sh ---"
|
||||
echo " Not installed"
|
||||
fi
|
||||
echo ""
|
||||
@@ -140,6 +164,8 @@ echo "=============================================="
|
||||
echo ""
|
||||
echo "Quick fixes to try:"
|
||||
echo " - ttyUSB is regular file: rm $AT_PORT && mknod $AT_PORT c 188 1 && chmod 660 $AT_PORT && chown root:dialout $AT_PORT"
|
||||
echo " - Stray /dev/ttyUSB (no number): rm /dev/ttyUSB"
|
||||
echo " - Port held by another process (see section 5): stop ModemManager (rc-service ModemManager stop) or restart 5g-router"
|
||||
echo " - Modem in Mode 41 (7127): power-cycle modem or reboot; need Mode 40 (7126) for AT"
|
||||
echo " - AT not OK: set AT_PORT in $CONFIG to the port that showed OK above (e.g. /dev/ttyUSB0)"
|
||||
echo " - Restart connection: service 5g-router restart or /usr/local/bin/connect-5g.sh"
|
||||
|
||||
Reference in New Issue
Block a user