added about page functioanlity

This commit is contained in:
Russel Yasol
2024-10-06 08:00:12 +08:00
parent 0adddef63a
commit 8c0b758cb3
18 changed files with 1023 additions and 63 deletions

View File

@@ -25,6 +25,7 @@
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/about/fetch-data.js"></script>
<script>
(function () {
@@ -153,27 +154,27 @@
<tbody>
<tr>
<td>Modem Manufacturer</td>
<th>Quectel</th>
<th id="manufacturer">Fetching...</th>
</tr>
<tr>
<td>Modem Model Name</td>
<th>RM520N-GL</th>
<th id="model"></th>
</tr>
<tr>
<td>Firmware Version</td>
<th>RM520NGLAA123</th>
<th id="firmwareVersion"></th>
</tr>
<tr>
<td>Phone Number</td>
<th>+639938931024</th>
<th id="phoneNumber"></th>
</tr>
<tr>
<td>IMSI</td>
<th>123456789</th>
<th id="imsi"></th>
</tr>
<tr>
<td>ICCID</td>
<th>123456789</th>
<th id="iccid"></th>
</tr>
<tr>
<td>IMEI</td>
@@ -184,29 +185,33 @@
class="input has-text-weight-semibold"
type="text"
placeholder="IMEI Here"
id="imeiInput"
/>
</div>
<div class="control">
<button class="button is-link">Change</button>
<button class="button is-link" id="changeButton">Change</button>
</div>
</div>
<span class="is-block-mobile is-hidden">
123456789123
<span class="is-block-mobile is-hidden" id="imei">
</span>
</th>
</tr>
<tr>
<td>LAN GATEWAY</td>
<th>192.168.225.1</th>
<th id="lanIP">
</th>
</tr>
<tr>
<td>WWAN IPv4</td>
<th>38.0.101.76</th>
<th id="IPv4">
</th>
</tr>
<tr>
<td>WWAN IPv6</td>
<th style="word-break: break-all">
5be8:dde9:7f0b:d5a7:bd01:b3be:9c69:573b
<th style="word-break: break-all" id="IPv6">
</th>
</tr>
</tbody>
@@ -271,6 +276,9 @@
>rbflurry</a
>
</li>
<li>
Wutang Clan
</li>
</ul>
</div>
</div>
@@ -297,12 +305,12 @@
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
Do not do any action while the modem is rebooting.
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
Rebooting... <span id="countdown">80</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">

View File

@@ -199,7 +199,7 @@
<option value="AUTO">Automatic</option>
<option value="LTE">LTE Only</option>
<option value="NR5G">5G SA Only</option>
<option value="NR5G:LTE">5G NSA Only</option>
<option value="LTE:NR5G">5G NSA Only</option>
</select>
</span>
<span class="icon is-small is-left">

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+CGMI' 'AT+CGMM' 'AT+CGMR' 'AT+CNUM' 'AT+CIMI' 'AT+ICCID' 'AT+CGSN' 'AT+QMAP="LANIP"' 'AT+QMAP="WWAN"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+QMAP="MPDN_RULE"' 'AT+QMAP="DHCPV4DNS"' 'AT+QCFG="usbnet"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,49 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Create a temporary file to store the processed data
temp_file=$(mktemp)
# Process ARP entries and store in temporary file
arp -a | while IFS= read -r line; do
if [ -n "$line" ]; then
# Extract hostname (or IP if hostname is "?"), IP, and MAC
hostname=$(echo "$line" | awk '{print $1}')
ip=$(echo "$line" | awk -F '[()]' '{print $2}')
mac=$(echo "$line" | awk '{print $4}')
# Skip entries without valid MAC addresses
if [ "$mac" = "<incomplete>" ]; then
continue
fi
# If hostname is "?", use the IP address instead
if [ "$hostname" = "?" ]; then
hostname="$ip"
fi
# Store each entry in the temp file
echo "$hostname:$ip:$mac" >> "$temp_file"
fi
done
# Initialize JSON array
echo -n "["
# Process the temporary file to create JSON
first=true
while IFS=: read -r hostname ip mac; do
if [ "$first" = true ]; then
first=false
else
echo -n ","
fi
echo -n "{\"hostname\":\"$hostname\",\"ip\":\"$ip\",\"mac\":\"$mac\"}"
done < "$temp_file"
# Close the JSON array
echo "]"
# Clean up
rm -f "$temp_file"

View File

@@ -0,0 +1,94 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
ttl_file="/etc/firewall.user.ttl"
lan_utils_script="/etc/data/lanUtils.sh"
setup_persistent_config() {
if [ ! -f "$lan_utils_script" ]; then
echo "{\"success\": false, \"error\": \"lanUtils.sh not found\"}"
return 1
fi
# Backup the original script if not already done
if [ ! -f "${lan_utils_script}.bak" ]; then
cp "$lan_utils_script" "${lan_utils_script}.bak"
fi
# Add the local ttl_firewall_file line if it's not already present
if ! grep -q "local ttl_firewall_file" "$lan_utils_script"; then
sed -i '/local tcpmss_firewall_filev6/a \ local ttl_firewall_file=/etc/firewall.user.ttl' "$lan_utils_script"
fi
# Add the condition to include the ttl_firewall_file if it's not already present
if ! grep -q "if \[ -f \"\$ttl_firewall_file\" \]; then" "$lan_utils_script"; then
sed -i '/if \[ -f "\$tcpmss_firewall_filev6" \]; then/i \ if [ -f "\$ttl_firewall_file" ]; then\n cat \$ttl_firewall_file >> \$firewall_file\n fi' "$lan_utils_script"
fi
}
clear_existing_rules() {
local current_ttl=$1
if [ -n "$current_ttl" ]; then
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set "$current_ttl" 2>/dev/null
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set "$current_ttl" 2>/dev/null
fi
}
case "$REQUEST_METHOD" in
GET)
# Ensure consistent JSON format for GET requests
if [ -s "$ttl_file" ]; then
ttl_value=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
# Ensure ttl_value is a number, default to 0 if not
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
ttl_value=0
fi
echo "{\"isEnabled\": true, \"currentValue\": $ttl_value}"
else
echo "{\"isEnabled\": false, \"currentValue\": 0}"
fi
;;
POST)
read -r post_data
ttl_value=$(echo "$post_data" | sed 's/ttl=//')
# Ensure ttl_file exists
touch "$ttl_file" 2>/dev/null
if [ ! -f "$ttl_file" ]; then
echo "{\"success\": false, \"error\": \"Cannot create TTL file\"}"
exit 1
fi
# Setup persistent configuration
setup_persistent_config
# Get current TTL value for cleanup
current_ttl=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
echo "{\"success\": false, \"error\": \"Invalid TTL value\"}"
elif [ "$ttl_value" = "0" ]; then
clear_existing_rules "$current_ttl"
> "$ttl_file"
echo "{\"success\": true}"
else
# Clear existing rules
clear_existing_rules "$current_ttl"
# Set new rules
echo "iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set $ttl_value" > "$ttl_file"
echo "ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set $ttl_value" >> "$ttl_file"
# Apply the rules
iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set "$ttl_value"
ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set "$ttl_value"
echo "{\"success\": true}"
fi
;;
*)
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
;;
esac

