fixed file dir locations
This commit is contained in:
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
|
||||||
function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
|
|
||||||
|
|
||||||
if [ "${QUERY_STRING}" ]; then
|
|
||||||
export IFS="&"
|
|
||||||
for cmd in ${QUERY_STRING}; do
|
|
||||||
if [ "$(echo $cmd | grep '=')" ]; then
|
|
||||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
|
||||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
|
||||||
eval $key=$value
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
MYATCMD=$(printf '%b\n' "${atcmd//%/\\x}")
|
|
||||||
if [ -n "${MYATCMD}" ]; then
|
|
||||||
x=$(urldecode "$atcmd")
|
|
||||||
# Initialize wait time to 200 ms
|
|
||||||
wait_time=200
|
|
||||||
while true; do
|
|
||||||
runcmd=$(echo -en "$x\r\n" | microcom -t $wait_time /dev/ttyOUT2)
|
|
||||||
# Check if "OK" or "ERROR" is present in the response
|
|
||||||
if [[ $runcmd =~ "OK" ]] || [[ $runcmd =~ "ERROR" ]]; then
|
|
||||||
break # Exit the loop if "OK" or "ERROR" is found
|
|
||||||
fi
|
|
||||||
# If neither "OK" nor "ERROR" is found, increment wait time by 1 second
|
|
||||||
((wait_time++))
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Content-type: text/plain"
|
|
||||||
echo $x
|
|
||||||
echo ""
|
|
||||||
echo $runcmd
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# This script will ping 8.8.8.8 and return the result
|
|
||||||
# If the ping is successful, it will return "OK"
|
|
||||||
# If the ping fails, it will return "ERROR"
|
|
||||||
|
|
||||||
# Send the ping command and store the output
|
|
||||||
ping_output=$(ping -c 1 8.8.8.8)
|
|
||||||
|
|
||||||
# Check if the output contains "0% packet loss"
|
|
||||||
if echo "$ping_output" | grep -q "0% packet loss"; then
|
|
||||||
echo "Content-type: text/plain"
|
|
||||||
echo ""
|
|
||||||
echo "OK"
|
|
||||||
else
|
|
||||||
echo "Content-type: text/plain"
|
|
||||||
echo ""
|
|
||||||
echo "ERROR"
|
|
||||||
fi
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# This is a simple scrip that fetches the SMS messages from the device
|
|
||||||
SMS_MESSAGE_INDICATION="AT+CNMI=2,1"
|
|
||||||
SMS_FORMAT="AT+CMGF=1"
|
|
||||||
SMS_LIST="AT+CMGL=\"ALL\""
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
runcmd=$(echo -en "$SMS_LIST\r\n" | microcom -t 2000 /dev/ttyOUT2)
|
|
||||||
if [[ $runcmd =~ "OK" ]] || [[ $runcmd =~ "ERROR" ]]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((wait_time++))
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
# Print the list of SMS messages as JSON plain text
|
|
||||||
echo "Content-type: text/plain"
|
|
||||||
echo ""
|
|
||||||
echo $runcmd
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Check iptables for ttlvalue
|
|
||||||
ttlvalue=$(iptables -t mangle -vnL | awk '/TTL/ {print $13; exit}')
|
|
||||||
ttlenabled=true;
|
|
||||||
|
|
||||||
# Set Variables
|
|
||||||
if [ -z "${ttlvalue}" ]; then
|
|
||||||
ttlvalue=0
|
|
||||||
ttlenabled=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Content-type: text/json"
|
|
||||||
echo ""
|
|
||||||
cat <<EOT
|
|
||||||
{
|
|
||||||
"isEnabled": $ttlenabled,
|
|
||||||
"ttl": $ttlvalue
|
|
||||||
}
|
|
||||||
EOT
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
|
||||||
function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
|
|
||||||
|
|
||||||
if [ "${QUERY_STRING}" ]; then
|
|
||||||
export IFS="&"
|
|
||||||
for cmd in ${QUERY_STRING}; do
|
|
||||||
if [ "$(echo $cmd | grep '=')" ]; then
|
|
||||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
|
||||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
|
||||||
eval $key=$value
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract phone number and message from inputs
|
|
||||||
phone_number="$number"
|
|
||||||
message="$msg"
|
|
||||||
|
|
||||||
# Prepare AT command with phone number and message
|
|
||||||
ATCMD="AT+CMGS=\"$phone_number\""
|
|
||||||
|
|
||||||
MYATCMD=$(printf '%b\n' "${ATCMD//%/\\x}")
|
|
||||||
if [ -n "${MYATCMD}" ]; then
|
|
||||||
x=$(urldecode "$ATCMD")
|
|
||||||
# Send the AT command to initiate message sending
|
|
||||||
echo -en "$x\r\n" | microcom /dev/ttyOUT2
|
|
||||||
# Wait for a brief moment (assuming the message sending is instantaneous)
|
|
||||||
sleep 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Send the message
|
|
||||||
echo -en "$message\c"
|
|
||||||
|
|
||||||
# Send Ctrl+Z to terminate the message
|
|
||||||
echo -en "\032"
|
|
||||||
|
|
||||||
# Ensure microcom reads the response (assuming microcom will show response instantly)
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
# Capture and output the response
|
|
||||||
runcmd=$(microcom /dev/ttyOUT2)
|
|
||||||
echo "Content-type: text/plain"
|
|
||||||
echo "$runcmd"
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Get query
|
|
||||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
|
||||||
|
|
||||||
if [ "${QUERY_STRING}" ]; then
|
|
||||||
|
|
||||||
export IFS="&"
|
|
||||||
for cmd in ${QUERY_STRING}; do
|
|
||||||
|
|
||||||
if [ "$(echo $cmd | grep '=')" ]; then
|
|
||||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
|
||||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
|
||||||
eval $key=$value
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
setTTL=$(printf '%b\n' "${ttlvalue//%/\\x}")
|
|
||||||
|
|
||||||
if [ -n "${setTTL}" ]; then
|
|
||||||
# Stop Service To Remove Rules
|
|
||||||
/usrdata/simplefirewall/ttl-override stop
|
|
||||||
|
|
||||||
# Check iptables is still set
|
|
||||||
ttlcheck=$(iptables -t mangle -vnL | grep TTL | awk '{print $13}')
|
|
||||||
|
|
||||||
# If TTL is still set manually remove values
|
|
||||||
if [ !-z "${ttlcheck}" ]; then
|
|
||||||
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set ${ttlcheck} &>/dev/null || true
|
|
||||||
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set ${ttlcheck} &>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Echo TTL to file
|
|
||||||
echo $setTTL > /usrdata/simplefirewall/ttlvalue
|
|
||||||
|
|
||||||
# Set Start Service
|
|
||||||
/usrdata/simplefirewall/ttl-override start
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Check iptables for ttlvalue
|
|
||||||
ttlvalue=$(iptables -t mangle -vnL | grep TTL | awk '{print $13}')
|
|
||||||
ttlenabled=true;
|
|
||||||
|
|
||||||
# Set Variables
|
|
||||||
if [ -z "${ttlvalue}" ]; then
|
|
||||||
ttlvalue=0
|
|
||||||
ttlenabled=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Content-type: text/json"
|
|
||||||
echo ""
|
|
||||||
cat <<EOT
|
|
||||||
{
|
|
||||||
"isEnabled": $ttlenabled,
|
|
||||||
"ttl": $ttlvalue
|
|
||||||
}
|
|
||||||
6
simpleadmin/css/bootstrap.min.css
vendored
6
simpleadmin/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,95 +0,0 @@
|
|||||||
/* import poppins */
|
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
|
|
||||||
|
|
||||||
/* import fontawesome icons */
|
|
||||||
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css");
|
|
||||||
|
|
||||||
* {
|
|
||||||
font-family: "Poppins", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-checkbox .form-check-input {
|
|
||||||
margin-right: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-modal {
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 3rem;
|
|
||||||
border-radius: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
border: 3px dotted #000;
|
|
||||||
border-style: solid solid dotted dotted;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
animation: rotation 2s linear infinite;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader::after {
|
|
||||||
content: "";
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
border: 3px dotted #0b5ed7;
|
|
||||||
border-style: solid solid dotted;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: rotationBack 1s linear infinite;
|
|
||||||
transform-origin: center center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotation {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes rotationBack {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(-360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-warning {
|
|
||||||
background-color: #ffb70f !important;
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-medium {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
@@ -1,358 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" data-bs-theme="light">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
<!-- <link
|
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/> -->
|
|
||||||
<!-- Import all the bootstrap css files from css folder -->
|
|
||||||
<link rel="stylesheet" href="/css/styles.css" />
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
|
||||||
|
|
||||||
<!-- Import BootStrap Javascript -->
|
|
||||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div class="container my-4" x-data="fetchDeviceInfo()">
|
|
||||||
<nav class="navbar navbar-expand-lg mt-2">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="/"
|
|
||||||
><span class="mb-0 h4">Simple Admin</span></a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="navbar-toggler"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#navbarText"
|
|
||||||
aria-controls="navbarText"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarText">
|
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/">Home</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a
|
|
||||||
class="nav-link active"
|
|
||||||
href="/deviceinfo.html"
|
|
||||||
aria-current="page"
|
|
||||||
>Device Information</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<span class="navbar-text">
|
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
|
||||||
Dark Mode
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="row mt-5 gap-3">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">Device Information</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-text">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Manufacturer</th>
|
|
||||||
<td x-text="manufacturer"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Model Name</th>
|
|
||||||
<td x-text="modelName"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Firmware version</th>
|
|
||||||
<td class="col-md-2" x-text="firmwareVersion"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">IMSI</th>
|
|
||||||
<td class="col-md-2" x-text="imsi"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">ICCID</th>
|
|
||||||
<td class="col-md-2" x-text="iccid"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">IMEI</th>
|
|
||||||
<td class="col-md-2">
|
|
||||||
<input
|
|
||||||
class="form-control"
|
|
||||||
type="text"
|
|
||||||
x-model="newImei"
|
|
||||||
x-bind:placeholder="imei === '-' ? 'Fetching IMEI...' : imei"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="openModal()"
|
|
||||||
>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th scope="row">LAN IP</th>
|
|
||||||
<td class="col-md-2" x-text="lanIp"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">WWAN IPv<sup>4</sup></th>
|
|
||||||
<td class="col-md-2" x-text="wwanIpv4"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">WWAN IPv<sup>6</sup></th>
|
|
||||||
<td class="col-md-2" x-text="wwanIpv6"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Simple Admin Version</th>
|
|
||||||
<td class="col-md-2">SimpleAdminRev-Alpha-0.3</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
Visit our
|
|
||||||
<a
|
|
||||||
href="https://github.com/iamromulan/quectel-rgmii-toolkit.gits"
|
|
||||||
target="_blank"
|
|
||||||
class="text-reset"
|
|
||||||
>repository</a
|
|
||||||
>
|
|
||||||
or
|
|
||||||
<a
|
|
||||||
href="https://github.com/iamromulan/quectel-rgmii-configuration-notes.git"
|
|
||||||
target="_blank"
|
|
||||||
class="text-reset"
|
|
||||||
>documentation</a
|
|
||||||
>
|
|
||||||
for more information. All rights reserved. 2024
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Loading Modal for Reboot -->
|
|
||||||
<div class="modal-overlay" x-show="showModal">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>This will reboot the modem.</h3>
|
|
||||||
<p style="margin-top: 0.5rem">Continue?</p>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-block">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
type="button"
|
|
||||||
@click="updateIMEI()"
|
|
||||||
>
|
|
||||||
Reboot
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-danger"
|
|
||||||
type="button"
|
|
||||||
@click="closeModal()"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Reboot Modal Countdown -->
|
|
||||||
<div class="modal-overlay" x-show="isRebooting">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="loader"></div>
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>Rebooting...</h3>
|
|
||||||
<p style="margin-top: 0.5rem">
|
|
||||||
Please wait for
|
|
||||||
<span x-text="countdown" style="font-weight: 500"></span>
|
|
||||||
seconds.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<script src="/js/dark-mode.js"></script>
|
|
||||||
<script>
|
|
||||||
function fetchDeviceInfo() {
|
|
||||||
return {
|
|
||||||
manufacturer: "-",
|
|
||||||
modelName: "-",
|
|
||||||
firmwareVersion: "-",
|
|
||||||
imsi: "-",
|
|
||||||
iccid: "-",
|
|
||||||
imei: "-",
|
|
||||||
newImei: null,
|
|
||||||
lanIp: "-",
|
|
||||||
wwanIpv4: "-",
|
|
||||||
wwanIpv6: "-",
|
|
||||||
simpleAdminVersion: "-",
|
|
||||||
atcmd: null,
|
|
||||||
atCommandResponse: "",
|
|
||||||
showModal: false,
|
|
||||||
isLoading: false,
|
|
||||||
isRebooting: false,
|
|
||||||
countdown: 3,
|
|
||||||
|
|
||||||
sendATCommand() {
|
|
||||||
if (!this.atcmd) {
|
|
||||||
// Use ATI as default command
|
|
||||||
console.log(
|
|
||||||
"AT Command is empty, using ATI as default command: "
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoading = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error: ", error);
|
|
||||||
this.showError = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchATCommand() {
|
|
||||||
this.atcmd =
|
|
||||||
'AT+CGMI;+CGMM;+QGMR;+CIMI;+ICCID;+CGSN;+QMAP="LANIP";+QMAP="WWAN"';
|
|
||||||
this.isLoading = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
this.parseFetchedData();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error: ", error);
|
|
||||||
this.showError = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
parseFetchedData() {
|
|
||||||
const lines = this.atCommandResponse.split("\n");
|
|
||||||
|
|
||||||
console.log("AT Command Response: ", lines);
|
|
||||||
|
|
||||||
this.manufacturer = lines[1].trim();
|
|
||||||
this.modelName = lines[3].trim();
|
|
||||||
this.firmwareVersion = lines[5].trim();
|
|
||||||
this.imsi = lines[7].trim();
|
|
||||||
this.iccid = lines[9].trim().replace("+ICCID: ", "");
|
|
||||||
this.imei = lines[11].trim();
|
|
||||||
this.lanIp = lines[13].trim().split(",")[3];
|
|
||||||
this.wwanIpv4 = lines[15].trim().split(",")[4].replace(/"/g, "");
|
|
||||||
this.wwanIpv6 = lines[16].trim().split(",")[4].replace(/"/g, "");
|
|
||||||
this.simpleAdminVersion = "SimpleAdminRev-Alpha-0.5";
|
|
||||||
this.isLoading = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
updateIMEI() {
|
|
||||||
this.atcmd = `AT+EGMR=1,7,"${this.newImei}"`;
|
|
||||||
this.sendATCommand();
|
|
||||||
this.rebootDevice();
|
|
||||||
},
|
|
||||||
|
|
||||||
rebootDevice() {
|
|
||||||
this.atcmd = "AT+CFUN=1,1";
|
|
||||||
this.sendATCommand();
|
|
||||||
|
|
||||||
this.isLoading = true;
|
|
||||||
this.showModal = false;
|
|
||||||
this.isRebooting = true;
|
|
||||||
this.countdown = 40;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.isLoading = false;
|
|
||||||
this.showModal = false;
|
|
||||||
this.isRebooting = false;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
|
|
||||||
openModal() {
|
|
||||||
if (!this.newImei) {
|
|
||||||
alert("No new IMEI provided.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.newImei.length !== 15) {
|
|
||||||
alert("IMEI is invalid");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.newImei === this.imei) {
|
|
||||||
alert("IMEI is the same as the current IMEI");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showModal = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
closeModal() {
|
|
||||||
this.showModal = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.fetchATCommand();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because it is too large
Load Diff
5
simpleadmin/js/alpinejs.min.js
vendored
5
simpleadmin/js/alpinejs.min.js
vendored
File diff suppressed because one or more lines are too long
7
simpleadmin/js/bootstrap.bundle.min.js
vendored
7
simpleadmin/js/bootstrap.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,29 +0,0 @@
|
|||||||
// Function to toggle dark mode
|
|
||||||
const toggleDarkMode = () => {
|
|
||||||
const html = document.querySelector('html');
|
|
||||||
const currentTheme = html.getAttribute('data-bs-theme');
|
|
||||||
|
|
||||||
if (currentTheme === 'dark') {
|
|
||||||
html.removeAttribute('data-bs-theme');
|
|
||||||
darkModeToggle.textContent = 'Dark Mode';
|
|
||||||
localStorage.setItem('theme', 'light'); // Store the theme in localStorage
|
|
||||||
} else {
|
|
||||||
html.setAttribute('data-bs-theme', 'dark');
|
|
||||||
darkModeToggle.textContent = 'Light Mode';
|
|
||||||
localStorage.setItem('theme', 'dark'); // Store the theme in localStorage
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const darkModeToggle = document.getElementById('darkModeToggle');
|
|
||||||
|
|
||||||
// Check if theme preference is stored in localStorage
|
|
||||||
const storedTheme = localStorage.getItem('theme');
|
|
||||||
if (storedTheme) {
|
|
||||||
const html = document.querySelector('html');
|
|
||||||
html.setAttribute('data-bs-theme', storedTheme);
|
|
||||||
if (storedTheme === 'dark') {
|
|
||||||
darkModeToggle.textContent = 'Light Mode';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
darkModeToggle.addEventListener('click', toggleDarkMode);
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
const freqNumbersContainer = document.getElementById(
|
|
||||||
"freqNumbersContainer"
|
|
||||||
);
|
|
||||||
|
|
||||||
function generateFreqNumberInputs(num) {
|
|
||||||
let html = "";
|
|
||||||
const maxFields = Math.min(num, 10); // Limit to a maximum of 10 fields
|
|
||||||
for (let i = 1; i <= maxFields; i++) {
|
|
||||||
html += `
|
|
||||||
<div class="input-group mb-3" x-show="cellNum >= ${i} && networkModeCell == 'LTE'">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
aria-label="EARFCN"
|
|
||||||
placeholder="EARFCN"
|
|
||||||
class="form-control"
|
|
||||||
x-model="earfcn${i}"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
aria-label="PCI"
|
|
||||||
placeholder="PCI"
|
|
||||||
class="form-control"
|
|
||||||
x-model="pci${i}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
const cellNumInput = document.querySelector("[aria-label='NumCells']");
|
|
||||||
cellNumInput.addEventListener("input", function () {
|
|
||||||
const cellNum = parseInt(this.value);
|
|
||||||
freqNumbersContainer.innerHTML = generateFreqNumberInputs(cellNum);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
function parseCurrentSettings(rawdata) {
|
|
||||||
const data = rawdata;
|
|
||||||
|
|
||||||
const lines = data.split("\n");
|
|
||||||
console.log(lines);
|
|
||||||
|
|
||||||
// Remove QUIMSLOT and only take 1 or 2
|
|
||||||
this.sim = lines[1].split(":")[1].trim();
|
|
||||||
this.apn = lines[3].split(",")[2].replace(/\"/g, "");
|
|
||||||
this.cellLock4GStatus = lines[5].split(",")[1].replace(/\"/g, "");
|
|
||||||
this.cellLock5GStatus = lines[7].split(",")[1].replace(/\"/g, "");
|
|
||||||
this.prefNetwork = lines[9].split(",")[1].replace(/\"/g, "");
|
|
||||||
this.nrModeControlStatus = lines[11].split(",")[1].replace(/\"/g, "");
|
|
||||||
|
|
||||||
|
|
||||||
let bands = [];
|
|
||||||
|
|
||||||
// Append the values if there is separated by comma with a space.
|
|
||||||
// i.e. LTE BAND 3, LTE BAND 1
|
|
||||||
for (let i = 13; i < 17; i++) {
|
|
||||||
if (lines[i].split(",").length > 1) {
|
|
||||||
bands.push(lines[i].split(",")[3].replace(/\"/g, " "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bands = bands;
|
|
||||||
|
|
||||||
|
|
||||||
if (this.cellLock4GStatus == 1 && this.cellLock5GStatus == 1) {
|
|
||||||
this.cellLockStatus = "Locked to 4G and 5G";
|
|
||||||
} else if (this.cellLock4GStatus == 1) {
|
|
||||||
this.cellLockStatus = "Locked to 4G";
|
|
||||||
}
|
|
||||||
else if (this.cellLock5GStatus == 1) {
|
|
||||||
this.cellLockStatus = "Locked to 5G";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.cellLockStatus = "Not Locked";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.nrModeControlStatus == 0) {
|
|
||||||
this.nrModeControlStatus = "Not Disabled";
|
|
||||||
}
|
|
||||||
else if (this.nrModeControlStatus == 1) {
|
|
||||||
this.nrModeControlStatus = "SA Disabled";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.nrModeControlStatus = "NSA Disabled";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
sim: sim,
|
|
||||||
apn: apn,
|
|
||||||
cellLockStatus: cellLockStatus,
|
|
||||||
prefNetwork: prefNetwork,
|
|
||||||
nrModeControl: nrModeControlStatus,
|
|
||||||
bands: bands
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
function populateCheckboxes(lte_band, nsa_nr5g_band, nr5g_band, locked_lte_bands, locked_nsa_bands, locked_sa_bands, cellLock) {
|
|
||||||
var checkboxesForm = document.getElementById("checkboxForm");
|
|
||||||
var selectedMode = document.getElementById("networkModeBand").value;
|
|
||||||
var bands;
|
|
||||||
|
|
||||||
// Determine bands based on selected network mode
|
|
||||||
if (selectedMode === "LTE") {
|
|
||||||
bands = lte_band;
|
|
||||||
} else if (selectedMode === "NSA") {
|
|
||||||
bands = nsa_nr5g_band;
|
|
||||||
} else if (selectedMode === "SA") {
|
|
||||||
bands = nr5g_band;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkboxesForm.innerHTML = ""; // Clear existing checkboxes
|
|
||||||
|
|
||||||
var bandsArray;
|
|
||||||
if (bands !== null) {
|
|
||||||
bandsArray = bands.split(":");
|
|
||||||
bandsArray.forEach(function(band, index) {
|
|
||||||
if (index % 5 === 0) {
|
|
||||||
currentRow = document.createElement("div");
|
|
||||||
currentRow.className = "row mb-2 mx-auto"; // Add margin bottom for spacing
|
|
||||||
checkboxesForm.appendChild(currentRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkboxDiv = document.createElement("div");
|
|
||||||
checkboxDiv.className = "form-check form-check-reverse col-2"; // Each checkbox takes a column
|
|
||||||
var checkboxInput = document.createElement("input");
|
|
||||||
checkboxInput.className = "form-check-input";
|
|
||||||
checkboxInput.type = "checkbox";
|
|
||||||
checkboxInput.id = "inlineCheckbox" + band;
|
|
||||||
checkboxInput.value = band;
|
|
||||||
checkboxInput.autocomplete = "off";
|
|
||||||
|
|
||||||
// Store the locked bands in an array
|
|
||||||
var locked_lte_bands_array = locked_lte_bands.split(":");
|
|
||||||
var locked_nsa_bands_array = locked_nsa_bands.split(":");
|
|
||||||
var locked_sa_bands_array = locked_sa_bands.split(":");
|
|
||||||
|
|
||||||
// Check if the current band is locked
|
|
||||||
var isLocked = false;
|
|
||||||
if (selectedMode === "LTE") {
|
|
||||||
if (locked_lte_bands_array.includes(band)) {
|
|
||||||
isLocked = true;
|
|
||||||
}
|
|
||||||
} else if (selectedMode === "NSA") {
|
|
||||||
if (locked_nsa_bands_array.includes(band)) {
|
|
||||||
isLocked = true;
|
|
||||||
}
|
|
||||||
} else if (selectedMode === "SA") {
|
|
||||||
if (locked_sa_bands_array.includes(band)) {
|
|
||||||
isLocked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLocked) {
|
|
||||||
checkboxInput.checked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkboxLabel = document.createElement("label");
|
|
||||||
checkboxLabel.className = "form-check-label";
|
|
||||||
checkboxLabel.htmlFor = "inlineCheckbox" + band;
|
|
||||||
checkboxLabel.innerText = "B" + band;
|
|
||||||
|
|
||||||
checkboxDiv.appendChild(checkboxInput);
|
|
||||||
checkboxDiv.appendChild(checkboxLabel);
|
|
||||||
currentRow.appendChild(checkboxDiv);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentRow;
|
|
||||||
addCheckboxListeners(cellLock);
|
|
||||||
}
|
|
||||||
@@ -1,933 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" data-bs-theme="light">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
<!-- <link
|
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/> -->
|
|
||||||
<!-- Import all the bootstrap css files from css folder -->
|
|
||||||
<link rel="stylesheet" href="css/styles.css" />
|
|
||||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
|
||||||
|
|
||||||
<!-- Import BootStrap Javascript -->
|
|
||||||
<script src="js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="js/alpinejs.min.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div class="container my-4" x-data="cellLocking()">
|
|
||||||
<nav class="navbar navbar-expand-lg mt-2">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="/"
|
|
||||||
><span class="mb-0 h4">Simple Admin</span></a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="navbar-toggler"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#navbarText"
|
|
||||||
aria-controls="navbarText"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarText">
|
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/">Home</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a
|
|
||||||
class="nav-link active"
|
|
||||||
href="network.html"
|
|
||||||
aria-current="page"
|
|
||||||
>Simple Network</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="deviceinfo.html"
|
|
||||||
>Device Information</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<span class="navbar-text">
|
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
|
||||||
Dark Mode
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="row mt-5 gap-3">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="row align-items-center">
|
|
||||||
<div class="col">Band Locking</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
id="networkModeBand"
|
|
||||||
aria-label="LTE"
|
|
||||||
>
|
|
||||||
<option selected value="LTE">LTE</option>
|
|
||||||
<option value="NSA">NR5G-NSA</option>
|
|
||||||
<option value="SA">NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-subtitle" x-show="isLoading">
|
|
||||||
Fetching supported bands...
|
|
||||||
</h5>
|
|
||||||
<form id="checkboxForm" x-show="isLoading === false">
|
|
||||||
<!-- Checkboxes will be populated here -->
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="col">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary m-2"
|
|
||||||
@click="lockSelectedBands()"
|
|
||||||
>
|
|
||||||
Lock Bands
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-info m-2"
|
|
||||||
id="uncheckAll"
|
|
||||||
>
|
|
||||||
Uncheck All
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-danger m-2"
|
|
||||||
@click="resetBandLocking()"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<p x-text="'Active bands: ' + bands"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row gap-3 mt-4">
|
|
||||||
<div class="col">
|
|
||||||
<form>
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">Network Utilities</div>
|
|
||||||
<div class="card-body row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="APN" class="form-label">APN</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="APN"
|
|
||||||
x-model="newApn"
|
|
||||||
aria-describedby="APN"
|
|
||||||
x-bind:placeholder="apn === '-' ? 'Fetching...' : apn"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-4 input-group grid gap-3">
|
|
||||||
<label for="SIM1" class="form-label"> Change SIM</label>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="radio"
|
|
||||||
name="inlineRadioOptions"
|
|
||||||
aria-describedby="SIM1"
|
|
||||||
id="SIM1"
|
|
||||||
value="option1"
|
|
||||||
x-bind:checked="sim === '1'"
|
|
||||||
x-on:click="newSim = '1'"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="inlineRadio1"
|
|
||||||
>1</label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="radio"
|
|
||||||
name="inlineRadioOptions"
|
|
||||||
aria-describedby="SIM2"
|
|
||||||
id="SIM2"
|
|
||||||
value="option2"
|
|
||||||
x-bind:checked="sim === '2'"
|
|
||||||
x-on:click="newSim = '2'"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="inlineRadio2"
|
|
||||||
>2</label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="nrModeControl" class="form-label"
|
|
||||||
>Select Preferred Network</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
id="prefNetworkMode"
|
|
||||||
x-model="prefNetworkMode"
|
|
||||||
aria-label="prefNetworkMode"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
selected
|
|
||||||
x-text="prefNetwork === '-' ? 'Fetching...' : 'Current: ' + prefNetwork"
|
|
||||||
></option>
|
|
||||||
<option value="AUTO">AUTO</option>
|
|
||||||
<option value="LTE">LTE Only</option>
|
|
||||||
<option value="LTE:NR5G">NR5G-NSA</option>
|
|
||||||
<option value="NR5G">NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="prefNetwork" class="form-label"
|
|
||||||
>NR5G Mode Control</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
id="nrModeControl"
|
|
||||||
x-model="nrModeControl"
|
|
||||||
aria-label="nrModeControl"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
selected
|
|
||||||
x-text="nrModeControl === '-' ? 'Fetching...' : 'Current: ' + nrModeControl"
|
|
||||||
></option>
|
|
||||||
<option value="0">Enable All</option>
|
|
||||||
<option value="2">Disable NR5G-NSA</option>
|
|
||||||
<option value="1">Disable NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="saveChanges()"
|
|
||||||
>
|
|
||||||
Save Changes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">Cell Locking</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
id="networkModeCell"
|
|
||||||
x-model="networkModeCell"
|
|
||||||
aria-label="LTE"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
selected
|
|
||||||
x-text="'Cell Lock: ' + cellLockStatus"
|
|
||||||
></option>
|
|
||||||
<option>LTE</option>
|
|
||||||
<option>NR5G-SA</option>
|
|
||||||
<option>Unlock LTE</option>
|
|
||||||
<option>Unlock NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div class="my-4">
|
|
||||||
<!-- For LTE -->
|
|
||||||
<div id="lteElementsCell" x-show="networkModeCell == 'LTE'">
|
|
||||||
<div class="input-group mb-3">
|
|
||||||
<span class="input-group-text" id="basic-addon1"
|
|
||||||
>Num Cells</span
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="1-10"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
aria-label="NumCells"
|
|
||||||
aria-describedby="basic-addon1"
|
|
||||||
x-model="cellNum"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="freqNumbersContainer">
|
|
||||||
<!-- Generate EARFCN and PCI here -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- For SA -->
|
|
||||||
<div
|
|
||||||
id="saElementsCell"
|
|
||||||
x-show="networkModeCell == 'NR5G-SA'"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="input-group mb-3"
|
|
||||||
x-show="networkModeCell == 'NR5G-SA'"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
aria-label="EARFCN"
|
|
||||||
placeholder="EARFCN"
|
|
||||||
class="form-control"
|
|
||||||
x-model="earfcn1"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
aria-label="PCI"
|
|
||||||
placeholder="PCI"
|
|
||||||
class="form-control"
|
|
||||||
x-model="pci1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="input-group mb-3"
|
|
||||||
x-show="networkModeCell == 'NR5G-SA'"
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
x-model="scs"
|
|
||||||
aria-label="SCS"
|
|
||||||
>
|
|
||||||
<option selected>SCS</option>
|
|
||||||
<option>15</option>
|
|
||||||
<option>30</option>
|
|
||||||
<option>60</option>
|
|
||||||
<option>120</option>
|
|
||||||
<option>240</option>
|
|
||||||
</select>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
aria-label="band"
|
|
||||||
placeholder="Band"
|
|
||||||
class="form-control"
|
|
||||||
x-model="band"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
x-show="networkModeCell == 'LTE'"
|
|
||||||
@click="cellLockEnableLTE()"
|
|
||||||
>
|
|
||||||
Lock LTE Cells
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
x-show="networkModeCell == 'NR5G-SA'"
|
|
||||||
@click="cellLockEnableNR()"
|
|
||||||
>
|
|
||||||
Lock NR5G-SA Cells
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-danger"
|
|
||||||
x-show="networkModeCell == 'Unlock LTE'"
|
|
||||||
@click="cellLockDisableLTE()"
|
|
||||||
>
|
|
||||||
Unlock LTE Cells
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-danger"
|
|
||||||
x-show="networkModeCell == 'Unlock NR5G-SA'"
|
|
||||||
@click="cellLockDisableNR()"
|
|
||||||
>
|
|
||||||
Unlock NR5G-SA Cells
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Loading Modal for Locking Band -->
|
|
||||||
<div class="modal-overlay" x-show="showModal">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="loader"></div>
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>Initializing Network...</h3>
|
|
||||||
<p style="margin-top: 0.5rem">
|
|
||||||
Please wait for
|
|
||||||
<span x-text="countdown" style="font-weight: 500"></span>
|
|
||||||
seconds.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- Import Band Locking GUI JS -->
|
|
||||||
<!-- <script src="js/band-locking.js"></script> -->
|
|
||||||
<script src="js/generate-freq-box.js"></script>
|
|
||||||
<script src="js/populate-checkbox.js"></script>
|
|
||||||
<script src="js/parse-settings.js"></script>
|
|
||||||
<script>
|
|
||||||
function requestATInfo(atcmd) {
|
|
||||||
return fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
return data;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
// Throw the error again to ensure it's propagated
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSupportedBands() {
|
|
||||||
const atcmd = 'AT+QNWPREFCFG="policy_band"';
|
|
||||||
return requestATInfo(atcmd).then((rawdata) => {
|
|
||||||
let { lte_bands, nsa_bands, sa_bands } = parseSupportedBands(rawdata);
|
|
||||||
|
|
||||||
return {
|
|
||||||
lte_bands: lte_bands,
|
|
||||||
nsa_bands: nsa_bands,
|
|
||||||
sa_bands: sa_bands,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSupportedBands(rawdata) {
|
|
||||||
const data = rawdata;
|
|
||||||
const regex = /"([^"]+)",([0-9:]+)/g;
|
|
||||||
|
|
||||||
// Object to store the results
|
|
||||||
const bands = {};
|
|
||||||
|
|
||||||
let match;
|
|
||||||
while ((match = regex.exec(data)) !== null) {
|
|
||||||
const bandType = match[1];
|
|
||||||
const numbers = match[2].split(":").map(Number);
|
|
||||||
bands[bandType] = numbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seperate the bands for each network mode
|
|
||||||
const lte_bands = bands.lte_band.join(":");
|
|
||||||
const nsa_bands = bands.nsa_nr5g_band.join(":");
|
|
||||||
const sa_bands = bands.nr5g_band.join(":");
|
|
||||||
|
|
||||||
return {
|
|
||||||
lte_bands,
|
|
||||||
nsa_bands,
|
|
||||||
sa_bands,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseLockedBands(rawdata) {
|
|
||||||
const data = rawdata;
|
|
||||||
const regex = /"([^"]+)",([0-9:]+)/g;
|
|
||||||
|
|
||||||
// Object to store the results
|
|
||||||
const bands = {};
|
|
||||||
|
|
||||||
let match;
|
|
||||||
while ((match = regex.exec(data)) !== null) {
|
|
||||||
const bandType = match[1];
|
|
||||||
const numbers = match[2].split(":").map(Number);
|
|
||||||
bands[bandType] = numbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seperate the bands for each network mode
|
|
||||||
const locked_lte_bands = bands.lte_band.join(":");
|
|
||||||
const locked_nsa_bands = bands.nsa_nr5g_band.join(":");
|
|
||||||
const locked_sa_bands = bands.nr5g_band.join(":");
|
|
||||||
|
|
||||||
return {
|
|
||||||
locked_lte_bands,
|
|
||||||
locked_nsa_bands,
|
|
||||||
locked_sa_bands,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLockedBands() {
|
|
||||||
const atcmd =
|
|
||||||
'AT+QNWPREFCFG="lte_band";+QNWPREFCFG= "nsa_nr5g_band";+QNWPREFCFG= "nr5g_band"';
|
|
||||||
|
|
||||||
return requestATInfo(atcmd).then((rawdata) => {
|
|
||||||
const lockedBandsData = parseLockedBands(rawdata);
|
|
||||||
return lockedBandsData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCurrentSettings() {
|
|
||||||
const atcmd =
|
|
||||||
'AT+QUIMSLOT?;+CGCONTRDP=1;+QNWLOCK="common/4g";+QNWLOCK="common/5g";+QNWPREFCFG="mode_pref";+QNWPREFCFG="nr5g_disable_mode";+QCAINFO';
|
|
||||||
|
|
||||||
return requestATInfo(atcmd).then((rawdata) => {
|
|
||||||
const settings = parseCurrentSettings(rawdata);
|
|
||||||
return {
|
|
||||||
sim: settings.sim,
|
|
||||||
apn: settings.apn,
|
|
||||||
cellLockStatus: settings.cellLockStatus,
|
|
||||||
prefNetwork: settings.prefNetwork,
|
|
||||||
nrModeControl: settings.nrModeControl,
|
|
||||||
bands: settings.bands,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cellLocking() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
showModal: false,
|
|
||||||
countdown: 0,
|
|
||||||
networkModeCell: "-",
|
|
||||||
earfcn1: null,
|
|
||||||
pci1: null,
|
|
||||||
earfcn2: null,
|
|
||||||
pci2: null,
|
|
||||||
earfcn3: null,
|
|
||||||
pci3: null,
|
|
||||||
earfcn4: null,
|
|
||||||
pci4: null,
|
|
||||||
earfcn5: null,
|
|
||||||
pci5: null,
|
|
||||||
earfcn6: null,
|
|
||||||
pci6: null,
|
|
||||||
earfcn7: null,
|
|
||||||
pci7: null,
|
|
||||||
earfcn8: null,
|
|
||||||
pci8: null,
|
|
||||||
earfcn9: null,
|
|
||||||
pci9: null,
|
|
||||||
earfcn10: null,
|
|
||||||
pci10: null,
|
|
||||||
scs: null,
|
|
||||||
band: null,
|
|
||||||
apn: "-",
|
|
||||||
newApn: null,
|
|
||||||
prefNetwork: "-",
|
|
||||||
prefNetworkMode: null,
|
|
||||||
nrModeControl: "-",
|
|
||||||
cellNum: null,
|
|
||||||
lte_bands: null,
|
|
||||||
nsa_bands: null,
|
|
||||||
sa_bands: null,
|
|
||||||
locked_lte_bands: null,
|
|
||||||
locked_nsa_bands: null,
|
|
||||||
locked_sa_bands: null,
|
|
||||||
currentNetworkMode: "-",
|
|
||||||
updatedLockedBands: null,
|
|
||||||
sim: "-",
|
|
||||||
newSim: null,
|
|
||||||
cellLockStatus: "Unknown",
|
|
||||||
bands: "Fetching Bands...",
|
|
||||||
init() {
|
|
||||||
// Function to populate checkboxes
|
|
||||||
const showPopulateCheckboxes = () => {
|
|
||||||
this.isLoading = true;
|
|
||||||
Promise.all([getSupportedBands(), getLockedBands()])
|
|
||||||
.then(([supportedBandsData, lockedBandsData]) => {
|
|
||||||
this.lte_bands = supportedBandsData.lte_bands;
|
|
||||||
this.nsa_bands = supportedBandsData.nsa_bands;
|
|
||||||
this.sa_bands = supportedBandsData.sa_bands;
|
|
||||||
this.locked_lte_bands = lockedBandsData.locked_lte_bands;
|
|
||||||
this.locked_nsa_bands = lockedBandsData.locked_nsa_bands;
|
|
||||||
this.locked_sa_bands = lockedBandsData.locked_sa_bands;
|
|
||||||
|
|
||||||
// Once both promises are resolved, call populateCheckboxes
|
|
||||||
populateCheckboxes(
|
|
||||||
this.lte_bands,
|
|
||||||
this.nsa_bands,
|
|
||||||
this.sa_bands,
|
|
||||||
this.locked_lte_bands,
|
|
||||||
this.locked_nsa_bands,
|
|
||||||
this.locked_sa_bands,
|
|
||||||
this
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set isLoading to false after populating checkboxes
|
|
||||||
this.isLoading = false;
|
|
||||||
|
|
||||||
// Add event listeners to checkboxes after populating them
|
|
||||||
addCheckboxListeners(this);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
// Handle errors if any
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to track checkbox changes
|
|
||||||
this.trackCheckboxChanges = () => {
|
|
||||||
var selectedMode =
|
|
||||||
document.getElementById("networkModeBand").value;
|
|
||||||
var checkboxes = document.querySelectorAll(
|
|
||||||
'input[type="checkbox"]'
|
|
||||||
);
|
|
||||||
var newCheckedValues = [];
|
|
||||||
|
|
||||||
checkboxes.forEach(function (checkbox) {
|
|
||||||
if (checkbox.checked) {
|
|
||||||
newCheckedValues.push(checkbox.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update currentNetworkMode and updatedLockedBands
|
|
||||||
this.currentNetworkMode = selectedMode;
|
|
||||||
this.updatedLockedBands = newCheckedValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to get the current settings
|
|
||||||
const getCurrentSettingsData = () => {
|
|
||||||
getCurrentSettings().then((settings) => {
|
|
||||||
this.sim = settings.sim;
|
|
||||||
this.apn = settings.apn;
|
|
||||||
this.cellLockStatus = settings.cellLockStatus;
|
|
||||||
this.prefNetwork = settings.prefNetwork;
|
|
||||||
this.nrModeControl = settings.nrModeControl;
|
|
||||||
this.bands = settings.bands;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to add event listener to network mode dropdown
|
|
||||||
const addNetworkModeListener = () => {
|
|
||||||
document
|
|
||||||
.getElementById("networkModeBand")
|
|
||||||
.addEventListener("change", function () {
|
|
||||||
showPopulateCheckboxes(); // Update checkboxes when network mode changes
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute necessary functions on initialization
|
|
||||||
showPopulateCheckboxes();
|
|
||||||
addNetworkModeListener();
|
|
||||||
getCurrentSettingsData();
|
|
||||||
},
|
|
||||||
lockSelectedBands() {
|
|
||||||
// Get the updated this.currentNetworkMode = selectedMode; and this.updatedLockedBands = newCheckedValues;
|
|
||||||
const selectedMode = this.currentNetworkMode;
|
|
||||||
const newCheckedValues = this.updatedLockedBands;
|
|
||||||
let atcmd;
|
|
||||||
|
|
||||||
// Check if both values are null then show the error message
|
|
||||||
if (selectedMode === null || newCheckedValues === null) {
|
|
||||||
} else {
|
|
||||||
if (selectedMode === "LTE") {
|
|
||||||
atcmd = `AT+QNWPREFCFG="lte_band",${newCheckedValues.join(
|
|
||||||
":"
|
|
||||||
)}`;
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
} else if (selectedMode === "NSA") {
|
|
||||||
atcmd = `AT+QNWPREFCFG="nsa_nr5g_band",${newCheckedValues.join(
|
|
||||||
":"
|
|
||||||
)}`;
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
} else if (selectedMode === "SA") {
|
|
||||||
atcmd = `AT+QNWPREFCFG="nr5g_band",${newCheckedValues.join(
|
|
||||||
":"
|
|
||||||
)}`;
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
} else {
|
|
||||||
alert("Invalid network mode selected");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do a 5 second countdown
|
|
||||||
this.showModal = true;
|
|
||||||
this.countdown = 5;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
|
|
||||||
// Refresh the page to show the updated bands
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resetBandLocking() {
|
|
||||||
// Send the atcmd command to reset the locked bands
|
|
||||||
const atcmd = 'AT+QNWPREFCFG="restore_band"';
|
|
||||||
|
|
||||||
this.showModal = true;
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
this.countdown = 5;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
|
|
||||||
// Refresh the page to show the updated bands
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
// Run init function to repopulate the checkboxes
|
|
||||||
this.init();
|
|
||||||
},
|
|
||||||
saveChanges() {
|
|
||||||
const newApn = this.newApn;
|
|
||||||
const newSim = this.newSim;
|
|
||||||
const prefNetworkMode = this.prefNetworkMode;
|
|
||||||
const nrModeControl = this.nrModeControl;
|
|
||||||
|
|
||||||
let atAPN, atSIM, ATNetwork, ATNRMode, atcmd;
|
|
||||||
atAPN = "";
|
|
||||||
atSIM = "";
|
|
||||||
ATNetwork = "";
|
|
||||||
ATNRMode = "";
|
|
||||||
|
|
||||||
if (newApn !== null) {
|
|
||||||
atAPN = `+CGDCONT=1,"IP","${newApn}";`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newSim !== null) {
|
|
||||||
atSIM = `+QUIMSLOT=${newSim};`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefNetworkMode !== null) {
|
|
||||||
ATNetwork = `+QNWPREFCFG="mode_pref",${prefNetworkMode};`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nrModeControl !== this.nrModeControl) {
|
|
||||||
ATNRMode = `+QNWPREFCFG="nr5g_disable_mode",${nrModeControl}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
atcmd = `AT+${atAPN}${atSIM}${ATNetwork}${ATNRMode}`;
|
|
||||||
// If there is double + (++), remove 1 + from the command
|
|
||||||
atcmd = atcmd.replace("++", "+");
|
|
||||||
if (atcmd !== "AT+") {
|
|
||||||
this.showModal = true;
|
|
||||||
console.log(atcmd);
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
// Do a 15 second countdown
|
|
||||||
this.countdown = 15;
|
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
alert("No changes made");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cellLockEnableLTE() {
|
|
||||||
const cellNum = this.cellNum;
|
|
||||||
|
|
||||||
if (cellNum === null) {
|
|
||||||
alert("Please enter the number of cells to lock");
|
|
||||||
return; // Exit the function early if cellNum is null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an array to hold earfcn and pci pairs
|
|
||||||
const earfcnPciPairs = [
|
|
||||||
{ earfcn: this.earfcn1, pci: this.pci1 },
|
|
||||||
{ earfcn: this.earfcn2, pci: this.pci2 },
|
|
||||||
{ earfcn: this.earfcn3, pci: this.pci3 },
|
|
||||||
{ earfcn: this.earfcn4, pci: this.pci4 },
|
|
||||||
{ earfcn: this.earfcn5, pci: this.pci5 },
|
|
||||||
{ earfcn: this.earfcn6, pci: this.pci6 },
|
|
||||||
{ earfcn: this.earfcn7, pci: this.pci7 },
|
|
||||||
{ earfcn: this.earfcn8, pci: this.pci8 },
|
|
||||||
{ earfcn: this.earfcn9, pci: this.pci9 },
|
|
||||||
{ earfcn: this.earfcn10, pci: this.pci10 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Filter out pairs where either earfcn or pci is null
|
|
||||||
const validPairs = earfcnPciPairs.filter(
|
|
||||||
(pair) => pair.earfcn !== null && pair.pci !== null
|
|
||||||
);
|
|
||||||
|
|
||||||
if (validPairs.length === 0) {
|
|
||||||
alert("Please enter at least one valid earfcn and pci pair");
|
|
||||||
return; // Exit the function early if no valid pairs are found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the AT command using the valid pairs
|
|
||||||
let atcmd = `+QNWLOCK="common/4g",${cellNum},${validPairs
|
|
||||||
.map((pair) => `${pair.earfcn},${pair.pci}`)
|
|
||||||
.join(",")}`;
|
|
||||||
atcmd = "AT+CFUN=0;" + atcmd + ";+CFUN=1";
|
|
||||||
|
|
||||||
// Mock data
|
|
||||||
this.showModal = true;
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
// Do a 15 second countdown
|
|
||||||
this.countdown = 15;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
cellLockEnableNR() {
|
|
||||||
const earfcn = this.earfcn1;
|
|
||||||
const pci = this.pci1;
|
|
||||||
const scs = this.scs;
|
|
||||||
const band = this.band;
|
|
||||||
|
|
||||||
if (
|
|
||||||
earfcn === null ||
|
|
||||||
pci === null ||
|
|
||||||
scs === null ||
|
|
||||||
band === null
|
|
||||||
) {
|
|
||||||
alert("Please enter all the required fields");
|
|
||||||
return; // Exit the function early if any of the fields are null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the AT command using the valid pairs
|
|
||||||
let atcmd = `+QNWLOCK="common/5g",${earfcn},${pci},${scs},${band}`;
|
|
||||||
atcmd = "AT+CFUN=0;" + atcmd + ";+CFUN=1";
|
|
||||||
|
|
||||||
// Mock data
|
|
||||||
this.showModal = true;
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
// Do a 15 second countdown
|
|
||||||
this.countdown = 15;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
cellLockDisableLTE() {
|
|
||||||
// Send the atcmd command to reset the locked bands
|
|
||||||
const atcmd = 'AT+CFUN=0;+QNWLOCK="common/4g,0;+CFUN=1"';
|
|
||||||
this.showModal = true;
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
this.countdown = 15;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
cellLockDisableNR() {
|
|
||||||
// Send the atcmd command to reset the locked bands
|
|
||||||
const atcmd = 'AT+CFUN=0;+QNWLOCK="common/5g,0;+CFUN=1"';
|
|
||||||
|
|
||||||
this.showModal = true;
|
|
||||||
|
|
||||||
this.sendATcommand(atcmd);
|
|
||||||
|
|
||||||
this.countdown = 15;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.showModal = false;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
sendATcommand(atcmd) {
|
|
||||||
return fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
return data;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
// Throw the error again to ensure it's propagated
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCheckboxListeners(cellLock) {
|
|
||||||
// Remove existing event listeners
|
|
||||||
document
|
|
||||||
.querySelectorAll('input[type="checkbox"]')
|
|
||||||
.forEach(function (checkbox) {
|
|
||||||
checkbox.removeEventListener(
|
|
||||||
"change",
|
|
||||||
cellLock.trackCheckboxChanges
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add new event listeners
|
|
||||||
document
|
|
||||||
.querySelectorAll('input[type="checkbox"]')
|
|
||||||
.forEach(function (checkbox) {
|
|
||||||
checkbox.addEventListener("change", cellLock.trackCheckboxChanges);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function for unchecking all checkboxes
|
|
||||||
document
|
|
||||||
.getElementById("uncheckAll")
|
|
||||||
.addEventListener("click", function () {
|
|
||||||
document
|
|
||||||
.querySelectorAll('input[type="checkbox"]')
|
|
||||||
.forEach(function (checkbox) {
|
|
||||||
checkbox.checked = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script src="/js/dark-mode.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,667 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" data-bs-theme="light">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
<link rel="stylesheet" href="/css/styles.css" />
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
|
||||||
|
|
||||||
<!-- Import BootStrap Javascript -->
|
|
||||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div class="container my-4" x-data="simpleSettings()">
|
|
||||||
<nav class="navbar navbar-expand-lg mt-2">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="/"
|
|
||||||
><span class="mb-0 h4">Simple Admin</span></a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="navbar-toggler"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#navbarText"
|
|
||||||
aria-controls="navbarText"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarText">
|
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/">Home</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a
|
|
||||||
class="nav-link active"
|
|
||||||
href="/settings.html"
|
|
||||||
aria-current="page"
|
|
||||||
>Simple Settings</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/deviceinfo.html"
|
|
||||||
>Device Information</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<span class="navbar-text">
|
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
|
||||||
Dark Mode
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="row mt-5 mb-4">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">AT Terminal</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-text">
|
|
||||||
<div class="form-floating mb-4">
|
|
||||||
<!-- At commands output here -->
|
|
||||||
<textarea
|
|
||||||
class="form-control"
|
|
||||||
placeholder="ATI"
|
|
||||||
id="atOutputBox"
|
|
||||||
style="height: 220px"
|
|
||||||
x-text="atCommandResponse"
|
|
||||||
readonly
|
|
||||||
>
|
|
||||||
<label for="floatingTextarea">ATI</label>
|
|
||||||
</textarea>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="col-md-4 mb-3">
|
|
||||||
<label for="exampleInputEmail1" class="form-label"
|
|
||||||
>AT Command</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="atCommandInput"
|
|
||||||
placeholder="ATI"
|
|
||||||
aria-describedby="atCommandInput"
|
|
||||||
x-model="atcmd"
|
|
||||||
@keydown.enter = "sendATCommand()"
|
|
||||||
/>
|
|
||||||
<div id="atCommandInputHelper" class="form-text">
|
|
||||||
Seperate multiple commands with comma (,).
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-grid gap-2 d-md-flex justify-content-md-start"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="btn btn-primary me-md-2"
|
|
||||||
type="button"
|
|
||||||
@click="sendATCommand()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-danger"
|
|
||||||
type="button"
|
|
||||||
@click="clearResponses()"
|
|
||||||
:disabled="isClean"
|
|
||||||
>
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">One Click Utilities</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-text">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Reboot</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="showRebootModal()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Reboot
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Reset AT Commands Settings</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="resetATCommands()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">ETH IP Passthrough</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="ethPassthroughEnable()"
|
|
||||||
x-show="ethPassStatus === false"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Enable
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="ethPassthroughDisable()"
|
|
||||||
x-show="ethPassStatus === true"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Disable
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Onboard DNS Proxy</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="onBoardDNSProxyEnable()"
|
|
||||||
x-show="DNSProxyStatus === false"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Enable
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="onBoardDNSProxyDisable()"
|
|
||||||
x-show="DNSProxyStatus === true"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Disable
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">USB Mode</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="usbModeEnable()"
|
|
||||||
x-show="USBModeStatus === true"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Enable
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="usbModeDisable()"
|
|
||||||
x-show="USBModeStatus === false"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Disable
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Scan Neighbour LTE</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="scanLTE()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Scan LTE
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Scan Neighbour NSA</th>
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="scanNSA()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Scan NSA
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header">TTL and Network Scan Settings</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<label for="TTLState" class="form-label"
|
|
||||||
>TTL State and Value</label
|
|
||||||
>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div
|
|
||||||
class="p-3 text-primary-emphasis bg-primary-subtle border border-primary-subtle rounded-3"
|
|
||||||
x-show="ttlStatus === true"
|
|
||||||
>
|
|
||||||
TTL is Active
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="p-3 text-danger-emphasis bg-danger-subtle border border-danger-subtle rounded-3"
|
|
||||||
x-show="ttlStatus === false"
|
|
||||||
>
|
|
||||||
TTL is Inactive
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div
|
|
||||||
class="p-3 text-info-emphasis bg-info-subtle border border-info-subtle rounded-3 mb-4"
|
|
||||||
x-text="ttlvalue"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-text mb-3">
|
|
||||||
<div class="mb-4">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
id="ttlInput"
|
|
||||||
placeholder="TTL Value"
|
|
||||||
x-model="newTTL"
|
|
||||||
/>
|
|
||||||
<div id="ttlValueHelper" class="form-text">
|
|
||||||
Set TTL Value to 0 to disable.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
type="button"
|
|
||||||
@click="setTTL()"
|
|
||||||
>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-text">
|
|
||||||
<!-- Select Input Scan Here -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="networkScan" class="form-label"
|
|
||||||
>Network Scan</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-select"
|
|
||||||
id="networkScan"
|
|
||||||
x-model="fullScanModeType"
|
|
||||||
>
|
|
||||||
<option selected>Choose Scan Mode</option>
|
|
||||||
<option value="LTE">LTE</option>
|
|
||||||
<option value="NR5G">NR5G</option>
|
|
||||||
<option value="ALL">ALL</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
type="button"
|
|
||||||
@click="fullScanMode()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
x-text="scanStart ? 'Scanning... Please wait.' : 'Start Scan'"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Loading Modal for Reboot -->
|
|
||||||
<div class="modal-overlay" x-show="showModal">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>This will reboot the modem.</h3>
|
|
||||||
<p style="margin-top: 0.5rem">Continue?</p>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-block">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
type="button"
|
|
||||||
@click="rebootDevice()"
|
|
||||||
>
|
|
||||||
Reboot
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-danger"
|
|
||||||
type="button"
|
|
||||||
@click="closeModal()"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Reboot Modal Countdown -->
|
|
||||||
<div class="modal-overlay" x-show="isRebooting">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="loader"></div>
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>Rebooting...</h3>
|
|
||||||
<p style="margin-top: 0.5rem">
|
|
||||||
Please wait for
|
|
||||||
<span x-text="countdown" style="font-weight: 500"></span>
|
|
||||||
seconds.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<script src="/js/dark-mode.js"></script>
|
|
||||||
<script>
|
|
||||||
function simpleSettings() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
showSuccess: false,
|
|
||||||
showError: false,
|
|
||||||
isClean: true,
|
|
||||||
showModal: false,
|
|
||||||
isRebooting: false,
|
|
||||||
atcmd: "",
|
|
||||||
fetchATCommand: "",
|
|
||||||
countdown: 0,
|
|
||||||
atCommandResponse: "",
|
|
||||||
currentSettingsResponse: "",
|
|
||||||
ttldata: null,
|
|
||||||
ttlvalue: 0,
|
|
||||||
ttlStatus: false,
|
|
||||||
newTTL: null,
|
|
||||||
ethPassStatus: false,
|
|
||||||
DNSProxyStatus: true,
|
|
||||||
USBModeStatus: true,
|
|
||||||
fullScanModeType: "",
|
|
||||||
scanStart: false,
|
|
||||||
|
|
||||||
closeModal() {
|
|
||||||
this.confirmModal = false;
|
|
||||||
this.showModal = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
showRebootModal() {
|
|
||||||
this.showModal = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
sendATCommand() {
|
|
||||||
if (!this.atcmd) {
|
|
||||||
// Use ATI as default command
|
|
||||||
this.atcmd = "ATI";
|
|
||||||
console.log(
|
|
||||||
"AT Command is empty, using ATI as default command: ",
|
|
||||||
this.atcmd
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoading = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isClean = false;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error: ", error);
|
|
||||||
this.showError = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
clearResponses() {
|
|
||||||
this.atCommandResponse = "";
|
|
||||||
this.isClean = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
rebootDevice() {
|
|
||||||
this.atcmd = "AT+CFUN=1,1";
|
|
||||||
this.sendATCommand();
|
|
||||||
|
|
||||||
this.atCommandResponse = "";
|
|
||||||
this.showModal = false;
|
|
||||||
this.isRebooting = true;
|
|
||||||
this.countdown = 40;
|
|
||||||
|
|
||||||
// Do the countdown
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown === 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.isRebooting = false;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
|
|
||||||
resetATCommands() {
|
|
||||||
this.atcmd = "AT&F";
|
|
||||||
this.sendATCommand();
|
|
||||||
console.log("Resetting AT Commands");
|
|
||||||
this.atcmd = "";
|
|
||||||
this.atCommandResponse = "";
|
|
||||||
this.showRebootModal();
|
|
||||||
},
|
|
||||||
|
|
||||||
ethPassthroughEnable() {
|
|
||||||
this.atcmd = 'AT+QMAP="MPDN_RULE",0,1,0,1,1,"FF:FF:FF:FF:FF:FF"';
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
ethPassthroughDisable() {
|
|
||||||
this.atcmd = 'AT+QMAP="MPDN_RULE",0';
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
onBoardDNSProxyEnable() {
|
|
||||||
this.atcmd = 'AT+QMAP="DHCPV4DNS","enable"';
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
onBoardDNSProxyDisable() {
|
|
||||||
this.atcmd = 'AT+QMAP="DHCPV4DNS","disable"';
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
usbModeEnable() {
|
|
||||||
this.atcmd = "AT+QMAPWAC=1";
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
usbModeDisable() {
|
|
||||||
this.atcmd = "AT+QMAPWAC=0";
|
|
||||||
this.sendATCommand();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
scanLTE() {
|
|
||||||
this.atcmd = 'AT+QENG="neighbourcell"';
|
|
||||||
this.sendATCommand();
|
|
||||||
},
|
|
||||||
|
|
||||||
scanNSA() {
|
|
||||||
this.atcmd =
|
|
||||||
'AT+QNWCFG="nr5g_meas_info",1;+QNWCFG="nr5g_meas_info"';
|
|
||||||
this.sendATCommand();
|
|
||||||
},
|
|
||||||
|
|
||||||
fullScanMode() {
|
|
||||||
switch (this.fullScanModeType) {
|
|
||||||
case "LTE":
|
|
||||||
this.atcmd = "AT+QSCAN=1,1";
|
|
||||||
this.scanStart = true;
|
|
||||||
this.atCommandResponse = "Scanning all available LTE networks... This might take a while."
|
|
||||||
this.sendATCommand();
|
|
||||||
this.scanStart = false;
|
|
||||||
break;
|
|
||||||
case "NR5G":
|
|
||||||
this.atcmd = "AT+QSCAN=2,1";
|
|
||||||
this.scanStart = true;
|
|
||||||
this.atCommandResponse = "Scanning all available NR5G-SA networks... This might take a while."
|
|
||||||
this.sendATCommand();
|
|
||||||
this.scanStart = false;
|
|
||||||
break;
|
|
||||||
case "ALL":
|
|
||||||
this.atcmd = "AT+QSCAN=3,1";
|
|
||||||
this.scanStart = true;
|
|
||||||
this.atCommandResponse = "Scanning all available networks... This might take a while."
|
|
||||||
this.sendATCommand();
|
|
||||||
this.scanStart = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
alert("Select a Scan Mode First");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchCurrentSettings() {
|
|
||||||
this.fetchATCommand =
|
|
||||||
'AT+QMAP="MPDN_RULE";+QMAP="DHCPV4DNS";+QMAPWAC?';
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.fetchATCommand,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
// Set the value of currentSettingsResponse
|
|
||||||
this.currentSettingsResponse = data;
|
|
||||||
const currentData = data.split("\n");
|
|
||||||
|
|
||||||
const testEthpass = currentData[1].match(
|
|
||||||
/\+QMAP: "MPDN_rule",0,0,0,0,0/
|
|
||||||
);
|
|
||||||
|
|
||||||
if (testEthpass) {
|
|
||||||
this.ethPassStatus = false;
|
|
||||||
} else {
|
|
||||||
this.ethPassStatus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const testDNSProxy = currentData[6].match(
|
|
||||||
/\+QMAP: "DHCPV4DNS","enable"/
|
|
||||||
);
|
|
||||||
|
|
||||||
if (testDNSProxy) {
|
|
||||||
this.DNSProxyStatus = true;
|
|
||||||
} else {
|
|
||||||
this.DNSProxyStatus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const testUSBMode = currentData[8].match(/\+QMAPWAC: 1/);
|
|
||||||
|
|
||||||
if (testUSBMode) {
|
|
||||||
this.USBModeStatus = true;
|
|
||||||
} else {
|
|
||||||
this.USBModeStatus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear atcmd
|
|
||||||
this.atcmd = "";
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error: ", error);
|
|
||||||
this.showError = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchTTL() {
|
|
||||||
fetch("/cgi-bin/get_ttl_status")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
this.ttldata = data;
|
|
||||||
this.ttlStatus = this.ttldata.isEnabled;
|
|
||||||
this.ttlvalue = this.ttldata.ttl;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setTTL() {
|
|
||||||
this.isLoading = true; // Set loading state while updating TTL
|
|
||||||
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/set_ttl?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
ttlvalue: this.newTTL,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
// Once TTL is updated, fetch the updated TTL data
|
|
||||||
this.fetchTTL();
|
|
||||||
this.isLoading = false; // Set loading state back to false
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error updating TTL: ", error);
|
|
||||||
this.isLoading = false; // Ensure loading state is properly handled in case of error
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.fetchTTL();
|
|
||||||
this.fetchCurrentSettings();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" data-bs-theme="light">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
<!-- <link
|
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/> -->
|
|
||||||
<!-- Import all the bootstrap css files from css folder -->
|
|
||||||
<link rel="stylesheet" href="/css/styles.css" />
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
|
||||||
|
|
||||||
<!-- Import BootStrap Javascript -->
|
|
||||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<script src="/js/auth.js"></script>
|
|
||||||
</head>
|
|
||||||
<body onload="isAuthenticated()">
|
|
||||||
<main>
|
|
||||||
<div class="container my-4" x-data="fetchSMS()">
|
|
||||||
<nav class="navbar navbar-expand-lg mt-2">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="/"
|
|
||||||
><span class="mb-0 h4">Simple Admin</span></a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="navbar-toggler"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#navbarText"
|
|
||||||
aria-controls="navbarText"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarText">
|
|
||||||
<ul class="navbar-nav me-auto mb-2 ml-4 mb-lg-0">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/">Home</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a
|
|
||||||
class="nav-link active"
|
|
||||||
href="/sms.html"
|
|
||||||
aria-current="page"
|
|
||||||
>SMS</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/deviceinfo.html"
|
|
||||||
>Device Information</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<span class="navbar-text">
|
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
|
||||||
Dark Mode
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="row mt-5 mb-4">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">SMS Manager</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-text">
|
|
||||||
<div class="col">
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
max-height: 400px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<table class="table table-hover border-success">
|
|
||||||
<tbody>
|
|
||||||
<div class="card-subtitle" x-show="isLoading">
|
|
||||||
<h4>Fetching SMS...</h4>
|
|
||||||
</div>
|
|
||||||
<!-- Only show template if isLoading is False -->
|
|
||||||
<template x-if="messages.length === 0 && isLoading === false" >
|
|
||||||
<div>
|
|
||||||
<p>Message Empty</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
x-for="(message, index) in messages"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<tr class="">
|
|
||||||
<td>
|
|
||||||
<div class="row column-gap-1 mb-2">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<p x-text="'Sender: ' + senders[index]"></p>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<p
|
|
||||||
x-text="'Date and Time: ' + dates[index]"
|
|
||||||
></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-9">
|
|
||||||
<p x-text="message"></p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form>
|
|
||||||
<div class="col-md-4 my-4">
|
|
||||||
<label for="PhoneNumber" class="form-label"
|
|
||||||
>Send SMS</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="Phone Number"
|
|
||||||
aria-label="Phone Number"
|
|
||||||
x-model="phoneNumber"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8 mb-3">
|
|
||||||
<!-- Text Area Here for SMS Input -->
|
|
||||||
<textarea
|
|
||||||
class="form-control"
|
|
||||||
id="smsInputBox"
|
|
||||||
rows="5"
|
|
||||||
placeholder="Enter SMS here (!!!CURRENTLY UNDER DEVELOPMENT!!!)"
|
|
||||||
x-model="messageToSend"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-grid gap-2 d-md-flex justify-content-md-start"
|
|
||||||
>
|
|
||||||
<button class="btn btn-primary me-md-2" type="button" @click="sendSMS()" :disabled="true" >
|
|
||||||
Send SMS
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-success"
|
|
||||||
type="button"
|
|
||||||
@click="init()"
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-danger"
|
|
||||||
type="button"
|
|
||||||
@click="deleteAllSMS()"
|
|
||||||
>
|
|
||||||
Delete All SMS
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<script src="/js/dark-mode.js"></script>
|
|
||||||
<script>
|
|
||||||
function fetchSMS() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
atCommandResponse: "",
|
|
||||||
messageToSend: "",
|
|
||||||
phoneNumber: "",
|
|
||||||
messages: [],
|
|
||||||
senders: [],
|
|
||||||
dates: [],
|
|
||||||
requestSMS() {
|
|
||||||
this.isLoading = true;
|
|
||||||
this.atCommandResponse = "Loading...";
|
|
||||||
// Expect a text response from the server
|
|
||||||
fetch("/cgi-bin/get_sms")
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
this.isLoading = false;
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.parseSMSData(this.atCommandResponse);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
parseSMSData(data) {
|
|
||||||
const cmglRegex =
|
|
||||||
/^\s*\+CMGL:\s*(\d+),"[^"]*","([^"]*)"[^"]*,"([^"]*)"/gm;
|
|
||||||
|
|
||||||
let match;
|
|
||||||
while ((match = cmglRegex.exec(data)) !== null) {
|
|
||||||
const index = parseInt(match[1]);
|
|
||||||
const sender = match[2];
|
|
||||||
let date = match[3];
|
|
||||||
|
|
||||||
// remove +32 from the date
|
|
||||||
date = date.replace("+32", "");
|
|
||||||
|
|
||||||
// Find the start and end positions of the message
|
|
||||||
const startIndex = cmglRegex.lastIndex;
|
|
||||||
let endIndex = data.indexOf("+CMGL:", startIndex + 1);
|
|
||||||
if (endIndex === -1) {
|
|
||||||
// If no more +CMGL lines, set end index to end of string
|
|
||||||
endIndex = data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the message from start to end index
|
|
||||||
const message = data.substring(startIndex, endIndex).trim();
|
|
||||||
|
|
||||||
this.messages.push(message);
|
|
||||||
this.senders.push(sender);
|
|
||||||
this.dates.push(date);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteAllSMS() {
|
|
||||||
const atcmd = "AT+CMGD=,4";
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.requestSMS();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
sendSMS() {
|
|
||||||
this.isLoading = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/send_sms?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
phone_number: this.phoneNumber,
|
|
||||||
message: this.messageToSend,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
this.requestSMS();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
init() {
|
|
||||||
// Send AT+CMGF=1 once to set the modem to text mode
|
|
||||||
const atcmd = "AT+CMGF=1";
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((data) => {
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.requestSMS();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -16,8 +16,8 @@ fi
|
|||||||
MYATCMD=$(printf '%b\n' "${atcmd//%/\\x}")
|
MYATCMD=$(printf '%b\n' "${atcmd//%/\\x}")
|
||||||
if [ -n "${MYATCMD}" ]; then
|
if [ -n "${MYATCMD}" ]; then
|
||||||
x=$(urldecode "$atcmd")
|
x=$(urldecode "$atcmd")
|
||||||
# Initialize wait time to 1 second
|
# Initialize wait time to 200 ms
|
||||||
wait_time=1000
|
wait_time=200
|
||||||
while true; do
|
while true; do
|
||||||
runcmd=$(echo -en "$x\r\n" | microcom -t $wait_time /dev/ttyOUT2)
|
runcmd=$(echo -en "$x\r\n" | microcom -t $wait_time /dev/ttyOUT2)
|
||||||
# Check if "OK" or "ERROR" is present in the response
|
# Check if "OK" or "ERROR" is present in the response
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Check iptables for ttlvalue
|
# Check iptables for ttlvalue
|
||||||
ttlvalue=$(/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -vnL | grep TTL | awk '{print $13}' | head -n1)
|
ttlvalue=$(iptables -t mangle -vnL | awk '/TTL/ {print $13; exit}')
|
||||||
ttlenabled=true;
|
ttlenabled=true;
|
||||||
|
|
||||||
# Set Variables
|
# Set Variables
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
PATH=/bin:/usr/sbin:/usr/bin:/sbin:/opt/sbin:/opt/bin:/usrdata/root/bin
|
|
||||||
# Get query
|
# Get query
|
||||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||||
|
|
||||||
@@ -22,28 +22,28 @@ setTTL=$(printf '%b\n' "${ttlvalue//%/\\x}")
|
|||||||
|
|
||||||
if [ -n "${setTTL}" ]; then
|
if [ -n "${setTTL}" ]; then
|
||||||
# Stop Service To Remove Rules
|
# Stop Service To Remove Rules
|
||||||
/opt/bin/sudo /usrdata/simplefirewall/ttl-override stop
|
/usrdata/simplefirewall/ttl-override stop
|
||||||
|
|
||||||
# Check iptables is still set
|
# Check iptables is still set
|
||||||
ttlcheck=$(/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -vnL | grep TTL | awk '{print $13}')
|
ttlcheck=$(iptables -t mangle -vnL | grep TTL | awk '{print $13}')
|
||||||
|
|
||||||
# If TTL is still set manually remove values
|
# If TTL is still set manually remove values
|
||||||
if [ !-z "${ttlcheck}" ]; then
|
if [ !-z "${ttlcheck}" ]; then
|
||||||
/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set ${ttlcheck} &>/dev/null || true
|
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set ${ttlcheck} &>/dev/null || true
|
||||||
/opt/bin/sudo /usr/sbin/ip6tables -w 5 -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set ${ttlcheck} &>/dev/null || true
|
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set ${ttlcheck} &>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Echo TTL to file
|
# Echo TTL to file
|
||||||
echo $setTTL > /usrdata/simplefirewall/ttlvalue
|
echo $setTTL > /usrdata/simplefirewall/ttlvalue
|
||||||
|
|
||||||
# Set Start Service
|
# Set Start Service
|
||||||
/opt/bin/sudo /usrdata/simplefirewall/ttl-override start
|
/usrdata/simplefirewall/ttl-override start
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Check iptables for ttlvalue
|
# Check iptables for ttlvalue
|
||||||
ttlvalue=$(/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -vnL | grep TTL | awk '{print $13}')
|
ttlvalue=$(iptables -t mangle -vnL | grep TTL | awk '{print $13}')
|
||||||
ttlenabled=true;
|
ttlenabled=true;
|
||||||
|
|
||||||
# Set Variables
|
# Set Variables
|
||||||
@@ -59,4 +59,3 @@ cat <<EOT
|
|||||||
"isEnabled": $ttlenabled,
|
"isEnabled": $ttlenabled,
|
||||||
"ttl": $ttlvalue
|
"ttl": $ttlvalue
|
||||||
}
|
}
|
||||||
EOT
|
|
||||||
|
|||||||
@@ -52,17 +52,18 @@
|
|||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
<a class="nav-link" href="/sms.html">SMS</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/console">Console</a>
|
<a
|
||||||
</li>
|
class="nav-link active"
|
||||||
<li class="nav-item">
|
href="/deviceinfo.html"
|
||||||
<a class="nav-link active" href="/deviceinfo.html" aria-current="page" >Device Information</a>
|
aria-current="page"
|
||||||
|
>Device Information</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
|
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||||
</span>
|
Dark Mode
|
||||||
<span class="navbar-text">
|
</button>
|
||||||
<button class="btn btn-link" href="logout.html">Log Out</button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,7 +40,9 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarText">
|
<div class="collapse navbar-collapse" id="navbarText">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
<a class="nav-link active" aria-current="page" href="/"
|
||||||
|
>Home</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="network.html">Simple Network</a>
|
<a class="nav-link" href="network.html">Simple Network</a>
|
||||||
@@ -52,17 +54,15 @@
|
|||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
<a class="nav-link" href="/sms.html">SMS</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/console">Console</a>
|
<a class="nav-link" href="/deviceinfo.html"
|
||||||
</li>
|
>Device Information</a
|
||||||
<li class="nav-item">
|
>
|
||||||
<a class="nav-link" href="/deviceinfo.html">Device Information</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
|
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||||
</span>
|
Dark Mode
|
||||||
<span class="navbar-text">
|
</button>
|
||||||
<button class="btn btn-link" href="logout.html">Log Out</button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -272,7 +272,6 @@
|
|||||||
}
|
}
|
||||||
} }"
|
} }"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
x-show="rsrqLTE != '-'"
|
x-show="rsrqLTE != '-'"
|
||||||
class="progress w-100"
|
class="progress w-100"
|
||||||
@@ -287,7 +286,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + rsrqLTEPercentage + '%'"
|
:style="'width: ' + rsrqLTEPercentage + '%'"
|
||||||
>
|
>
|
||||||
<span x-text="rsrqLTE + ' / ' + rsrqLTEPercentage + '%'"></span>
|
<span
|
||||||
|
x-text="rsrqLTE + ' / ' + rsrqLTEPercentage + '%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -322,7 +323,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + rsrqNRPercentage + '%'"
|
:style="'width: ' + rsrqNRPercentage + '%'"
|
||||||
>
|
>
|
||||||
<span x-text="rsrqNR + ' / ' + rsrqNRPercentage + '%'"></span>
|
<span
|
||||||
|
x-text="rsrqNR + ' / ' + rsrqNRPercentage + '%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -360,7 +363,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + rsrpLTEPercentage + '%'"
|
:style="'width: ' + rsrpLTEPercentage + '%'"
|
||||||
>
|
>
|
||||||
<span x-text="rsrpLTE + ' / ' + rsrpLTEPercentage + '%'"></span>
|
<span
|
||||||
|
x-text="rsrpLTE + ' / ' + rsrpLTEPercentage + '%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -398,7 +403,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + rsrpNRPercentage + '%'"
|
:style="'width: ' + rsrpNRPercentage + '%'"
|
||||||
>
|
>
|
||||||
<span x-text="rsrpNR + ' / ' + rsrpNRPercentage + '%'"></span>
|
<span
|
||||||
|
x-text="rsrpNR + ' / ' + rsrpNRPercentage + '%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -436,7 +443,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + sinrLTEPercentage +'%'"
|
:style="'width: ' + sinrLTEPercentage +'%'"
|
||||||
>
|
>
|
||||||
<span x-text="sinrLTE + ' / ' + sinrLTEPercentage +'%'"></span>
|
<span
|
||||||
|
x-text="sinrLTE + ' / ' + sinrLTEPercentage +'%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -474,7 +483,9 @@
|
|||||||
:class="getProgressBarClass()"
|
:class="getProgressBarClass()"
|
||||||
:style="'width: ' + sinrNRPercentage +'%'"
|
:style="'width: ' + sinrNRPercentage +'%'"
|
||||||
>
|
>
|
||||||
<span x-text="sinrNR + ' / ' + sinrNRPercentage +'%'"></span>
|
<span
|
||||||
|
x-text="sinrNR + ' / ' + sinrNRPercentage +'%'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -543,7 +554,7 @@
|
|||||||
internetConnection: "Disconnected",
|
internetConnection: "Disconnected",
|
||||||
lastUpdate: new Date().toLocaleString(),
|
lastUpdate: new Date().toLocaleString(),
|
||||||
newRefreshRate: null,
|
newRefreshRate: null,
|
||||||
refreshRate: 3,
|
refreshRate: 30,
|
||||||
intervalId: null,
|
intervalId: null,
|
||||||
fetchNetworkInfo() {
|
fetchNetworkInfo() {
|
||||||
this.atcmd =
|
this.atcmd =
|
||||||
@@ -607,9 +618,25 @@
|
|||||||
if (networkMode1 === '"NR5G-SA"') {
|
if (networkMode1 === '"NR5G-SA"') {
|
||||||
this.network_mode = networkMode1;
|
this.network_mode = networkMode1;
|
||||||
this.network_mode = this.network_mode.replace(/"/g, "");
|
this.network_mode = this.network_mode.replace(/"/g, "");
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
let networkMode2, networkMode3;
|
let networkMode2, networkMode3;
|
||||||
|
|
||||||
|
if (
|
||||||
|
lines[27] !== undefined &&
|
||||||
|
lines[27] !== "OK" &&
|
||||||
|
lines[27] !== "" &&
|
||||||
|
lines[27] !== "/r"
|
||||||
|
) {
|
||||||
|
// Check if lines[27] doesnt have TDD or FDD
|
||||||
|
if (lines[27].match(/FDD/) != null || lines[27].match(/TDD/) != null) {
|
||||||
|
networkMode2 = lines[27].split(",")[2].replace(/"/g, "");
|
||||||
|
networkMode2 = networkMode2.split(",")[0].trim();
|
||||||
|
console.log(networkMode2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (networkMode2 !== "LTE") {
|
||||||
networkMode2 = lines[28].split(":")[1].replace(/"/g, "");
|
networkMode2 = lines[28].split(":")[1].replace(/"/g, "");
|
||||||
networkMode2 = networkMode2.split(",")[0];
|
networkMode2 = networkMode2.split(",")[0];
|
||||||
|
|
||||||
@@ -618,10 +645,16 @@
|
|||||||
lines[29] !== "OK" &&
|
lines[29] !== "OK" &&
|
||||||
lines[29] !== ""
|
lines[29] !== ""
|
||||||
) {
|
) {
|
||||||
networkMode3 = lines[29].split(":")[1].replace(/"/g, "");
|
networkMode3 = lines[29]
|
||||||
|
.split(":")[1]
|
||||||
|
.split(",")[0]
|
||||||
|
.replace(/"/g, "");
|
||||||
networkMode3 = networkMode3.split(",")[0];
|
networkMode3 = networkMode3.split(",")[0];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(networkMode2, networkMode3);
|
||||||
// Check if networkMode3 is not empty
|
// Check if networkMode3 is not empty
|
||||||
if (networkMode3 !== undefined) {
|
if (networkMode3 !== undefined) {
|
||||||
this.network_mode = networkMode2 + ", " + networkMode3;
|
this.network_mode = networkMode2 + ", " + networkMode3;
|
||||||
@@ -871,6 +904,9 @@
|
|||||||
this.signalPercentage =
|
this.signalPercentage =
|
||||||
(this.signalPercentage + nrSignalPercentage) / 2;
|
(this.signalPercentage + nrSignalPercentage) / 2;
|
||||||
|
|
||||||
|
// Round the signalPercentage value
|
||||||
|
this.signalPercentage = Math.round(this.signalPercentage);
|
||||||
|
|
||||||
// Get the Signal Assessment
|
// Get the Signal Assessment
|
||||||
this.signalAssessment = this.signalQuality(
|
this.signalAssessment = this.signalQuality(
|
||||||
this.signalPercentage
|
this.signalPercentage
|
||||||
@@ -998,8 +1034,9 @@
|
|||||||
const rawdata = data;
|
const rawdata = data;
|
||||||
|
|
||||||
const lines = rawdata.split("\n");
|
const lines = rawdata.split("\n");
|
||||||
|
console.log("CSQ: ", lines);
|
||||||
|
|
||||||
this.csq = lines[0].split(":")[1].split(",")[0].trim();
|
this.csq = lines[1].split(":")[1].split(",")[0].trim();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1031,11 +1068,22 @@
|
|||||||
this.refreshRate = this.newRefreshRate;
|
this.refreshRate = this.newRefreshRate;
|
||||||
console.log("Refresh Rate Updated to " + this.refreshRate);
|
console.log("Refresh Rate Updated to " + this.refreshRate);
|
||||||
|
|
||||||
|
// Store the refresh rate in local storage or session storage
|
||||||
|
localStorage.setItem("refreshRate", this.refreshRate);
|
||||||
|
|
||||||
// Initialize with the new refresh rate
|
// Initialize with the new refresh rate
|
||||||
this.init();
|
this.init();
|
||||||
},
|
},
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
// Retrieve the refresh rate from local storage or session storage
|
||||||
|
const storedRefreshRate = localStorage.getItem("refreshRate");
|
||||||
|
|
||||||
|
// If a refresh rate is stored, use it; otherwise, use a default value
|
||||||
|
this.refreshRate = storedRefreshRate
|
||||||
|
? parseInt(storedRefreshRate)
|
||||||
|
: 5; // Change 5 to your desired default value
|
||||||
|
|
||||||
this.fetchNetworkInfo();
|
this.fetchNetworkInfo();
|
||||||
// sleep for 2 seconds
|
// sleep for 2 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -1044,7 +1092,8 @@
|
|||||||
|
|
||||||
this.requestPing()
|
this.requestPing()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const response = data.trim(); // Trim any leading/trailing spaces
|
const response = data.trim();
|
||||||
|
// Trim any leading/trailing spaces
|
||||||
if (response === "OK") {
|
if (response === "OK") {
|
||||||
this.internetConnection = "Connected";
|
this.internetConnection = "Connected";
|
||||||
} else {
|
} else {
|
||||||
@@ -1069,7 +1118,8 @@
|
|||||||
|
|
||||||
this.requestPing()
|
this.requestPing()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const response = data.trim(); // Trim any leading/trailing spaces
|
const response = data.trim();
|
||||||
|
// Trim any leading/trailing spaces
|
||||||
if (response === "OK") {
|
if (response === "OK") {
|
||||||
this.internetConnection = "Connected";
|
this.internetConnection = "Connected";
|
||||||
} else {
|
} else {
|
||||||
@@ -1082,7 +1132,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.lastUpdate = new Date().toLocaleString();
|
this.lastUpdate = new Date().toLocaleString();
|
||||||
|
|
||||||
console.log("Refreshed");
|
console.log("Refreshed");
|
||||||
}, this.refreshRate * 1000);
|
}, this.refreshRate * 1000);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ function parseCurrentSettings(rawdata) {
|
|||||||
|
|
||||||
let bands = [];
|
let bands = [];
|
||||||
|
|
||||||
// Append the values if there is separated by comma
|
// Append the values if there is separated by comma with a space.
|
||||||
|
// i.e. LTE BAND 3, LTE BAND 1
|
||||||
for (let i = 13; i < 17; i++) {
|
for (let i = 13; i < 17; i++) {
|
||||||
if (lines[i].split(",").length > 1) {
|
if (lines[i].split(",").length > 1) {
|
||||||
bands.push(lines[i].split(",")[3].replace(/\"/g, " "));
|
bands.push(lines[i].split(",")[3].replace(/\"/g, " "));
|
||||||
@@ -24,6 +25,7 @@ function parseCurrentSettings(rawdata) {
|
|||||||
|
|
||||||
this.bands = bands;
|
this.bands = bands;
|
||||||
|
|
||||||
|
|
||||||
if (this.cellLock4GStatus == 1 && this.cellLock5GStatus == 1) {
|
if (this.cellLock4GStatus == 1 && this.cellLock5GStatus == 1) {
|
||||||
this.cellLockStatus = "Locked to 4G and 5G";
|
this.cellLockStatus = "Locked to 4G and 5G";
|
||||||
} else if (this.cellLock4GStatus == 1) {
|
} else if (this.cellLock4GStatus == 1) {
|
||||||
|
|||||||
@@ -43,7 +43,12 @@
|
|||||||
<a class="nav-link" href="/">Home</a>
|
<a class="nav-link" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="network.html" aria-current="page">Simple Network</a>
|
<a
|
||||||
|
class="nav-link active"
|
||||||
|
href="network.html"
|
||||||
|
aria-current="page"
|
||||||
|
>Simple Network</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||||
@@ -52,17 +57,15 @@
|
|||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
<a class="nav-link" href="/sms.html">SMS</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/console">Console</a>
|
<a class="nav-link" href="deviceinfo.html"
|
||||||
</li>
|
>Device Information</a
|
||||||
<li class="nav-item">
|
>
|
||||||
<a class="nav-link" href="deviceinfo.html">Device Information</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
|
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||||
</span>
|
Dark Mode
|
||||||
<span class="navbar-text">
|
</button>
|
||||||
<button class="btn btn-link" href="logout.html">Log Out</button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -552,7 +555,7 @@
|
|||||||
updatedLockedBands: null,
|
updatedLockedBands: null,
|
||||||
sim: "-",
|
sim: "-",
|
||||||
newSim: null,
|
newSim: null,
|
||||||
cellLockStatus: null,
|
cellLockStatus: "Unknown",
|
||||||
bands: "Fetching Bands...",
|
bands: "Fetching Bands...",
|
||||||
init() {
|
init() {
|
||||||
// Function to populate checkboxes
|
// Function to populate checkboxes
|
||||||
|
|||||||
@@ -39,14 +39,16 @@
|
|||||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/settings.html" aria-current="page">Simple Settings</a>
|
<a
|
||||||
|
class="nav-link active"
|
||||||
|
href="/settings.html"
|
||||||
|
aria-current="page"
|
||||||
|
>Simple Settings</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/sms.html">SMS</a>
|
<a class="nav-link" href="/sms.html">SMS</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/console">Console</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/deviceinfo.html"
|
<a class="nav-link" href="/deviceinfo.html"
|
||||||
>Device Information</a
|
>Device Information</a
|
||||||
@@ -54,10 +56,9 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
|
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||||
</span>
|
Dark Mode
|
||||||
<span class="navbar-text">
|
</button>
|
||||||
<button class="btn btn-link" href="logout.html">Log Out</button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,10 +50,12 @@
|
|||||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/sms.html" aria-current="page">SMS</a>
|
<a
|
||||||
</li>
|
class="nav-link active"
|
||||||
<li class="nav-item">
|
href="/sms.html"
|
||||||
<a class="nav-link" href="/console">Console</a>
|
aria-current="page"
|
||||||
|
>SMS</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/deviceinfo.html"
|
<a class="nav-link" href="/deviceinfo.html"
|
||||||
@@ -62,10 +64,9 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
|
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||||
</span>
|
Dark Mode
|
||||||
<span class="navbar-text">
|
</button>
|
||||||
<button class="btn btn-link" href="logout.html">Log Out</button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user