Add web GUI, docs, scripts, and 5G router config

- Web app (Flask): status, config, firewall, logs, users, restart
- Docs: AT commands, deploy, DNS, quickstart, web GUI
- Scripts: connect, deploy, diag, healthcheck, modem-status, speedtest, status, troubleshoot
- Init and iptables: 5g-router, 5g-webgui, rules.v4
- CHANGELOG, TODO, REVISION; config and README updates
This commit is contained in:
nearxos
2026-02-02 09:38:23 +02:00
parent 1136a332b5
commit 160ad641ce
46 changed files with 4320 additions and 40 deletions

105
scripts/modem-status-at.sh Normal file
View File

@@ -0,0 +1,105 @@
#!/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)
CONFIG="/etc/5g-router.conf"
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
[ -f "$CONFIG" ] && . "$CONFIG"
get_at() {
_cmd="$1"
_wait="${2:-1}"
timeout $((_wait + 2)) sh -c "
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'