Merge @dr-dolomite 's for-merging branch
-Create new development-v2 branch to work on simpleadmin v2
-Merged @dr-dolomite work from:
2d197220a4
Co-Authored-By: Russel Yasol <73575327+dr-dolomite@users.noreply.github.com>
This commit is contained in:
@@ -1,355 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>AT Commands</title>
|
|
||||||
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
class="navbar-burger burger"
|
|
||||||
@click="isOpen = !isOpen"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="navMenu"
|
|
||||||
class="navbar-menu"
|
|
||||||
:class="isOpen ? 'is-active' : ''"
|
|
||||||
>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
<div class="container" x-data="atCommands()">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-12">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-4">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">AT Command</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">AT Command</label>
|
|
||||||
<div class="control">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="text"
|
|
||||||
placeholder="ATI"
|
|
||||||
x-model="atcmd"
|
|
||||||
x-ref="atCmdInput"
|
|
||||||
@keydown.enter="sendAtCommand()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<p class="control">
|
|
||||||
<button
|
|
||||||
class="button is-success"
|
|
||||||
@click="sendAtCommand()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Send AT Command
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-danger"
|
|
||||||
@click="clearResponses()"
|
|
||||||
:disabled="atCommandResponse === ''"
|
|
||||||
>
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column is-8">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">AT Command Response</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<textarea
|
|
||||||
class="textarea"
|
|
||||||
placeholder="Multiple commands should be separated by a semicolon. Example: AT+CGMR;+GSN"
|
|
||||||
rows="10"
|
|
||||||
x-text="isLoading ? 'Fetching response, please wait...' : atCommandResponse"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- START Useful Commands Section -->
|
|
||||||
<div class="container" x-data="atCommands()">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-12">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Useful One Click Commands</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<div style="display: flex; flex-direction: row; flex-wrap: wrap; margin-top: 1rem; justify-content: space-between;">
|
|
||||||
<div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<button
|
|
||||||
class="button is-danger"
|
|
||||||
@click="sendRebootCommand()"
|
|
||||||
:disabled="isRebooting"
|
|
||||||
>
|
|
||||||
Reboot
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<button
|
|
||||||
class="button is-danger"
|
|
||||||
@click="sendRebootCommand()"
|
|
||||||
:disabled="isRebooting"
|
|
||||||
>
|
|
||||||
Reboot
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
<p>Here are some useful commands:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<!-- Open to another tab -->
|
|
||||||
See <a href="https://github.com/iamromulan/RM520N-GL#at-commands" target="_blank" style="cursor: pointer;">https://github.com/iamromulan/RM520N-GL#at-commands</a> for
|
|
||||||
more
|
|
||||||
</li>
|
|
||||||
<li>AT+CFUN=1,1 (reboot)</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAPWAC? (get current status of auto connect, 0=disabled
|
|
||||||
1=enabled)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAPWAC=1 (enable auto connect internet for ethernet)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAPWAC=0 (disable auto connect for ethernet; use when
|
|
||||||
you want internet over usb to work; IPPT must be disabled)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QUIMSLOT? (get active sim slot; 1=Slot 1; 2=Slot 2)
|
|
||||||
</li>
|
|
||||||
<li>AT+QUIMSLOT=1 (switch to sim slot 1)</li>
|
|
||||||
<li>AT+QUIMSLOT=2 (switch to sim slot 2)</li>
|
|
||||||
<li>AT+CGDCONT? (Get active APN profle list 1 through 8)</li>
|
|
||||||
<li>
|
|
||||||
AT+CGDCONT=1,"IPV4V6","APNHERE" (Sets APN profle 1 to
|
|
||||||
APNHERE using both IPV4 and IPV6)
|
|
||||||
</li>
|
|
||||||
<li>AT+GSN (Show current IMEI)</li>
|
|
||||||
<li>AT+EGMR=1,7,"IMEIGOESHERE" (sets/repairs IMEI)</li>
|
|
||||||
<li>AT+QCAINFO (Show all connected bands/CA info)</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="mode_pref" (Check what the current network
|
|
||||||
search mode is set to)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="mode_pref",AUTO (Set network search mode to
|
|
||||||
automatic)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="mode_pref",NR5G:LTE (Set network search mode
|
|
||||||
to 5G/NR and 4G/LTE only)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="mode_pref",NR5G (Set network search mode to
|
|
||||||
5G/NR only)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="mode_pref",LTE (Set network search mode to
|
|
||||||
4G/LTE only)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_disable_mode" (Check to see if SA or NSA
|
|
||||||
NR5G is disabled)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_disable_mode",0 (Enable Both SA and NSA
|
|
||||||
5G/NR)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_disable_mode",1 (Disable SA 5G/NR only)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_disable_mode",2 (Disable NSA 5G/NR only)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_band" (Get current 5G/NR bandlock
|
|
||||||
settings)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="nr5g_band",1:2:3:4:5:6 (Example: Lock to
|
|
||||||
5G/NR bands n1,n2,n3,n4,n5, and n6)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="lte_band" (Get current 4G/LTE bandlock
|
|
||||||
settings)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QNWPREFCFG="lte_band",1:2:3:4:5:6 (Example: Lock to
|
|
||||||
4G/LTE bands 1,2,3,4,5, and 6)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="WWAN" (Show currently assigned IPv4 and IPv6 from
|
|
||||||
the provider)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="LANIP" (Show current DHCP range and Gateway address
|
|
||||||
for VLAN0)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="LANIP",IP_start_range,IP_end_range,Gateway_IP (Set
|
|
||||||
IPv4 Start/End range and Gateway IP of DHCP for VLAN0)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="DHCPV4DNS","disable" (disable the onboard DNS
|
|
||||||
proxy; recommended for IPPT)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="MPDN_rule",0,1,0,1,1,"FF:FF:FF:FF:FF:FF" (Turn on
|
|
||||||
IP Passthrough for Ethernet)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
AT+QMAP="MPDN_rule",0 (turn off IPPT/clear MPDN rule 0;
|
|
||||||
Remember to run AT+QMAPWAC=1 and reboot after)
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Loading modal -->
|
|
||||||
<div x-show="isRebooting" class="modal-overlay">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="spinner"></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
|
|
||||||
before refreshing the page.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function atCommands() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
isRebooting: false,
|
|
||||||
countdown: 40, // Total waiting time in seconds
|
|
||||||
atcmd: null,
|
|
||||||
defaultAtCommand: "ATI",
|
|
||||||
atCommandResponse: "",
|
|
||||||
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;
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
clearResponses() {
|
|
||||||
this.atCommandResponse = "";
|
|
||||||
},
|
|
||||||
sendRebootCommand() {
|
|
||||||
this.atcmd = "AT+CFUN=1,1";
|
|
||||||
this.isRebooting = true;
|
|
||||||
console.log("Reboot command sent: ", this.atcmd);
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse =
|
|
||||||
"Rebooting... Please wait a few seconds before refreshing the page.";
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
let timer = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown <= 0) {
|
|
||||||
clearInterval(timer);
|
|
||||||
this.isRebooting = false;
|
|
||||||
}
|
|
||||||
}, 1000); // Update countdown every second
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,878 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Simple Network</title>
|
|
||||||
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.card-column {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
class="navbar-burger burger"
|
|
||||||
@click="isOpen = !isOpen"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="navMenu"
|
|
||||||
class="navbar-menu"
|
|
||||||
:class="isOpen ? 'is-active' : ''"
|
|
||||||
>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
<div
|
|
||||||
class="container"
|
|
||||||
style="margin: auto"
|
|
||||||
x-data="atCommands()"
|
|
||||||
x-init="atCommands()"
|
|
||||||
>
|
|
||||||
<div class="columns is-multiline">
|
|
||||||
<!-- First Box -->
|
|
||||||
<div class="column is-8-tablet is-6-desktop card-column">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Band Locking</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<!-- Create a drop down -->
|
|
||||||
<div class="select is-primary">
|
|
||||||
<select id="networkMode" x-model="networkMode">
|
|
||||||
<option>Select Network Mode</option>
|
|
||||||
<option>LTE</option>
|
|
||||||
<option>NR5G-NSA</option>
|
|
||||||
<option>NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
class="input is-primary"
|
|
||||||
type="text"
|
|
||||||
placeholder="Example: 1,3,41"
|
|
||||||
style="margin-top: 1rem"
|
|
||||||
x-model="bandNumbers"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem; display: flex; flex-direction: row">
|
|
||||||
<button
|
|
||||||
class="button is-primary"
|
|
||||||
@click="lockBands()"
|
|
||||||
:disabled="isLocking"
|
|
||||||
>
|
|
||||||
Lock Bands
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-warning"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="restoreBands()"
|
|
||||||
:disabled="isLocking"
|
|
||||||
>
|
|
||||||
Restore Bands
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer" style="padding: 0.25rem">
|
|
||||||
<p class="card-footer-item">
|
|
||||||
Please first select your desired network band from the dropdown
|
|
||||||
menu. To lock onto specific bands, please type the band numbers
|
|
||||||
separated by commas (,) and then click the lock button.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Second Box -->
|
|
||||||
<div class="column is-8-tablet is-6-desktop card-column">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">LTE and NR5G Cell Locking</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div style="display: flex; flex-direction: row">
|
|
||||||
<div class="select is-info">
|
|
||||||
<select id="networkModeSelect" x-model="networkMode2">
|
|
||||||
<option>Select Network Mode</option>
|
|
||||||
<option>LTE</option>
|
|
||||||
<option>NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
id="numFreqContainer"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
x-show="networkMode2 == 'LTE'"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
class="input is-info"
|
|
||||||
type="number"
|
|
||||||
id="numFreqInput"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
placeholder="1-10"
|
|
||||||
x-model="cellNum"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="freqNumbersContainer"></div>
|
|
||||||
|
|
||||||
<!-- For NR5G-SA -->
|
|
||||||
<div style="margin-top: 1rem" x-show="networkMode2 == 'NR5G-SA'">
|
|
||||||
<div style="display: flex; flex-direction: row">
|
|
||||||
<input
|
|
||||||
class="input is-info"
|
|
||||||
type="text"
|
|
||||||
placeholder="EARFCN"
|
|
||||||
x-model="earfcn1"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="input is-info"
|
|
||||||
type="text"
|
|
||||||
placeholder="PCI"
|
|
||||||
x-model="pci1"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="input is-info"
|
|
||||||
type="text"
|
|
||||||
placeholder="SCS"
|
|
||||||
x-model="scs"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="input is-info"
|
|
||||||
type="text"
|
|
||||||
placeholder="BAND"
|
|
||||||
x-model="band"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem; display: flex; flex-direction: row">
|
|
||||||
<button
|
|
||||||
class="button is-info"
|
|
||||||
@click="cellLock()"
|
|
||||||
:disabled="isLocking"
|
|
||||||
>
|
|
||||||
Lock Cell
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-warning"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="restoreCell()"
|
|
||||||
:disabled="isLocking"
|
|
||||||
>
|
|
||||||
Restore Cell
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer" style="padding: 0.25rem">
|
|
||||||
<p class="card-footer-item">
|
|
||||||
To utilize cell locking, first, select the network mode, then
|
|
||||||
specify the number of cells you wish to lock onto (max 10) if
|
|
||||||
you are using LTE. Next, input the EARFCN and PCI values for
|
|
||||||
each cell number. If you are locking through NR5G-SA instead,
|
|
||||||
simply fill up all the required parameters.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Third Box -->
|
|
||||||
|
|
||||||
<div class="column is-8-tablet is-6-desktop card-column">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Network Utilities</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div style="display: flex; flex-direction: column">
|
|
||||||
<div>
|
|
||||||
<p>Set Network APN</p>
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
class="input is-link"
|
|
||||||
type="text"
|
|
||||||
placeholder="APN"
|
|
||||||
x-model="apnInput"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="setAPN()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Set APN
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem">
|
|
||||||
<p>Set Preferred Network Mode</p>
|
|
||||||
<div
|
|
||||||
style="display: flex; flex-direction: row; margin-top: 0.5rem"
|
|
||||||
>
|
|
||||||
<div class="select is-info">
|
|
||||||
<select id="prefNetworkMode" x-model="prefNetworkMode">
|
|
||||||
<option>Select Network</option>
|
|
||||||
<option>AUTO</option>
|
|
||||||
<option>WCDMA</option>
|
|
||||||
<option>LTE ONLY</option>
|
|
||||||
<option>NR5G-NSA</option>
|
|
||||||
<option>NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="setPrefNetwork()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Set Network
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem">
|
|
||||||
<p>Set Sim Slot</p>
|
|
||||||
<div
|
|
||||||
style="display: flex; flex-direction: row; margin-top: 0.5rem"
|
|
||||||
>
|
|
||||||
<div class="select is-info">
|
|
||||||
<select id="simSlot" x-model="simSlot">
|
|
||||||
<option>Select Sim</option>
|
|
||||||
<option>1</option>
|
|
||||||
<option>2</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="setSimSlot()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Set Sim
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem">
|
|
||||||
<p>NR5G Mode Control</p>
|
|
||||||
<div
|
|
||||||
style="display: flex; flex-direction: row; margin-top: 0.5rem"
|
|
||||||
>
|
|
||||||
<div class="select is-info">
|
|
||||||
<select id="nrMode" x-model="nrMode">
|
|
||||||
<option>Select NR5G Mode</option>
|
|
||||||
<option>Enable All</option>
|
|
||||||
<option>Disable NSA</option>
|
|
||||||
<option>Disable SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem"
|
|
||||||
@click="nr5GMode()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Set Mode
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer" style="padding: 0.25rem">
|
|
||||||
<p class="card-footer-item">
|
|
||||||
This section allows you to set the APN, preferred network mode,
|
|
||||||
and sim slot. Simply input the desired values and click the
|
|
||||||
respective buttons to apply the changes. (Sim slot is only
|
|
||||||
applicable for dual sim devices.)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fourth Box -->
|
|
||||||
<div class="column is-8-tablet is-6-desktop card-column">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Query Network Parameters</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<textarea
|
|
||||||
class="textarea"
|
|
||||||
rows="5"
|
|
||||||
placeholder="Query Response"
|
|
||||||
x-text=" isLoading ? 'Getting Response...' : queryCommandResponse"
|
|
||||||
></textarea>
|
|
||||||
|
|
||||||
<div style="margin-top: 1.5rem">
|
|
||||||
<p>Check Locked Bands</p>
|
|
||||||
<div class="select is-info" style="margin-top: 0.5rem">
|
|
||||||
<select id="lockedBands" x-model="lockedBands">
|
|
||||||
<option>Locked Bands</option>
|
|
||||||
<option>LTE</option>
|
|
||||||
<option>NSA</option>
|
|
||||||
<option>SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem; margin-top: 0.5rem"
|
|
||||||
@click="showLockedBands()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Check Bands
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 1rem">
|
|
||||||
<p>Check Cell Lock</p>
|
|
||||||
<div class="select is-info" style="margin-top: 0.5rem">
|
|
||||||
<select id="cellState" x-model="cellState">
|
|
||||||
<option>Cell Lock</option>
|
|
||||||
<option>LTE</option>
|
|
||||||
<option>NR5G-SA</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
style="margin-left: 1rem; margin-top: 0.5rem"
|
|
||||||
@click="showCellState()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Check Cell
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 2rem">
|
|
||||||
<p>Other Network Query</p>
|
|
||||||
</div>
|
|
||||||
<div class="buttons" style="margin-top: 0.5rem">
|
|
||||||
<button
|
|
||||||
class="button is-link mr-2"
|
|
||||||
@click="showSupportedBands()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Show Supported Bands
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link mr-2"
|
|
||||||
@click="showCurrentSim()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Show Current Sim
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="showPrefNetwork()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Show Pref Network
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="showCaInfo()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Carrier Aggregation Info
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="servingCellInfo()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Serving Cell Info
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="scanNeighbourCells()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Scan Neighbour Cells
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="scanNsaCells()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Scan NSA Cells
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button is-link"
|
|
||||||
@click="fullNetworkScan()"
|
|
||||||
:disabled="isLoading"
|
|
||||||
>
|
|
||||||
Full Network Scan
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer" style="padding: 0.25rem">
|
|
||||||
<p class="card-footer-item">
|
|
||||||
This section allows you to query the network parameters. Simply
|
|
||||||
click the respective buttons to view the network parameters.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Loading Modal for Locking Band -->
|
|
||||||
<div x-show="isLocking" class="modal-overlay">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="spinner"></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 x-show="isError" class="modal-overlay">
|
|
||||||
<div class="loading-modal">
|
|
||||||
<div class="spinner"></div>
|
|
||||||
<div
|
|
||||||
class="loading-text"
|
|
||||||
style="display: flex; flex-direction: column"
|
|
||||||
>
|
|
||||||
<h3>Request Error</h3>
|
|
||||||
<p style="margin-top: 0.5rem">
|
|
||||||
Please follow the instructions properly. Exiting in
|
|
||||||
<span x-text="countdown" style="font-weight: 500"></span> seconds.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function atCommands() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
isQuerying: false,
|
|
||||||
isLocking: false,
|
|
||||||
isError: false,
|
|
||||||
countdown: 5, // Initial countdown value
|
|
||||||
networkMode: null,
|
|
||||||
networkMode2: null,
|
|
||||||
bandNumbers: null,
|
|
||||||
cellNum: null,
|
|
||||||
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,
|
|
||||||
band: null,
|
|
||||||
scs: null,
|
|
||||||
apnInput: null,
|
|
||||||
prefNetworkMode: null,
|
|
||||||
simSlot: null,
|
|
||||||
nrMode: null,
|
|
||||||
lockedBands: null,
|
|
||||||
cellState: null,
|
|
||||||
invalidCellNum: "",
|
|
||||||
atCommandResponse: "",
|
|
||||||
queryCommandResponse: "",
|
|
||||||
lockBands() {
|
|
||||||
if (!this.networkMode || !this.bandNumbers) {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Network mode and band numbers are required.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove commas and replace with colons
|
|
||||||
const parsedBandNumbers = this.bandNumbers.replace(/,/g, ":");
|
|
||||||
|
|
||||||
// Construct the atcmd based on the selected network mode
|
|
||||||
let atcmd;
|
|
||||||
switch (this.networkMode) {
|
|
||||||
case "LTE":
|
|
||||||
atcmd = `AT+QNWPREFCFG="lte_band",${parsedBandNumbers}`;
|
|
||||||
console.log(atcmd);
|
|
||||||
break;
|
|
||||||
case "NR5G-NSA":
|
|
||||||
atcmd = `AT+QNWPREFCFG="nsa_nr5g_band",${parsedBandNumbers}`;
|
|
||||||
console.log(atcmd);
|
|
||||||
break;
|
|
||||||
case "NR5G-SA":
|
|
||||||
atcmd = `AT+QNWPREFCFG="nr5g_band",${parsedBandNumbers}`;
|
|
||||||
console.log(atcmd);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Invalid network mode.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoading = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => res.text())
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
this.isLocking = true;
|
|
||||||
this.startCountdown();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Error sending AT command:", error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
cellLock() {
|
|
||||||
// Error handlers
|
|
||||||
if (!this.networkMode2) {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Network mode is required.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the AT command based on the selected network mode
|
|
||||||
let atcmd;
|
|
||||||
|
|
||||||
if (this.networkMode2 === "LTE") {
|
|
||||||
if (parseInt(this.cellNum) > 10) {
|
|
||||||
this.invalidCellNum = "Invalid";
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Invalid frequency number.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLocking = true;
|
|
||||||
atcmd = `AT+QNWLOCK="common/4g",${this.cellNum}`;
|
|
||||||
for (let i = 1; i <= parseInt(this.cellNum); i++) {
|
|
||||||
atcmd += `,${this["earfcn" + i]},${this["pci" + i]}`;
|
|
||||||
}
|
|
||||||
console.log(atcmd);
|
|
||||||
} else if (this.networkMode2 === "NR5G-SA") {
|
|
||||||
this.isLocking = true;
|
|
||||||
atcmd = `AT+QNWLOCK="common/5g",${this.pci1},${this.earfcn1},${this.scs},${this.band}`;
|
|
||||||
console.log(atcmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sendAtCommand(atcmd);
|
|
||||||
},
|
|
||||||
restoreBands() {
|
|
||||||
const restoreCmd = 'AT+QNWPREFCFG="restore_band"';
|
|
||||||
this.sendAtCommand(restoreCmd);
|
|
||||||
},
|
|
||||||
restoreCell() {
|
|
||||||
const restoreCmd = 'AT+QNWLOCK="common/4g",0';
|
|
||||||
this.sendAtCommand(restoreCmd);
|
|
||||||
},
|
|
||||||
setAPN() {
|
|
||||||
const apnCmd = `AT+CGDCONT=1,"IPV4V6","${this.apnInput}"`;
|
|
||||||
this.sendAtCommand(apnCmd);
|
|
||||||
},
|
|
||||||
setPrefNetwork() {
|
|
||||||
// AT+QNWPREFCFG="mode_pref",<mode>
|
|
||||||
let prefCmd;
|
|
||||||
switch (this.prefNetworkMode) {
|
|
||||||
case "AUTO":
|
|
||||||
prefCmd = 'AT+QNWPREFCFG="mode_pref",AUTO';
|
|
||||||
break;
|
|
||||||
case "WCDMA":
|
|
||||||
prefCmd = 'AT+QNWPREFCFG="mode_pref",WCDMA';
|
|
||||||
break;
|
|
||||||
case "LTE ONLY":
|
|
||||||
prefCmd = 'AT+QNWPREFCFG="mode_pref",LTE';
|
|
||||||
break;
|
|
||||||
case "NR5G-NSA":
|
|
||||||
prefCmd = 'AT+QNWPREFCFG="mode_pref",LTE:NR5G';
|
|
||||||
break;
|
|
||||||
case "NR5G-SA":
|
|
||||||
prefCmd = 'AT+QNWPREFCFG="mode_pref",NR5G';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Invalid network mode.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.sendAtCommand(prefCmd);
|
|
||||||
},
|
|
||||||
setSimSlot() {
|
|
||||||
const simCmd = `AT+QUIMSLOT=${this.simSlot}`;
|
|
||||||
this.sendAtCommand(simCmd);
|
|
||||||
},
|
|
||||||
nr5GMode() {
|
|
||||||
let nrCmd;
|
|
||||||
switch (this.nrMode) {
|
|
||||||
case "Enable All":
|
|
||||||
nrCmd = 'AT+QNWPREFCFG="nr5g_disable_mode",0';
|
|
||||||
break;
|
|
||||||
case "Disable NSA":
|
|
||||||
nrCmd = 'AT+QNWPREFCFG="nr5g_disable_mode",2';
|
|
||||||
break;
|
|
||||||
case "Disable SA":
|
|
||||||
nrCmd = 'AT+QNWPREFCFG="nr5g_disable_mode",1';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Invalid NR5G mode.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.queryATCommand(nrCmd);
|
|
||||||
},
|
|
||||||
showLockedBands() {
|
|
||||||
let lockedCmd;
|
|
||||||
switch (this.lockedBands) {
|
|
||||||
case "LTE":
|
|
||||||
lockedCmd = 'AT+QNWPREFCFG="lte_band"';
|
|
||||||
break;
|
|
||||||
case "NSA":
|
|
||||||
lockedCmd = 'AT+QNWPREFCFG="nsa_nr5g_band"';
|
|
||||||
break;
|
|
||||||
case "SA":
|
|
||||||
lockedCmd = 'AT+QNWPREFCFG="nr5g_band"';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Invalid network mode.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.queryATCommand(lockedCmd);
|
|
||||||
},
|
|
||||||
|
|
||||||
showCellState() {
|
|
||||||
let cellCmd;
|
|
||||||
switch (this.cellState) {
|
|
||||||
case "LTE":
|
|
||||||
cellCmd = 'AT+QNWLOCK="common/4g"';
|
|
||||||
break;
|
|
||||||
case "NR5G-SA":
|
|
||||||
cellCmd = 'AT+QNWLOCK="common/5g"';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Invalid network mode.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.queryATCommand(cellCmd);
|
|
||||||
},
|
|
||||||
showSupportedBands() {
|
|
||||||
const supportedCmd = 'AT+QNWPREFCFG="policy_band"';
|
|
||||||
this.queryATCommand(supportedCmd);
|
|
||||||
},
|
|
||||||
showCurrentSim() {
|
|
||||||
const simCmd = "AT+QUIMSLOT?";
|
|
||||||
this.queryATCommand(simCmd);
|
|
||||||
},
|
|
||||||
showPrefNetwork() {
|
|
||||||
const prefCmd = 'AT+QNWPREFCFG="mode_pref"';
|
|
||||||
this.queryATCommand(prefCmd);
|
|
||||||
},
|
|
||||||
showCaInfo() {
|
|
||||||
const caCmd = "AT+QCAINFO";
|
|
||||||
this.queryATCommand(caCmd);
|
|
||||||
},
|
|
||||||
servingCellInfo() {
|
|
||||||
const servingCmd = 'AT+QENG="servingcell"';
|
|
||||||
this.queryATCommand(servingCmd);
|
|
||||||
},
|
|
||||||
scanNeighbourCells() {
|
|
||||||
const scanCmd = 'AT+QENG="neighbourcell"';
|
|
||||||
this.queryATCommand(scanCmd);
|
|
||||||
},
|
|
||||||
scanNsaCells() {
|
|
||||||
const enableCmd = 'AT+QNWCFG="nr5g_meas_info",1';
|
|
||||||
const queryScanCmd = 'AT+QNWCFG="nr5g_meas_info"';
|
|
||||||
// Send the enable command first without getting the response
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: enableCmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
console.log("Enable Success.");
|
|
||||||
// Show a temporary loading query message
|
|
||||||
this.queryCommandResponse =
|
|
||||||
"Enabling NSA cell scan. Please wait...";
|
|
||||||
this.queryATCommand(queryScanCmd);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Error sending AT command:", error);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
fullNetworkScan() {
|
|
||||||
const scanCmd = "AT+QSCAN=3,1";
|
|
||||||
// Show a temporary loading query message
|
|
||||||
this.queryCommandResponse =
|
|
||||||
"Full network scan initiated. This takes about a minute. Please wait...";
|
|
||||||
this.queryATCommand(scanCmd);
|
|
||||||
},
|
|
||||||
queryATCommand(atcmd) {
|
|
||||||
this.isQuerying = true;
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => res.text())
|
|
||||||
.then((data) => {
|
|
||||||
this.queryCommandResponse = data;
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Error sending AT command:", error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isQuerying = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
sendAtCommand(atcmd) {
|
|
||||||
this.isLoading = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.log(atcmd);
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => res.text())
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.isError = true;
|
|
||||||
this.startCountdown();
|
|
||||||
console.error("Error sending AT command:", error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
startCountdown() {
|
|
||||||
// Decrease countdown every second
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
this.countdown--;
|
|
||||||
if (this.countdown <= 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
// Reset values
|
|
||||||
this.isLocking = false;
|
|
||||||
this.isError = false;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isQuerying = false;
|
|
||||||
this.countdown = 5;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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 style="margin-top: 1rem" x-show="cellNum >= ${i} && networkMode2 == 'LTE'">
|
|
||||||
<div style="display: flex; flex-direction: row">
|
|
||||||
<input class="input is-info" type="text" placeholder="EARFCN" x-model="earfcn${i}" />
|
|
||||||
<input class="input is-info" type="text" placeholder="PCI" x-model="pci${i}" style="margin-left: 1rem" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById("numFreqInput")
|
|
||||||
.addEventListener("input", function () {
|
|
||||||
const cellNum = parseInt(this.value);
|
|
||||||
freqNumbersContainer.innerHTML = generateFreqNumberInputs(cellNum);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ ! -f /tmp/modemstatus.json ]
|
|
||||||
then
|
|
||||||
/usrdata/simpleadmin/scripts/modemstatus_parse.sh > /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
runcmd=$(</tmp/modemstatus.json)
|
|
||||||
|
|
||||||
echo "Content-type: text/json"
|
|
||||||
echo ""
|
|
||||||
cat <<EOT
|
|
||||||
$runcmd
|
|
||||||
19
simpleadmin/www/cgi-bin/get_ping
Normal file
19
simpleadmin/www/cgi-bin/get_ping
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/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
|
||||||
@@ -5,10 +5,6 @@ SMS_MESSAGE_INDICATION="AT+CNMI=2,1"
|
|||||||
SMS_FORMAT="AT+CMGF=1"
|
SMS_FORMAT="AT+CMGF=1"
|
||||||
SMS_LIST="AT+CMGL=\"ALL\""
|
SMS_LIST="AT+CMGL=\"ALL\""
|
||||||
|
|
||||||
# Send the all the AT commands 1 by 1 with 2 seconds waiting time for each command
|
|
||||||
runcmd=$(echo -en "$SMS_MESSAGE_INDICATION\r\n" | microcom -t 1000 /dev/ttyOUT2)
|
|
||||||
runcmd=$(echo -en "$SMS_FORMAT\r\n" | microcom -t 1000 /dev/ttyOUT2)
|
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
runcmd=$(echo -en "$SMS_LIST\r\n" | microcom -t 2000 /dev/ttyOUT2)
|
runcmd=$(echo -en "$SMS_LIST\r\n" | microcom -t 2000 /dev/ttyOUT2)
|
||||||
if [[ $runcmd =~ "OK" ]] || [[ $runcmd =~ "ERROR" ]]; then
|
if [[ $runcmd =~ "OK" ]] || [[ $runcmd =~ "ERROR" ]]; then
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -17,4 +17,4 @@ cat <<EOT
|
|||||||
"isEnabled": $ttlenabled,
|
"isEnabled": $ttlenabled,
|
||||||
"ttl": $ttlvalue
|
"ttl": $ttlvalue
|
||||||
}
|
}
|
||||||
EOT
|
EOT
|
||||||
44
simpleadmin/www/cgi-bin/send_sms
Normal file
44
simpleadmin/www/cgi-bin/send_sms
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/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,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
|
||||||
@@ -58,5 +58,4 @@ cat <<EOT
|
|||||||
{
|
{
|
||||||
"isEnabled": $ttlenabled,
|
"isEnabled": $ttlenabled,
|
||||||
"ttl": $ttlvalue
|
"ttl": $ttlvalue
|
||||||
}
|
}
|
||||||
EOT
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
:root{
|
|
||||||
::-webkit-scrollbar{height:10px;width:10px}::-webkit-scrollbar-track{background:#efefef;border-radius:6px}::-webkit-scrollbar-thumb{background:#d5d5d5;border-radius:6px}::-webkit-scrollbar-thumb:hover{background:#c4c4c4}
|
|
||||||
}
|
|
||||||
html, body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.5;
|
|
||||||
height: 100%;
|
|
||||||
background: #ECF0F3;
|
|
||||||
}
|
|
||||||
nav.navbar {
|
|
||||||
border-top: 4px solid #276cda;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.navbar-item.brand-text {
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
.navbar-item, .navbar-link {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.columns {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
.menu-label {
|
|
||||||
color: #8F99A3;
|
|
||||||
letter-spacing: 1.3;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.menu-list a {
|
|
||||||
color: #0F1D38;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.menu-list a:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #276cda;
|
|
||||||
}
|
|
||||||
.menu-list a.is-active {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #276cda;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.card {
|
|
||||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.18);
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
.card-header-title {
|
|
||||||
color: #8F99A3;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.info-tiles {
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
.info-tiles .subtitle {
|
|
||||||
font-weight: 300;
|
|
||||||
color: #8F99A3;
|
|
||||||
}
|
|
||||||
.hero.welcome.is-info {
|
|
||||||
background: #36D1DC;
|
|
||||||
background: -webkit-linear-gradient(to right, #5B86E5, #36D1DC);
|
|
||||||
background: linear-gradient(to right, #5B86E5, #36D1DC);
|
|
||||||
}
|
|
||||||
.hero.welcome .title, .hero.welcome .subtitle {
|
|
||||||
color: hsl(192, 17%, 99%);
|
|
||||||
}
|
|
||||||
.card .content {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.card-footer-item {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #8F99A3;
|
|
||||||
}
|
|
||||||
.card-footer-item:hover {
|
|
||||||
}
|
|
||||||
.card-table .table {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.events-card .card-table {
|
|
||||||
height: 330px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
6
simpleadmin/www/css/bootstrap.min.css
vendored
Normal file
6
simpleadmin/www/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
simpleadmin/www/css/bulma.css
vendored
1
simpleadmin/www/css/bulma.css
vendored
File diff suppressed because one or more lines are too long
95
simpleadmin/www/css/styles.css
Normal file
95
simpleadmin/www/css/styles.css
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
||||||
358
simpleadmin/www/deviceinfo.html
Normal file
358
simpleadmin/www/deviceinfo.html
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
<!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>
|
||||||
1093
simpleadmin/www/home.html
Normal file
1093
simpleadmin/www/home.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,287 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<!-- change to a much simpler tab title -->
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
class="navbar-burger burger"
|
|
||||||
@click="isOpen = !isOpen"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="navMenu"
|
|
||||||
class="navbar-menu"
|
|
||||||
:class="isOpen ? 'is-active' : ''"
|
|
||||||
>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
<div class="container">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-12" x-data="getSignalData()" x-init="init()">
|
|
||||||
<section class="hero is-info welcome is-small">
|
|
||||||
<div class="hero-body">
|
|
||||||
<div class="container">
|
|
||||||
<!-- Fetches the correct Model Name -->
|
|
||||||
<h1 class="title">
|
|
||||||
<span x-text="csqData.MODEM_MODEL"></span> Connection
|
|
||||||
Info
|
|
||||||
</h1>
|
|
||||||
<h2 class="subtitle">
|
|
||||||
Data Updated: <span x-text="lastUpdate"></span>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="info-tiles">
|
|
||||||
<div class="tile is-ancestor has-text-centered">
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child box">
|
|
||||||
<!-- added APN -->
|
|
||||||
<p class="title" x-text="csqData.APN"></p>
|
|
||||||
<p class="subtitle">Current APN</p>
|
|
||||||
<p
|
|
||||||
class="title"
|
|
||||||
style="margin-top: 1rem"
|
|
||||||
x-html="csqData.SIMSLOT"
|
|
||||||
></p>
|
|
||||||
<p class="subtitle">Current SIM</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child box">
|
|
||||||
<!-- added APN -->
|
|
||||||
<p class="title" x-text="csqData.MODE"></p>
|
|
||||||
<p class="subtitle">Network</p>
|
|
||||||
<p
|
|
||||||
class="title"
|
|
||||||
x-text="csqData.PC_BAND"
|
|
||||||
style="margin-top: 1rem"
|
|
||||||
></p>
|
|
||||||
<p class="subtitle">Primary Band</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<!-- added primary band and secondary bands value -->
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child box">
|
|
||||||
<p class="title" x-html="csqData.SC_BANDS"></p>
|
|
||||||
<p class="subtitle">Aggregated Bands</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<div class="tile is-parent">
|
|
||||||
<article class="tile is-child box">
|
|
||||||
<p class="title" x-text="csqData.CSQ_PER"></p>
|
|
||||||
<p class="subtitle">Signal Strength</p>
|
|
||||||
<p
|
|
||||||
class="title"
|
|
||||||
x-text="csqData.TEMP"
|
|
||||||
style="margin-top: 1rem"
|
|
||||||
></p>
|
|
||||||
<p class="subtitle">Modem Temperature</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-6">
|
|
||||||
<div class="card events-card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Signal Information</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-table">
|
|
||||||
<div class="content">
|
|
||||||
<table class="table is-fullwidth is-striped">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>Provider</th>
|
|
||||||
<td x-text="csqData.PROVIDER"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>CSQ</th>
|
|
||||||
<td x-text="csqData.CSQ"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Signal Strength</th>
|
|
||||||
<td x-text="csqData.CSQ_PER"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>RSSI</th>
|
|
||||||
<td x-text="csqData.CSQ_RSSI"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
ECIO<sup>3G</sup>/RSRQ<sup>4G</sup>/SS_RSRQ<sup
|
|
||||||
>5G</sup
|
|
||||||
>
|
|
||||||
</th>
|
|
||||||
<td x-html="csqData.ECIO"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
RSCP<sup>3G</sup>/RSRP<sup>4G</sup>/SS_RSRP<sup
|
|
||||||
>5G</sup
|
|
||||||
>
|
|
||||||
</th>
|
|
||||||
<td x-html="csqData.RSCP"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>SINR</th>
|
|
||||||
<td x-html="csqData.SINR"></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column is-6">
|
|
||||||
<div class="card events-card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">Cell Information</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-table">
|
|
||||||
<div class="content">
|
|
||||||
<table class="table is-fullwidth is-striped">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>MCC MNC</th>
|
|
||||||
<td>
|
|
||||||
<span x-text="csqData.MCCMNC"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>RNC<sup>3G</sup>/eNB ID<sup>4G/5G</sup></th>
|
|
||||||
<td>
|
|
||||||
<span x-text="csqData.RNC"></span>
|
|
||||||
<span x-text="csqData.RNC_NUM"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Lag<sup>3G</sup>/TAC<sup>4G/5G</sup></th>
|
|
||||||
<td>
|
|
||||||
<span x-text="csqData.LAC"></span>
|
|
||||||
<span x-text="csqData.LAC_NUM"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Cell ID</th>
|
|
||||||
<td x-text="csqData.CID"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Band</th>
|
|
||||||
<td x-html="csqData.LBAND"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Channel</th>
|
|
||||||
<td x-text="csqData.CHANNEL"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>PCI</th>
|
|
||||||
<td x-text="csqData.PCI"></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function signalInfo() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
atcmd: 'AT+QSPN;+CEREG=2;+CEREG?;+CEREG=0;+C5GREG=2;+C5GREG?;+C5GREG=0;+CSQ;+QENG=\"servingcell\";+QRSRP;+QCAINFO;+QNWPREFCFG=\"mode_pref\";+QTEMP\r\n',
|
|
||||||
atCommandResponse: null,
|
|
||||||
refreshSignal() {
|
|
||||||
this.isLoading = true; // Set loading state to true before fetching data
|
|
||||||
fetch(
|
|
||||||
"/cgi-bin/get_atcommand?" +
|
|
||||||
new URLSearchParams({
|
|
||||||
atcmd: this.atcmd,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
return res.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.atCommandResponse = data;
|
|
||||||
// Split the response into individual messages
|
|
||||||
const messages = data.trim().split("\n\n");
|
|
||||||
|
|
||||||
// Convert the messages into a JSON file
|
|
||||||
//TODO: Add the JSON conversion here
|
|
||||||
|
|
||||||
|
|
||||||
// Log the parsed messages array as JSON to the console
|
|
||||||
console.log(JSON.stringify(parsedMessages, null, 2));
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Something went wrong", error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isLoading = false; // Set loading state to false after fetching data
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function getSignalData() {
|
|
||||||
return {
|
|
||||||
csqData: {},
|
|
||||||
lastUpdate: new Date().toLocaleString(),
|
|
||||||
getcsq() {
|
|
||||||
fetch("/cgi-bin/get_csq")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
this.csqData = data;
|
|
||||||
this.lastUpdate = new Date(
|
|
||||||
data.LASTUPDATE * 1000
|
|
||||||
).toLocaleString();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
init() {
|
|
||||||
this.getcsq();
|
|
||||||
setInterval(() => {
|
|
||||||
this.getcsq();
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
7
simpleadmin/www/js/bootstrap.bundle.min.js
vendored
Normal file
7
simpleadmin/www/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
29
simpleadmin/www/js/dark-mode.js
Normal file
29
simpleadmin/www/js/dark-mode.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 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);
|
||||||
37
simpleadmin/www/js/generate-freq-box.js
Normal file
37
simpleadmin/www/js/generate-freq-box.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
58
simpleadmin/www/js/parse-settings.js
Normal file
58
simpleadmin/www/js/parse-settings.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
76
simpleadmin/www/js/populate-checkbox.js
Normal file
76
simpleadmin/www/js/populate-checkbox.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
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,55 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<!-- change to a much simpler tab title -->
|
|
||||||
<title>Simple Admin</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
class="navbar-burger burger"
|
|
||||||
@click="isOpen = !isOpen"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="navMenu"
|
|
||||||
class="navbar-menu"
|
|
||||||
:class="isOpen ? 'is-active' : ''"
|
|
||||||
>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.location=window.location.href.replace(/:\/\//, '://log:out@');
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
933
simpleadmin/www/network.html
Normal file
933
simpleadmin/www/network.html
Normal file
@@ -0,0 +1,933 @@
|
|||||||
|
<!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: null,
|
||||||
|
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>
|
||||||
667
simpleadmin/www/settings.html
Normal file
667
simpleadmin/www/settings.html
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
<!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,118 +1,291 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html lang="en" data-bs-theme="light">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<!-- change to a much simpler tab title -->
|
<title>Simple Admin</title>
|
||||||
<title>SMS Viewer</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/alpinejs.min.js" defer></script>
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
<script src="/js/auth.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
</head>
|
||||||
|
<body onload="isAuthenticated()">
|
||||||
<body>
|
<main>
|
||||||
<!-- START NAV -->
|
<div class="container my-4" x-data="fetchSMS()">
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
<nav class="navbar navbar-expand-lg mt-2">
|
||||||
<div class="container">
|
<div class="container-fluid">
|
||||||
<div class="navbar-brand">
|
<a class="navbar-brand" href="/"
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
><span class="mb-0 h4">Simple Admin</span></a
|
||||||
<a
|
>
|
||||||
role="button"
|
<button
|
||||||
class="navbar-burger burger"
|
class="navbar-toggler"
|
||||||
@click="isOpen = !isOpen"
|
type="button"
|
||||||
>
|
data-bs-toggle="collapse"
|
||||||
<span aria-hidden="true"></span>
|
data-bs-target="#navbarText"
|
||||||
<span aria-hidden="true"></span>
|
aria-controls="navbarText"
|
||||||
<span aria-hidden="true"></span>
|
aria-expanded="false"
|
||||||
</a>
|
aria-label="Toggle navigation"
|
||||||
</div>
|
>
|
||||||
<div
|
<span class="navbar-toggler-icon"></span>
|
||||||
id="navMenu"
|
</button>
|
||||||
class="navbar-menu"
|
<div class="collapse navbar-collapse" id="navbarText">
|
||||||
:class="isOpen ? 'is-active' : ''"
|
<ul class="navbar-nav me-auto mb-2 ml-4 mb-lg-0">
|
||||||
>
|
<li class="nav-item">
|
||||||
<div class="navbar-start">
|
<a class="nav-link" href="/">Home</a>
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
</li>
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
<li class="nav-item">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
</li>
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
<li class="nav-item">
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
</li>
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
<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>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</div>
|
|
||||||
</nav>
|
<div class="row mt-5 mb-4">
|
||||||
<!-- END NAV -->
|
<div class="col">
|
||||||
<div class="container" x-data="atCommands()">
|
<div class="card">
|
||||||
<div class="columns">
|
<div class="card-header">SMS Manager</div>
|
||||||
<div class="column is-12">
|
<div class="card-body">
|
||||||
<div class="columns">
|
<div class="card-text">
|
||||||
<div class="column is-8">
|
<div class="col">
|
||||||
<div class="card">
|
<div
|
||||||
<header class="card-header">
|
style="
|
||||||
<p class="card-header-title">SMS Viewer</p>
|
max-height: 400px;
|
||||||
<div class="field">
|
overflow-y: scroll;
|
||||||
<p class="control">
|
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
|
<button
|
||||||
class="button is-success"
|
class="btn btn-success"
|
||||||
@click="sendAtCommand()"
|
type="button"
|
||||||
:disabled="isLoading"
|
@click="init()"
|
||||||
>
|
>
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<p class="control">
|
|
||||||
<button
|
<button
|
||||||
class="button is-danger"
|
class="btn btn-danger"
|
||||||
@click="sendAtCommand()"
|
type="button"
|
||||||
:disabled="isLoading"
|
@click="deleteAllSMS()"
|
||||||
>
|
>
|
||||||
Delete
|
Delete All SMS
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<textarea
|
|
||||||
class="textarea"
|
|
||||||
placeholder="SMS Viewer (Make sure to run: AT+CMGF=1 first)"
|
|
||||||
readonly
|
|
||||||
rows="10"
|
|
||||||
cols="50"
|
|
||||||
x-model="atCommandResponse"
|
|
||||||
:disabled="isLoading"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
|
<script src="/js/dark-mode.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function atCommands() {
|
function fetchSMS() {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
atCommandResponse: "",
|
atCommandResponse: "",
|
||||||
// get the SMS list through cgi-bin/get_sms
|
messageToSend: "",
|
||||||
sendAtCommand() {
|
phoneNumber: "",
|
||||||
|
messages: [],
|
||||||
|
senders: [],
|
||||||
|
dates: [],
|
||||||
|
requestSMS() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
this.atCommandResponse = "Loading...";
|
||||||
|
// Expect a text response from the server
|
||||||
fetch("/cgi-bin/get_sms")
|
fetch("/cgi-bin/get_sms")
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.atCommandResponse = data;
|
|
||||||
console.log(data);
|
|
||||||
this.isLoading = false;
|
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();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Speedtest</title>
|
|
||||||
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css" />
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div
|
|
||||||
class="container"
|
|
||||||
>
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/"> Simple Admin </a>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
class="navbar-burger burger"
|
|
||||||
@click="isOpen = !isOpen"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="navMenu"
|
|
||||||
class="navbar-menu"
|
|
||||||
:class="isOpen ? 'is-active' : ''"
|
|
||||||
>
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
<div class="container">
|
|
||||||
<!--OST Widget code start-->
|
|
||||||
<div style="text-align: right">
|
|
||||||
<div style="min-height: 360px">
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
padding-bottom: 50%;
|
|
||||||
position: relative;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
style="
|
|
||||||
border: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 360px;
|
|
||||||
border: none;
|
|
||||||
overflow: hidden !important;
|
|
||||||
"
|
|
||||||
src="//openspeedtest.com/speedtest"
|
|
||||||
></iframe>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- OST Widget code end -->
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/* Google Poppins */
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
|
||||||
|
|
||||||
*{
|
|
||||||
font-family: 'Poppins', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
|
||||||
border-left-color: #333;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
margin: 0 auto 10px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
11
simpleadmin/www/systemd/simpleadmin_httpd.service
Normal file
11
simpleadmin/www/systemd/simpleadmin_httpd.service
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
simpleadmin_httpd.service[Unit]
|
||||||
|
Description=SimpleAdmin httpd service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/sbin/httpd -f -h /usrdata/simpleadmin/www -p 8080
|
||||||
|
ExecStop=/bin/kill -WINCH ${MAINPID}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>TTL Changer</title>
|
|
||||||
|
|
||||||
<script src="/js/alpinejs.min.js" defer></script>
|
|
||||||
<link rel="stylesheet" href="/css/bulma.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/admin.css">
|
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- START NAV -->
|
|
||||||
<nav class="navbar is-black" x-data="{ isOpen: false }">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item brand-text" href="/">
|
|
||||||
Simple Admin
|
|
||||||
</a>
|
|
||||||
<a role="button" class="navbar-burger burger" @click="isOpen = !isOpen">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div id="navMenu" class="navbar-menu" :class="isOpen ? 'is-active' : ''">
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="/"> Connection Info </a>
|
|
||||||
<a class="navbar-item" href="/atcommander.html"> AT Commands </a>
|
|
||||||
<a class="navbar-item" href="/bandlock.html"> Simple Network </a>
|
|
||||||
<a class="navbar-item" href="/sms.html"> SMS </a>
|
|
||||||
<a class="navbar-item" href="/ttl.html"> TTL Changer </a>
|
|
||||||
<a class="navbar-item" href="/speedtest.html"> OpenSpeedtest </a>
|
|
||||||
<a class="navbar-item" href="/console"> Console </a>
|
|
||||||
<a class="navbar-item" href="/logout.html"> Logout </a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- END NAV -->
|
|
||||||
<div class="container" x-data="ttlCommands()" x-init="init">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-12">
|
|
||||||
<div class="columns">
|
|
||||||
<div class="column is-8">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">
|
|
||||||
TTL Enabler
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<p>
|
|
||||||
<h2>TTL Status</h2> <br>
|
|
||||||
TTL is <span class="tag is-large"
|
|
||||||
:class="ttldata.isEnabled ? 'is-success' : 'is-danger'"
|
|
||||||
x-text="ttldata.isEnabled == true ? 'ON' : 'OFF'"></span>
|
|
||||||
<br />
|
|
||||||
TTL Set to <span x-text="ttldata.ttl"></span>
|
|
||||||
</p>
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">Set TTL</label>
|
|
||||||
<div class="control">
|
|
||||||
<input class="input" type="number" placeholder="64" x-model="newTTL">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<button class="button is-link" @click="setTTL()">Set TTL</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column is-4">
|
|
||||||
<div class="card">
|
|
||||||
<header class="card-header">
|
|
||||||
<p class="card-header-title">
|
|
||||||
Common TTL For Providers
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="content">
|
|
||||||
<ul>
|
|
||||||
<li>Magenta: 65</li>
|
|
||||||
<li>Red: 88</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
function ttlCommands() {
|
|
||||||
return {
|
|
||||||
isLoading: false,
|
|
||||||
ttldata: null,
|
|
||||||
newTTL: 0,
|
|
||||||
init() {
|
|
||||||
fetch('/cgi-bin/get_ttl_status')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
this.ttldata = data
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setTTL() {
|
|
||||||
fetch('/cgi-bin/set_ttl?' + new URLSearchParams({
|
|
||||||
ttlvalue: this.newTTL,
|
|
||||||
}))
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
this.ttldata = data
|
|
||||||
})
|
|
||||||
sleep(1000)
|
|
||||||
fetch('/cgi-bin/get_ttl_status')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
this.ttldata = data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function sleep(miliseconds) {
|
|
||||||
var currentTime = new Date().getTime();
|
|
||||||
while (currentTime + miliseconds >= new Date().getTime()) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user