View File

@@ -0,0 +1,153 @@
#!/bin/sh
# Parse POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | grep -o 'iccidProfile1=[^&]*' | cut -d= -f2)
apnProfile1=$(echo "$QUERY_STRING" | grep -o 'apnProfile1=[^&]*' | cut -d= -f2)
pdpType1=$(echo "$QUERY_STRING" | grep -o 'pdpType1=[^&]*' | cut -d= -f2)
iccidProfile2=$(echo "$QUERY_STRING" | grep -o 'iccidProfile2=[^&]*' | cut -d= -f2)
apnProfile2=$(echo "$QUERY_STRING" | grep -o 'apnProfile2=[^&]*' | cut -d= -f2)
pdpType2=$(echo "$QUERY_STRING" | grep -o 'pdpType2=[^&]*' | cut -d= -f2)
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
apnProfile1=$(urldecode "$apnProfile1")
pdpType1=$(urldecode "$pdpType1")
iccidProfile2=$(urldecode "$iccidProfile2")
apnProfile2=$(urldecode "$apnProfile2")
pdpType2=$(urldecode "$pdpType2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create the directory structure
mkdir -p /etc/quecmanager
# Create a configuration file to store APN profiles (as plain text)
cat > /etc/quecmanager/apn_config.txt << EOF
iccidProfile1=$iccidProfile1
apnProfile1=$apnProfile1
pdpType1=$pdpType1
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/apn_config.txt << EOF
iccidProfile2=$iccidProfile2
apnProfile2=$apnProfile2
pdpType2=$pdpType2
EOF
fi
# Create the apnProfiles.sh script
cat > /etc/quecmanager/apnProfiles.sh << 'EOF'
#!/bin/sh
# Function to read config values
get_config_value() {
local key=$1
grep "^${key}=" /etc/quecmanager/apn_config.txt | cut -d'=' -f2
}
# Read configuration
iccidProfile1=$(get_config_value "iccidProfile1")
apnProfile1=$(get_config_value "apnProfile1")
pdpType1=$(get_config_value "pdpType1")
iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Function to get current ICCID
get_current_iccid() {
local input_file="/tmp/inputICCID.txt"
local output_file="/tmp/outputICCID.txt"
echo "AT+ICCID" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
iccid=$(cat "$output_file" | grep "+ICCID:" | cut -d' ' -f2)
rm -f "$input_file" "$output_file"
echo "$iccid"
}
# Function to set APN
set_apn() {
local pdp_type="$1"
local apn="$2"
local input_file="/tmp/inputAPN.txt"
local output_file="/tmp/outputAPN.txt"
echo "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
local result=$(cat "$output_file")
rm -f "$input_file" "$output_file"
if echo "$result" | grep -q "OK"; then
return 0
else
return 1
fi
}
# Get current ICCID
current_iccid=$(get_current_iccid)
success=false
# Check ICCID against profile 1 (required)
if [ "$current_iccid" = "$iccidProfile1" ]; then
if set_apn "$pdpType1" "$apnProfile1"; then
success=true
fi
# Check ICCID against profile 2 (optional)
elif [ -n "$iccidProfile2" ] && [ "$current_iccid" = "$iccidProfile2" ]; then
if set_apn "$pdpType2" "$apnProfile2"; then
success=true
fi
fi
if [ "$success" = "true" ]; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
EOF
# Make the script executable
chmod +x /etc/quecmanager/apnProfiles.sh
# Add to rc.local if not already present
if ! grep -q "/etc/quecmanager/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apnProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apnProfiles.sh
# Check the result
if [ -f /tmp/apn_result.txt ]; then
result=$(cat /tmp/apn_result.txt)
rm -f /tmp/apn_result.txt
if [ "$result" = "APN set successfully" ]; then
echo '{"status": "success", "message": "APN profiles saved and applied successfully"}'
else
echo '{"status": "error", "message": "APN profiles saved but failed to apply"}'
fi
else
echo '{"status": "error", "message": "Something went wrong while processing APN profiles"}'
fi

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+CGDCONT?' 'AT+QNWPREFCFG="mode_pref"' 'AT+QNWPREFCFG="nr5g_disable_mode"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,45 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "error", "message": "No APN profiles found", "profiles": {}}'
exit 0
fi
# Function to read config values
get_config_value() {
local key=$1
local value=$(grep "^${key}=" "$CONFIG_FILE" | cut -d'=' -f2)
echo "$value"
}
# Read all profile values
iccidProfile1=$(get_config_value "iccidProfile1")
apnProfile1=$(get_config_value "apnProfile1")
pdpType1=$(get_config_value "pdpType1")
iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Construct JSON response
cat << EOF
{
"status": "success",
"profiles": {
"profile1": {
"iccid": "${iccidProfile1:-}",
"apn": "${apnProfile1:-}",
"pdpType": "${pdpType1:-}"
},
"profile2": {
"iccid": "${iccidProfile2:-}",
"apn": "${apnProfile2:-}",
"pdpType": "${pdpType2:-}"
}
}
}
EOF

View File

@@ -0,0 +1,14 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Ping 8.8.8.8 and capture the result
if ping -c 1 8.8.8.8 > /dev/null 2>&1; then
# Ping was successful
echo '{"connection": "ACTIVE"}'
else
# Ping failed
echo '{"connection": "INACTIVE"}'
fi

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGDCONT?" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,16 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Get RX and TX bytes from ifconfig eth0
data=$(ifconfig eth0 | grep "RX bytes")
# Extract download (RX) and upload (TX) values using awk
download=$(echo $data | awk '{print $2}' | cut -d':' -f2)
upload=$(echo $data | awk '{print $6}' | cut -d':' -f2)
# Return JSON response
echo "{"
echo " \"download\": \"$download\","
echo " \"upload\": \"$upload\""
echo "}"

347
www/js/about/fetch-data.js Normal file
View File

@@ -0,0 +1,347 @@
// State variables to track current values
let currentIMEI = "";
let updatedIMEI = "";
// Constants
const REBOOT_COUNTDOWN_TIME = 80;
const MESSAGES = {
DEFAULT_REBOOT: "Do not do any action while the modem is rebooting.",
IMEI_REBOOT:
"IMEI change requires a reboot.\nDo not perform any actions while the modem is rebooting.",
INVALID_IMEI: "IMEI should be 15 digits and should only contain numbers.",
NO_CHANGES: "No changes detected in the IMEI field.",
ERROR_SAVING: "Error saving settings. Please try again.",
};
const DATA_MAP = {
CGMI: {
parse: (response) => response.split("\n")[1].trim(),
elementId: "manufacturer",
},
CGMM: {
parse: (response) => response.split("\n")[1].trim(),
elementId: "model",
},
CGMR: {
parse: (response) => response.split("\n")[1].trim(),
elementId: "firmwareVersion",
},
CNUM: {
parse: (response) =>
response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.replace(/"/g, "")
.trim(),
elementId: "phoneNumber",
},
CIMI: {
parse: (response) => response.split("\n")[1].trim(),
elementId: "imsi",
},
ICCID: {
parse: (response) => response.split("\n")[1].split(":")[1].trim(),
elementId: "iccid",
},
CGSN: {
parse: (response) => response.split("\n")[1].trim(),
elementId: "imei",
special: true,
},
LANIP: {
parse: (response) =>
response.split("\n")[1].split(":")[1].split(",")[3].trim(),
elementId: "lanIP",
},
WWAN: {
parse: (response) => ({
IPv4: response
.split("\n")[1]
.split(":")[1]
.split(",")[4]
.replace(/"/g, "")
.trim(),
IPv6: response.split("\n")[2].split(",")[4].replace(/"/g, "").trim(),
}),
elementIds: ["IPv4", "IPv6"],
},
};
// DOM Element Selectors
const selectors = {
modal: "#reboot-modal",
countdown: "#countdown",
loadingContent: "#loading-content",
modalButtons: "#modal-buttons",
modalMessage: "#modal-message",
imeiInput: "#imeiInput",
changeButton: "#changeButton",
powerButton: ".reboot-modal",
alertButtons: ".delete",
modalBackground: ".modal-background",
cancelButton: ".cancel",
rebootButton: "#rebootModem",
};
// Utility Functions
function getElement(selector) {
return document.querySelector(selector);
}
function validateIMEI(imei) {
return imei.length === 15 && !isNaN(imei);
}
function updateElementDisplay(element, display) {
if (element) element.style.display = display;
}
// IMEI Management Functions
function haveIMEIChanged() {
return currentIMEI !== updatedIMEI;
}
function resetIMEIInput() {
const imeiInput = getElement(selectors.imeiInput);
if (imeiInput) {
imeiInput.value = currentIMEI;
updatedIMEI = currentIMEI;
}
}
// AT Command Functions
async function sendATCommand(command) {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: "command=" + encodeURIComponent(command),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error("Error sending AT command:", error);
throw error;
}
}
// Modal Management Functions
function handleRebootCountdown() {
const countdownElement = getElement(selectors.countdown);
const loadingContent = getElement(selectors.loadingContent);
const modalButtons = getElement(selectors.modalButtons);
const modalMessage = getElement(selectors.modalMessage);
updateElementDisplay(modalMessage, "none");
updateElementDisplay(modalButtons, "none");
updateElementDisplay(loadingContent, "block");
let timeLeft = REBOOT_COUNTDOWN_TIME;
const countdownInterval = setInterval(() => {
timeLeft--;
if (countdownElement) countdownElement.textContent = timeLeft;
if (timeLeft <= 0) {
clearInterval(countdownInterval);
window.location.reload();
}
}, 1000);
}
function showRebootModal(isIMEIChange = false) {
const modal = getElement(selectors.modal);
const loadingContent = getElement(selectors.loadingContent);
const modalButtons = getElement(selectors.modalButtons);
const modalMessage = getElement(selectors.modalMessage);
if (!modal) return;
modal.classList.add("is-active");
updateElementDisplay(loadingContent, "none");
updateElementDisplay(modalButtons, "block");
updateElementDisplay(modalMessage, "block");
if (modalMessage) {
modalMessage.textContent = isIMEIChange
? MESSAGES.IMEI_REBOOT
: MESSAGES.DEFAULT_REBOOT;
modalMessage.style.whiteSpace = "pre-line";
}
setupModalEventListeners(modal, isIMEIChange);
}
function setupModalEventListeners(modal, isIMEIChange) {
const rebootButton = getElement(selectors.rebootButton);
const cancelButton = modal.querySelector(selectors.cancelButton);
const modalBackground = modal.querySelector(selectors.modalBackground);
if (rebootButton) {
rebootButton.onclick = async () => {
handleRebootCountdown();
if (isIMEIChange) {
try {
await sendATCommand("AT+QPOWD=1");
} catch (error) {
console.error("Error sending reboot command:", error);
}
}
};
}
const closeModal = () => {
modal.classList.remove("is-active");
if (isIMEIChange) {
resetIMEIInput();
}
};
if (cancelButton) cancelButton.onclick = closeModal;
if (modalBackground) modalBackground.onclick = closeModal;
}
// IMEI Settings Management
async function saveIMEISetting() {
if (!haveIMEIChanged()) {
alert(MESSAGES.NO_CHANGES);
return;
}
if (!validateIMEI(updatedIMEI)) {
alert(MESSAGES.INVALID_IMEI);
return;
}
try {
const atCommand = `AT+EGMR=1,7,"${updatedIMEI}"`;
console.log("Sending AT command:", atCommand);
const inputs = document.querySelectorAll("input, select");
inputs.forEach((input) => (input.disabled = true));
const response = await sendATCommand(atCommand);
console.log("AT command response:", response);
showRebootModal(true);
} catch (error) {
console.error("Error saving settings:", error);
alert(MESSAGES.ERROR_SAVING);
resetIMEIInput();
const inputs = document.querySelectorAll("input, select");
inputs.forEach((input) => (input.disabled = false));
}
}
// Data Parsing Functions
function parseDeviceData(response, key) {
const dataMap = {
CGMI: (response) => response.split("\n")[1].trim(),
CGMM: (response) => response.split("\n")[1].trim(),
CGMR: (response) => response.split("\n")[1].trim(),
CNUM: (response) =>
response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.replace(/"/g, "")
.trim(),
CIMI: (response) => response.split("\n")[1].trim(),
ICCID: (response) => response.split("\n")[1].split(":")[1].trim(),
CGSN: (response) => response.split("\n")[1].trim(),
LANIP: (response) =>
response.split("\n")[1].split(":")[1].split(",")[3].trim(),
WWAN: (response) => ({
IPv4: response
.split("\n")[1]
.split(":")[1]
.split(",")[4]
.replace(/"/g, "")
.trim(),
IPv6: response.split("\n")[2].split(",")[4].replace(/"/g, "").trim(),
}),
};
return dataMap[key]?.(response);
}
// Data Fetching and Display
// Data Parsing and Update Functions
function updateDeviceInfo(key, value) {
const mapping = DATA_MAP[key];
if (!mapping) return;
if (mapping.elementIds) {
// Handle WWAN case with multiple values
mapping.elementIds.forEach((id) => {
const element = document.getElementById(id);
if (element) element.textContent = value[id];
});
} else {
const element = document.getElementById(mapping.elementId);
if (element) element.textContent = value;
// Special handling for IMEI
if (mapping.special) {
currentIMEI = value;
updatedIMEI = value;
const imeiInput = getElement(selectors.imeiInput);
if (imeiInput) {
imeiInput.value = value;
imeiInput.addEventListener("input", () => {
updatedIMEI = imeiInput.value;
console.log("Updated IMEI:", updatedIMEI);
});
}
}
}
}
// Data Fetching
async function fetchAboutData() {
try {
const response = await fetch("/cgi-bin/about/fetch-about.sh");
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log("Full response:", data);
data.forEach((item) => {
Object.keys(DATA_MAP).forEach((key) => {
if (item.response.includes(key)) {
const value = DATA_MAP[key].parse(item.response);
updateDeviceInfo(key, value);
}
});
});
} catch (error) {
console.error("Error fetching about data:", error);
}
}
// Initialize when DOM is loaded
document.addEventListener("DOMContentLoaded", () => {
fetchAboutData();
const changeButton = getElement(selectors.changeButton);
if (changeButton) {
changeButton.addEventListener("click", saveIMEISetting);
}
const powerButton = getElement(selectors.powerButton);
if (powerButton) {
powerButton.addEventListener("click", () => showRebootModal(false));
}
const alertButtons = document.querySelectorAll(selectors.alertButtons);
alertButtons.forEach((button) => {
button.addEventListener("click", fetchAboutData);
});
});

View File

@@ -2,7 +2,7 @@
const api = {
async fetchCurrentSettings() {
try {
const response = await fetch("/cgi-bin/advanced_settings.sh");
const response = await fetch("/cgi-bin/advance/advanced_settings.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
@@ -17,7 +17,7 @@ const api = {
async fetchConnectedDevices() {
try {
const response = await fetch("/cgi-bin/fetch_macs.sh");
const response = await fetch("/cgi-bin/advance/fetch_macs.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
@@ -151,35 +151,7 @@ const uiManager = {
}
}, 1000);
},
// showSuccessMessage(message) {
// // Implement based on your UI framework
// console.log("Success:", message);
// // Example: Show a toast notification
// if (window.bulmaToast) {
// bulmaToast.toast({
// message: message,
// type: 'is-success',
// duration: 3000,
// position: 'top-center',
// });
// }
// },
// showErrorMessage(message) {
// // Implement based on your UI framework
// console.error("Error:", message);
// // Example: Show a toast notification
// if (window.bulmaToast) {
// bulmaToast.toast({
// message: message,
// type: 'is-danger',
// duration: 5000,
// position: 'top-center',
// });
// }
// },
setElementLoading(element, isLoading) {
if (isLoading) {
element.disabled = true;

View File

@@ -2,7 +2,7 @@
const TTLControl = {
async getCurrentState() {
try {
const response = await fetch('/cgi-bin/ttl.sh');
const response = await fetch('/cgi-bin/advance/ttl.sh');
const data = await response.json();
return {
isEnabled: data.isEnabled,
@@ -16,7 +16,7 @@ const TTLControl = {
async setTTLValue(value) {
try {
const response = await fetch('/cgi-bin/ttl.sh', {
const response = await fetch('/cgi-bin/advance/ttl.sh', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',

View File

@@ -48,7 +48,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Function to fetch and display existing profiles
function fetchProfiles() {
fetch('/cgi-bin/fetch-apn-profiles.sh')
fetch('/cgi-bin/cell-settings/fetch-apn-profiles.sh')
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
@@ -138,7 +138,7 @@ document.addEventListener('DOMContentLoaded', function() {
};
// Send data to the server
fetch('/cgi-bin/apn-profile.sh', {
fetch('/cgi-bin/cell-settings/apn-profile.sh', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',

View File

@@ -156,7 +156,7 @@ async function sendATCommand(command) {
// Function to fetch cell settings data
async function fetchCellSettings() {
try {
const response = await fetch("/cgi-bin/cell-settings.sh");
const response = await fetch("/cgi-bin/cell-settings/cell-settings.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
@@ -220,8 +220,7 @@ async function fetchCellSettings() {
});
}
}
} else if (item.response.includes("QNWPREFCFG")) {
console.log("QNWPREFCFG:", item.response);
} else if (item.response.includes("mode_pref")) {
const networkMode = item.response
.split("\n")[1]
.replace("+QNWPREFCFG: ", "")
@@ -231,12 +230,14 @@ async function fetchCellSettings() {
currentNetworkMode = networkMode;
updatedNetworkMode = networkMode;
console.log("Network mode:", networkMode);
const networkSelect = document.getElementById("networkPreference");
if (networkSelect) {
// Set initial value based on actual value from modem
networkSelect.value =
networkMode === "LTE:NR5G"
? "NR5G:LTE"
? "LTE:NR5G"
: networkMode === "NR5G"
? "NR5G"
: networkMode === "LTE"
@@ -252,7 +253,7 @@ async function fetchCellSettings() {
});
}
}
} else if (item.response.includes("nr5g_disable_mode")) {
const nr5GModeControl = item.response
.split("\n")[1]
.split(":")[1]

View File

@@ -211,7 +211,7 @@ async function fetchATCommandData() {
}
async function fetchAndParseData() {
const response = await fetch("/cgi-bin/home_data.sh", {
const response = await fetch("/cgi-bin/home/home_data.sh", {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -247,10 +247,7 @@ function processSimData(jsonData) {
setText("simSlot", simSlot);
// Phone Number
const phoneNumber = extractValue(phoneResponse.response).replace(
/["\,]/g,
""
);
const phoneNumber = extractValue(phoneResponse.response).split(",")[1].replace(/"/g, "").trim();
setText("phoneNumber", phoneNumber);
// SIM Provider and Access Technology
@@ -961,7 +958,7 @@ function processWANIPData(jsonData) {
async function fetchTrafficStats() {
try {
const response = await fetch("/cgi-bin/traffic_stats.sh", {
const response = await fetch("/cgi-bin/home/traffic_stats.sh", {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -1013,7 +1010,7 @@ async function fetchConnectionStatus() {
container.appendChild(checkingElement);
// Fetch the data
const response = await fetch("/cgi-bin/check_net.sh", {
const response = await fetch("/cgi-bin/home/check_net.sh", {
method: "GET",
headers: {
"Content-Type": "application/json",