Merge pull request #83 from dr-dolomite/QuecManager
Added Cellular Settings Functionality
This commit is contained in:
@@ -63,12 +63,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link"> Cellular </a>
|
<a class="navbar-link"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
|
>Cell Settings</a
|
||||||
|
>
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
|
||||||
>Cell Settings</a
|
|
||||||
>
|
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -66,12 +66,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link"> Cellular </a>
|
<a class="navbar-link"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -255,7 +255,9 @@
|
|||||||
|
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Connected Devices MAC</label>
|
<label class="label"
|
||||||
|
>Connected Devices MAC</label
|
||||||
|
>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select id="connected-devices">
|
<select id="connected-devices">
|
||||||
@@ -287,7 +289,9 @@
|
|||||||
Select USB Modem Protocol
|
Select USB Modem Protocol
|
||||||
</option>
|
</option>
|
||||||
<option value="RMNET">RMNET</option>
|
<option value="RMNET">RMNET</option>
|
||||||
<option value="ECM (Recommended)">ECM (Recommended)</option>
|
<option value="ECM (Recommended)">
|
||||||
|
ECM (Recommended)
|
||||||
|
</option>
|
||||||
<option value="MBIM">MBIM</option>
|
<option value="MBIM">MBIM</option>
|
||||||
<option value="RNDIS">RNDIS</option>
|
<option value="RNDIS">RNDIS</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -297,7 +301,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Selecting a mode will apply immediately. Requires reboot.
|
Selecting a mode will apply immediately. Requires
|
||||||
|
reboot.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,12 +63,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,12 +63,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,12 +63,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,7 +89,10 @@
|
|||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons is-flex-direction-column-mobile">
|
<div class="buttons is-flex-direction-column-mobile">
|
||||||
<div class="control is-expanded-mobile">
|
<div class="control is-expanded-mobile">
|
||||||
<div id="restartConnectionBtn" class="button is-link is-outlined is-fullwidth-mobile">
|
<div
|
||||||
|
id="restartConnectionBtn"
|
||||||
|
class="button is-link is-outlined is-fullwidth-mobile"
|
||||||
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fas fa-arrows-rotate"></i>
|
<i class="fas fa-arrows-rotate"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
<script src="/js/styles/modal-trigger.js"></script>
|
<script src="/js/styles/modal-trigger.js"></script>
|
||||||
<script src="/js/utils/reboot.js"></script>
|
<script src="/js/utils/reboot.js"></script>
|
||||||
<script src="/js/utils/restart-connection.js"></script>
|
<script src="/js/utils/restart-connection.js"></script>
|
||||||
|
<script src="/js/cell-settings/fetch-settings.js"></script>
|
||||||
|
<script src="/js/cell-settings/apn-profile.js"></script>
|
||||||
<script defer src="/js/auth/auth.js"></script>
|
<script defer src="/js/auth/auth.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -63,12 +65,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,7 +91,10 @@
|
|||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons is-flex-direction-column-mobile">
|
<div class="buttons is-flex-direction-column-mobile">
|
||||||
<div class="control is-expanded-mobile">
|
<div class="control is-expanded-mobile">
|
||||||
<div id="restartConnectionBtn" class="button is-link is-outlined is-fullwidth-mobile">
|
<div
|
||||||
|
id="restartConnectionBtn"
|
||||||
|
class="button is-link is-outlined is-fullwidth-mobile"
|
||||||
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fas fa-arrows-rotate"></i>
|
<i class="fas fa-arrows-rotate"></i>
|
||||||
</span>
|
</span>
|
||||||
@@ -136,228 +141,233 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="column-margin">
|
<div class="column-margin">
|
||||||
<div class="fixed-grid has-2-cols has-1-cols-mobile">
|
<div class="columns">
|
||||||
<div class="grid">
|
<div class="column">
|
||||||
<div class="cell">
|
<div class="card">
|
||||||
<div class="card">
|
<div class="card-header">
|
||||||
<div class="card-header">
|
<div class="card-header-title">Basic Cellular Settings</div>
|
||||||
<div class="card-header-title">Basic Cellular Settings</div>
|
</div>
|
||||||
</div>
|
<div class="card-content">
|
||||||
<div class="card-content">
|
<div class="fixed-grid has-2-cols has-1-cols-mobile">
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="grid is-gap-5">
|
||||||
<div class="grid is-gap-5">
|
<div class="cell">
|
||||||
<div class="cell">
|
<div class="field">
|
||||||
<div class="field">
|
<label class="label">Current APN</label>
|
||||||
<label class="label">Current APN</label>
|
<div class="control">
|
||||||
<div class="control">
|
<input
|
||||||
<input
|
class="input"
|
||||||
class="input"
|
type="text"
|
||||||
type="text"
|
placeholder="Current APN Here"
|
||||||
placeholder="Current APN Here"
|
id="currentAPN"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<p class="help">
|
|
||||||
Changing this will disable automatic APN.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
Changing this will disable automatic APN.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">APN PDP Type</label>
|
<label class="label">APN PDP Type</label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select>
|
<select id="apnPDP">
|
||||||
<option selected>Select APN PDP Type</option>
|
<option selected>Select APN PDP Type</option>
|
||||||
<option>IPv4 Only</option>
|
<option value="IP">IPv4 Only</option>
|
||||||
<option>IPv6 Only</option>
|
<option value="IPV6">IPv6 Only</option>
|
||||||
<option>IPv4 and IPv6</option>
|
<option value="IPV4V6">IPv4 and IPv6</option>
|
||||||
<option>P2P Protocol</option>
|
<option value="PPP">P2P Protocol</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="fas fa-globe"></i>
|
<i class="fas fa-globe"></i>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Preferred Network Mode</label>
|
<label class="label">Preferred Network Mode</label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select>
|
<select id="networkPreference">
|
||||||
<option selected>
|
<option value="placeholder" selected>
|
||||||
Select Preferred Network Mode
|
Select Preferred Network Mode
|
||||||
</option>
|
</option>
|
||||||
<option>Automatic</option>
|
<option value="AUTO">Automatic</option>
|
||||||
<option>LTE Only</option>
|
<option value="LTE">LTE Only</option>
|
||||||
<option>5G SA Only</option>
|
<option value="NR5G">5G SA Only</option>
|
||||||
<option>5G NSA Only</option>
|
<option value="NR5G:LTE">5G NSA Only</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="fas fa-signal"></i>
|
<i class="fas fa-signal"></i>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
<p class="help">
|
||||||
|
Selecting a mode will apply immediately.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">NR5G Mode Control</label>
|
<label class="label">NR5G Mode Control</label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select>
|
<select id="nr5gModeControl">
|
||||||
<option selected>Select NR5G Mode Control</option>
|
<option selected>Select NR5G Mode Control</option>
|
||||||
<option>Enable NR5G SA and NSA</option>
|
<option value="0">Enable NR5G SA and NSA</option>
|
||||||
<option>Enable SA Only</option>
|
<option value="2">Enable SA Only</option>
|
||||||
<option>Enable NSA Only</option>
|
<option value="1">Enable NSA Only</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
<i class="fas fa-podcast"></i>
|
<i class="fas fa-podcast"></i>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
<p class="help">
|
||||||
|
Selecting a mode will apply immediately.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
</div>
|
||||||
<a
|
<div class="card-footer">
|
||||||
href="#"
|
<a
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
href="#"
|
||||||
>
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
Save
|
>
|
||||||
</a>
|
Save APN
|
||||||
<a
|
</a>
|
||||||
href="#"
|
<a
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
href="#"
|
||||||
>
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
Reset
|
>
|
||||||
</a>
|
Reset APN
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card" id="apnProfileForm">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-header-title">APN and ICCID Based Locking</div>
|
<div class="card-header-title">APN and ICCID Based Locking</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="fixed-grid has-1-cols">
|
<div class="fixed-grid has-1-cols">
|
||||||
<div class="grid is-gap-5">
|
<div class="grid is-gap-5">
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="fixed-grid has-2-cols has-1-cols-mobile">
|
||||||
<div class="grid is-gap-3">
|
<div class="grid is-gap-3">
|
||||||
<div class="cell">
|
<div class="cell is-col-span-2-mobile">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">APN Profile 1</label>
|
<label class="label">APN Profile 1</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="APN Here"
|
placeholder="APN Here"
|
||||||
/>
|
id="apnProfile1"
|
||||||
</div>
|
/>
|
||||||
<p class="help">
|
|
||||||
This will override the current APN.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
This will override the current APN.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell is-col-span-2-mobile">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">APN PDP Type</label>
|
<label class="label">APN PDP Type</label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select>
|
<select id="apnPDPType1">
|
||||||
<option selected>
|
<option selected>Select APN PDP Type</option>
|
||||||
Select APN PDP Type
|
<option value="IP">IPv4 Only</option>
|
||||||
</option>
|
<option value="IPV6">IPv6 Only</option>
|
||||||
<option>IPv4 Only</option>
|
<option value="IPV4V6">IPv4 and IPv6</option>
|
||||||
<option>IPv6 Only</option>
|
<option value="PPP">P2P Protocol</option>
|
||||||
<option>IPv4 and IPv6</option>
|
</select>
|
||||||
<option>P2P Protocol</option>
|
</span>
|
||||||
</select>
|
<span class="icon is-small is-left">
|
||||||
</span>
|
<i class="fas fa-globe"></i>
|
||||||
<span class="icon is-small is-left">
|
</span>
|
||||||
<i class="fas fa-globe"></i>
|
</p>
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell is-col-span-2">
|
<div class="cell is-col-span-2">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">ICCID Profile 1</label>
|
<label class="label">ICCID Profile 1</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="ICCID Here"
|
placeholder="ICCID Here"
|
||||||
/>
|
id="iccidProfile1"
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="fixed-grid has-2-cols">
|
||||||
<div class="grid is-gap-3">
|
<div class="grid is-gap-3">
|
||||||
<div class="cell">
|
<div class="cell is-col-span-2-mobile">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">APN Profile 2</label>
|
<label class="label">APN Profile 2</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="APN Here"
|
placeholder="APN Here"
|
||||||
/>
|
id="apnProfile2"
|
||||||
</div>
|
/>
|
||||||
<p class="help">
|
|
||||||
This will override the current APN.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
This will override the current APN.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="cell is-col-span-2-mobile">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">APN PDP Type</label>
|
<label class="label">APN PDP Type</label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<span class="select">
|
<span class="select">
|
||||||
<select>
|
<select id="apnPDPType2">
|
||||||
<option selected>
|
<option selected>Select APN PDP Type</option>
|
||||||
Select APN PDP Type
|
<option value="IP">IPv4 Only</option>
|
||||||
</option>
|
<option value="IPV6">IPv6 Only</option>
|
||||||
<option>IPv4 Only</option>
|
<option value="IPV4V6">IPv4 and IPv6</option>
|
||||||
<option>IPv6 Only</option>
|
<option value="PPP">P2P Protocol</option>
|
||||||
<option>IPv4 and IPv6</option>
|
</select>
|
||||||
<option>P2P Protocol</option>
|
</span>
|
||||||
</select>
|
<span class="icon is-small is-left">
|
||||||
</span>
|
<i class="fas fa-globe"></i>
|
||||||
<span class="icon is-small is-left">
|
</span>
|
||||||
<i class="fas fa-globe"></i>
|
</p>
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell is-col-span-2">
|
<div class="cell is-col-span-2">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">ICCID Profile 2</label>
|
<label class="label">ICCID Profile 2</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="ICCID Here"
|
placeholder="ICCID Here"
|
||||||
/>
|
id="iccidProfile2"
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -366,20 +376,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
</div>
|
||||||
<a
|
<div class="card-footer">
|
||||||
href="#"
|
<a
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
href="#"
|
||||||
>
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
Save
|
id="saveAPNProfile"
|
||||||
</a>
|
>
|
||||||
<a
|
Save APN Profile
|
||||||
href="#"
|
</a>
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
<a
|
||||||
>
|
href="#"
|
||||||
Reset
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
</a>
|
id="resetAPNProfile"
|
||||||
</div>
|
>
|
||||||
|
Reset APN Profile
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,12 +63,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
<a class="navbar-link has-text-weight-bold"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
>Cell Settings</a
|
>Cell Settings</a
|
||||||
>
|
>
|
||||||
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,7 +89,10 @@
|
|||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons is-flex-direction-column-mobile">
|
<div class="buttons is-flex-direction-column-mobile">
|
||||||
<div class="control is-expanded-mobile">
|
<div class="control is-expanded-mobile">
|
||||||
<div id="restartConnectionBtn" class="button is-link is-outlined is-fullwidth-mobile">
|
<div
|
||||||
|
id="restartConnectionBtn"
|
||||||
|
class="button is-link is-outlined is-fullwidth-mobile"
|
||||||
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fas fa-arrows-rotate"></i>
|
<i class="fas fa-arrows-rotate"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
153
www/cgi-bin/apn-profile.sh
Normal file
153
www/cgi-bin/apn-profile.sh
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Parse POST data
|
||||||
|
read -r QUERY_STRING
|
||||||
|
|
||||||
|
# Function to urldecode
|
||||||
|
urldecode() {
|
||||||
|
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract values from POST data
|
||||||
|
iccidProfile1=$(echo "$QUERY_STRING" | grep -o 'iccidProfile1=[^&]*' | cut -d= -f2)
|
||||||
|
apnProfile1=$(echo "$QUERY_STRING" | grep -o 'apnProfile1=[^&]*' | cut -d= -f2)
|
||||||
|
pdpType1=$(echo "$QUERY_STRING" | grep -o 'pdpType1=[^&]*' | cut -d= -f2)
|
||||||
|
iccidProfile2=$(echo "$QUERY_STRING" | grep -o 'iccidProfile2=[^&]*' | cut -d= -f2)
|
||||||
|
apnProfile2=$(echo "$QUERY_STRING" | grep -o 'apnProfile2=[^&]*' | cut -d= -f2)
|
||||||
|
pdpType2=$(echo "$QUERY_STRING" | grep -o 'pdpType2=[^&]*' | cut -d= -f2)
|
||||||
|
|
||||||
|
# URL decode the values
|
||||||
|
iccidProfile1=$(urldecode "$iccidProfile1")
|
||||||
|
apnProfile1=$(urldecode "$apnProfile1")
|
||||||
|
pdpType1=$(urldecode "$pdpType1")
|
||||||
|
iccidProfile2=$(urldecode "$iccidProfile2")
|
||||||
|
apnProfile2=$(urldecode "$apnProfile2")
|
||||||
|
pdpType2=$(urldecode "$pdpType2")
|
||||||
|
|
||||||
|
echo "Content-type: application/json"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Validate required first profile
|
||||||
|
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
|
||||||
|
echo '{"status": "error", "message": "Profile 1 is required"}'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the directory structure
|
||||||
|
mkdir -p /etc/quecmanager
|
||||||
|
|
||||||
|
# Create a configuration file to store APN profiles (as plain text)
|
||||||
|
cat > /etc/quecmanager/apn_config.txt << EOF
|
||||||
|
iccidProfile1=$iccidProfile1
|
||||||
|
apnProfile1=$apnProfile1
|
||||||
|
pdpType1=$pdpType1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add second profile only if ICCID is provided
|
||||||
|
if [ -n "$iccidProfile2" ]; then
|
||||||
|
cat >> /etc/quecmanager/apn_config.txt << EOF
|
||||||
|
iccidProfile2=$iccidProfile2
|
||||||
|
apnProfile2=$apnProfile2
|
||||||
|
pdpType2=$pdpType2
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the apnProfiles.sh script
|
||||||
|
cat > /etc/quecmanager/apnProfiles.sh << 'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Function to read config values
|
||||||
|
get_config_value() {
|
||||||
|
local key=$1
|
||||||
|
grep "^${key}=" /etc/quecmanager/apn_config.txt | cut -d'=' -f2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read configuration
|
||||||
|
iccidProfile1=$(get_config_value "iccidProfile1")
|
||||||
|
apnProfile1=$(get_config_value "apnProfile1")
|
||||||
|
pdpType1=$(get_config_value "pdpType1")
|
||||||
|
iccidProfile2=$(get_config_value "iccidProfile2")
|
||||||
|
apnProfile2=$(get_config_value "apnProfile2")
|
||||||
|
pdpType2=$(get_config_value "pdpType2")
|
||||||
|
|
||||||
|
# Function to get current ICCID
|
||||||
|
get_current_iccid() {
|
||||||
|
local input_file="/tmp/inputICCID.txt"
|
||||||
|
local output_file="/tmp/outputICCID.txt"
|
||||||
|
|
||||||
|
echo "AT+ICCID" > "$input_file"
|
||||||
|
atinout "$input_file" /dev/smd11 "$output_file"
|
||||||
|
|
||||||
|
iccid=$(cat "$output_file" | grep "+ICCID:" | cut -d' ' -f2)
|
||||||
|
|
||||||
|
rm -f "$input_file" "$output_file"
|
||||||
|
echo "$iccid"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set APN
|
||||||
|
set_apn() {
|
||||||
|
local pdp_type="$1"
|
||||||
|
local apn="$2"
|
||||||
|
local input_file="/tmp/inputAPN.txt"
|
||||||
|
local output_file="/tmp/outputAPN.txt"
|
||||||
|
|
||||||
|
echo "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0" > "$input_file"
|
||||||
|
atinout "$input_file" /dev/smd11 "$output_file"
|
||||||
|
|
||||||
|
local result=$(cat "$output_file")
|
||||||
|
rm -f "$input_file" "$output_file"
|
||||||
|
|
||||||
|
if echo "$result" | grep -q "OK"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get current ICCID
|
||||||
|
current_iccid=$(get_current_iccid)
|
||||||
|
success=false
|
||||||
|
|
||||||
|
# Check ICCID against profile 1 (required)
|
||||||
|
if [ "$current_iccid" = "$iccidProfile1" ]; then
|
||||||
|
if set_apn "$pdpType1" "$apnProfile1"; then
|
||||||
|
success=true
|
||||||
|
fi
|
||||||
|
# Check ICCID against profile 2 (optional)
|
||||||
|
elif [ -n "$iccidProfile2" ] && [ "$current_iccid" = "$iccidProfile2" ]; then
|
||||||
|
if set_apn "$pdpType2" "$apnProfile2"; then
|
||||||
|
success=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$success" = "true" ]; then
|
||||||
|
echo "APN set successfully" > /tmp/apn_result.txt
|
||||||
|
else
|
||||||
|
echo "Failed to set APN" > /tmp/apn_result.txt
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x /etc/quecmanager/apnProfiles.sh
|
||||||
|
|
||||||
|
# Add to rc.local if not already present
|
||||||
|
if ! grep -q "/etc/quecmanager/apnProfiles.sh" /etc/rc.local; then
|
||||||
|
sed -i '/^exit 0/i /etc/quecmanager/apnProfiles.sh' /etc/rc.local
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the script immediately
|
||||||
|
/etc/quecmanager/apnProfiles.sh
|
||||||
|
|
||||||
|
# Check the result
|
||||||
|
if [ -f /tmp/apn_result.txt ]; then
|
||||||
|
result=$(cat /tmp/apn_result.txt)
|
||||||
|
rm -f /tmp/apn_result.txt
|
||||||
|
|
||||||
|
if [ "$result" = "APN set successfully" ]; then
|
||||||
|
echo '{"status": "success", "message": "APN profiles saved and applied successfully"}'
|
||||||
|
else
|
||||||
|
echo '{"status": "error", "message": "APN profiles saved but failed to apply"}'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo '{"status": "error", "message": "Something went wrong while processing APN profiles"}'
|
||||||
|
fi
|
||||||
66
www/cgi-bin/cell-settings.sh
Normal file
66
www/cgi-bin/cell-settings.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Set content-type for JSON response
|
||||||
|
echo "Content-type: application/json"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Define the lock file
|
||||||
|
LOCK_FILE="/tmp/home_data.lock"
|
||||||
|
|
||||||
|
# Acquire the lock (wait if needed)
|
||||||
|
exec 200>$LOCK_FILE
|
||||||
|
flock -x 200
|
||||||
|
|
||||||
|
# Temporary files for input/output and AT port
|
||||||
|
INPUT_FILE="/tmp/input_$$.txt"
|
||||||
|
OUTPUT_FILE="/tmp/output_$$.txt"
|
||||||
|
AT_PORT="/dev/smd11"
|
||||||
|
|
||||||
|
# Debug file path
|
||||||
|
DEBUG_FILE="/tmp/debug-json-result.txt"
|
||||||
|
|
||||||
|
# Function to escape JSON strings (handling quotes and newlines)
|
||||||
|
escape_json() {
|
||||||
|
# Escape newlines and double quotes
|
||||||
|
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize JSON response array
|
||||||
|
JSON_RESPONSE="["
|
||||||
|
|
||||||
|
# List of AT commands to run, one by one
|
||||||
|
for COMMAND in 'AT+CGDCONT?' 'AT+QNWPREFCFG="mode_pref"' 'AT+QNWPREFCFG="nr5g_disable_mode"'; do
|
||||||
|
# Write the command to the input file
|
||||||
|
echo "$COMMAND" > "$INPUT_FILE"
|
||||||
|
|
||||||
|
# Run the command using atinout
|
||||||
|
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
|
||||||
|
|
||||||
|
# Read the output from the output file
|
||||||
|
OUTPUT=$(cat "$OUTPUT_FILE")
|
||||||
|
|
||||||
|
# Escape special characters for JSON (escape only output)
|
||||||
|
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
|
||||||
|
|
||||||
|
# Append the response as an object to the JSON response array
|
||||||
|
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove the trailing comma and close the JSON array
|
||||||
|
if [ "${JSON_RESPONSE: -1}" = "," ]; then
|
||||||
|
JSON_RESPONSE="${JSON_RESPONSE%,}]"
|
||||||
|
else
|
||||||
|
JSON_RESPONSE="${JSON_RESPONSE}]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Write the JSON response to the debug file for troubleshooting
|
||||||
|
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
|
||||||
|
|
||||||
|
# Return the output as a valid JSON response
|
||||||
|
echo "$JSON_RESPONSE"
|
||||||
|
|
||||||
|
# Clean up temporary files
|
||||||
|
rm "$INPUT_FILE" "$OUTPUT_FILE"
|
||||||
|
|
||||||
|
# Release the lock
|
||||||
|
flock -u 200
|
||||||
45
www/cgi-bin/fetch-apn-profiles.sh
Normal file
45
www/cgi-bin/fetch-apn-profiles.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Content-type: application/json"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
CONFIG_FILE="/etc/quecmanager/apn_config.txt"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
echo '{"status": "error", "message": "No APN profiles found", "profiles": {}}'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to read config values
|
||||||
|
get_config_value() {
|
||||||
|
local key=$1
|
||||||
|
local value=$(grep "^${key}=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read all profile values
|
||||||
|
iccidProfile1=$(get_config_value "iccidProfile1")
|
||||||
|
apnProfile1=$(get_config_value "apnProfile1")
|
||||||
|
pdpType1=$(get_config_value "pdpType1")
|
||||||
|
iccidProfile2=$(get_config_value "iccidProfile2")
|
||||||
|
apnProfile2=$(get_config_value "apnProfile2")
|
||||||
|
pdpType2=$(get_config_value "pdpType2")
|
||||||
|
|
||||||
|
# Construct JSON response
|
||||||
|
cat << EOF
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"profiles": {
|
||||||
|
"profile1": {
|
||||||
|
"iccid": "${iccidProfile1:-}",
|
||||||
|
"apn": "${apnProfile1:-}",
|
||||||
|
"pdpType": "${pdpType1:-}"
|
||||||
|
},
|
||||||
|
"profile2": {
|
||||||
|
"iccid": "${iccidProfile2:-}",
|
||||||
|
"apn": "${apnProfile2:-}",
|
||||||
|
"pdpType": "${pdpType2:-}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
@@ -29,7 +29,7 @@ escape_json() {
|
|||||||
JSON_RESPONSE="["
|
JSON_RESPONSE="["
|
||||||
|
|
||||||
# List of AT commands to run, one by one
|
# List of AT commands to run, one by one
|
||||||
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGCONTRDP=1" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
|
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGDCONT?" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
|
||||||
# Write the command to the input file
|
# Write the command to the input file
|
||||||
echo "$COMMAND" > "$INPUT_FILE"
|
echo "$COMMAND" > "$INPUT_FILE"
|
||||||
|
|
||||||
|
|||||||
@@ -268,4 +268,67 @@ html.theme-light {
|
|||||||
|
|
||||||
.isCursorPointer {
|
.isCursorPointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For APN Profiles */
|
||||||
|
.notification {
|
||||||
|
position: relative;
|
||||||
|
padding: 1.25rem 2.5rem 1.25rem 1.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.is-success {
|
||||||
|
background-color: #48c78e;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.is-danger {
|
||||||
|
background-color: #f14668;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .delete {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5rem;
|
||||||
|
top: 0.5rem;
|
||||||
|
background-color: rgba(10, 10, 10, 0.2);
|
||||||
|
border: none;
|
||||||
|
border-radius: 290486px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-loading {
|
||||||
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-loading:after {
|
||||||
|
animation: spinAround 500ms infinite linear;
|
||||||
|
border: 2px solid #dbdbdb;
|
||||||
|
border-radius: 290486px;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
height: 1em;
|
||||||
|
position: absolute;
|
||||||
|
width: 1em;
|
||||||
|
position: absolute;
|
||||||
|
left: calc(50% - (1em / 2));
|
||||||
|
top: calc(50% - (1em / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.is-danger,
|
||||||
|
.select.is-danger select {
|
||||||
|
border-color: #f14668;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinAround {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(359deg); }
|
||||||
}
|
}
|
||||||
@@ -64,12 +64,12 @@
|
|||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link"> Cellular </a>
|
<a class="navbar-link"> Cellular </a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
|
<a class="navbar-item" href="/cell-settings.html"
|
||||||
|
>Cell Settings</a
|
||||||
|
>
|
||||||
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
|
||||||
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
|
||||||
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
|
||||||
<a class="navbar-item" href="/cell-settings.html"
|
|
||||||
>Cell Settings</a
|
|
||||||
>
|
|
||||||
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
179
www/js/cell-settings/apn-profile.js
Normal file
179
www/js/cell-settings/apn-profile.js
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const form = document.getElementById('apnProfileForm');
|
||||||
|
|
||||||
|
// Helper function to show notifications
|
||||||
|
function showNotification(message, isError = false) {
|
||||||
|
// Remove existing notification if any
|
||||||
|
const existingNotification = form.previousElementSibling;
|
||||||
|
if (existingNotification && existingNotification.classList.contains('notification')) {
|
||||||
|
existingNotification.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.className = `notification ${isError ? 'is-danger' : 'is-success'} is-light`;
|
||||||
|
notification.innerHTML = `
|
||||||
|
<button class="delete"></button>
|
||||||
|
${message}
|
||||||
|
`;
|
||||||
|
|
||||||
|
form.insertAdjacentElement('beforebegin', notification);
|
||||||
|
|
||||||
|
// Remove notification after 5 seconds
|
||||||
|
setTimeout(() => notification.remove(), 5000);
|
||||||
|
|
||||||
|
// Allow manual close
|
||||||
|
notification.querySelector('.delete').addEventListener('click', () => notification.remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate ICCID format
|
||||||
|
function validateICCID(iccid) {
|
||||||
|
return /^\d{19,20}$/.test(iccid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate APN format
|
||||||
|
function validateAPN(apn) {
|
||||||
|
return /^[a-zA-Z0-9.-]+$/.test(apn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to set select element value
|
||||||
|
function setSelectValue(selectElement, value) {
|
||||||
|
const options = selectElement.options;
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
if (options[i].value === value) {
|
||||||
|
selectElement.selectedIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fetch and display existing profiles
|
||||||
|
function fetchProfiles() {
|
||||||
|
fetch('/cgi-bin/fetch-apn-profiles.sh')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
// Fill Profile 1
|
||||||
|
if (data.profiles.profile1) {
|
||||||
|
const p1 = data.profiles.profile1;
|
||||||
|
if (p1.iccid) document.getElementById('iccidProfile1').value = p1.iccid;
|
||||||
|
if (p1.apn) document.getElementById('apnProfile1').value = p1.apn;
|
||||||
|
if (p1.pdpType) setSelectValue(document.getElementById('apnPDPType1'), p1.pdpType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill Profile 2
|
||||||
|
if (data.profiles.profile2) {
|
||||||
|
const p2 = data.profiles.profile2;
|
||||||
|
if (p2.iccid) document.getElementById('iccidProfile2').value = p2.iccid;
|
||||||
|
if (p2.apn) document.getElementById('apnProfile2').value = p2.apn;
|
||||||
|
if (p2.pdpType) setSelectValue(document.getElementById('apnPDPType2'), p2.pdpType);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showNotification('No existing profiles found', true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
showNotification('Error fetching profiles: ' + error.message, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate form
|
||||||
|
function validateForm() {
|
||||||
|
const iccid1 = document.getElementById('iccidProfile1').value;
|
||||||
|
const apn1 = document.getElementById('apnProfile1').value;
|
||||||
|
const pdp1 = document.getElementById('apnPDPType1').value;
|
||||||
|
|
||||||
|
const iccid2 = document.getElementById('iccidProfile2').value;
|
||||||
|
const apn2 = document.getElementById('apnProfile2').value;
|
||||||
|
const pdp2 = document.getElementById('apnPDPType2').value;
|
||||||
|
|
||||||
|
// Validate first profile (required)
|
||||||
|
if (!iccid1 || !apn1 || pdp1 === 'Select APN PDP Type') {
|
||||||
|
showNotification('Please fill in all fields for Profile 1', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateICCID(iccid1)) {
|
||||||
|
showNotification('Invalid ICCID format in Profile 1 (should be 19-20 digits)', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!validateAPN(apn1)) {
|
||||||
|
showNotification('Invalid APN format in Profile 1 (alphanumeric, dots, and hyphens only)', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate second profile only if any field is filled
|
||||||
|
if (iccid2 || apn2 || pdp2 !== 'Select APN PDP Type') {
|
||||||
|
if (!validateICCID(iccid2)) {
|
||||||
|
showNotification('Invalid ICCID format in Profile 2 (should be 19-20 digits)', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!validateAPN(apn2)) {
|
||||||
|
showNotification('Invalid APN format in Profile 2 (alphanumeric, dots, and hyphens only)', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pdp2 === 'Select APN PDP Type') {
|
||||||
|
showNotification('Please select PDP type for Profile 2', true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle form submission
|
||||||
|
document.getElementById('saveAPNProfile').addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = {
|
||||||
|
iccidProfile1: document.getElementById('iccidProfile1').value,
|
||||||
|
apnProfile1: document.getElementById('apnProfile1').value,
|
||||||
|
pdpType1: document.getElementById('apnPDPType1').value,
|
||||||
|
iccidProfile2: document.getElementById('iccidProfile2').value || '',
|
||||||
|
apnProfile2: document.getElementById('apnProfile2').value || '',
|
||||||
|
pdpType2: document.getElementById('apnPDPType2').value || 'IP' // Default value if not selected
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send data to the server
|
||||||
|
fetch('/cgi-bin/apn-profile.sh', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: Object.keys(formData).map(key => {
|
||||||
|
return encodeURIComponent(key) + '=' + encodeURIComponent(formData[key])
|
||||||
|
}).join('&')
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
showNotification('APN profiles saved successfully');
|
||||||
|
} else {
|
||||||
|
showNotification(data.message || 'Error saving APN profiles', true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
showNotification('Error saving APN profiles: ' + error.message, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle reset button
|
||||||
|
document.getElementById('resetAPNProfile').addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
document.getElementById('iccidProfile1').value = '';
|
||||||
|
document.getElementById('apnProfile1').value = '';
|
||||||
|
document.getElementById('apnPDPType1').selectedIndex = 0;
|
||||||
|
document.getElementById('iccidProfile2').value = '';
|
||||||
|
document.getElementById('apnProfile2').value = '';
|
||||||
|
document.getElementById('apnPDPType2').selectedIndex = 0;
|
||||||
|
|
||||||
|
showNotification('Form has been reset');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch existing profiles when the page loads
|
||||||
|
fetchProfiles();
|
||||||
|
});
|
||||||
309
www/js/cell-settings/fetch-settings.js
Normal file
309
www/js/cell-settings/fetch-settings.js
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
// State variables to track current values
|
||||||
|
let currentSettings = {
|
||||||
|
apn: "",
|
||||||
|
pdpType: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
let updatedSettings = {
|
||||||
|
apn: "",
|
||||||
|
pdpType: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
let updatedNetworkMode = "";
|
||||||
|
let currentNetworkMode = "";
|
||||||
|
|
||||||
|
let currentNr5GModeControl = "";
|
||||||
|
let updatedNr5GModeControl = "";
|
||||||
|
|
||||||
|
// Function to check if settings have changed
|
||||||
|
function haveSettingsChanged() {
|
||||||
|
return (
|
||||||
|
currentSettings.apn !== updatedSettings.apn ||
|
||||||
|
currentSettings.pdpType !== updatedSettings.pdpType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to check if network mode has changed
|
||||||
|
function haveNetworkModeChanged() {
|
||||||
|
console.log("Current network mode:", currentNetworkMode);
|
||||||
|
console.log("Updated network mode:", updatedNetworkMode);
|
||||||
|
return currentNetworkMode !== updatedNetworkMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to check if NR5G mode control has changed
|
||||||
|
function haveNr5GModeControlChanged() {
|
||||||
|
console.log("Current NR5G mode control:", currentNr5GModeControl);
|
||||||
|
console.log("Updated NR5G mode control:", updatedNr5GModeControl);
|
||||||
|
return currentNr5GModeControl !== updatedNr5GModeControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to apply network mode changes immediately
|
||||||
|
async function applyNetworkModeChange() {
|
||||||
|
if (!haveNetworkModeChanged()) {
|
||||||
|
alert("No changes detected in the network mode.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const atCommand = `AT+QNWPREFCFG="mode_pref",${updatedNetworkMode}`;
|
||||||
|
console.log("Sending AT command for network mode change:", atCommand);
|
||||||
|
const response = await sendATCommand(atCommand);
|
||||||
|
console.log("AT command response:", response);
|
||||||
|
alert("Network mode applied successfully!");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error applying network mode:", error);
|
||||||
|
alert("Error applying network mode. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to apply NR5G mode control changes immediately
|
||||||
|
async function applyNr5GModeControlChange() {
|
||||||
|
if (!haveNr5GModeControlChanged()) {
|
||||||
|
alert("No changes detected in the NR5G mode control.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const atCommand = `AT+QNWPREFCFG="nr5g_disable_mode",${updatedNr5GModeControl}`;
|
||||||
|
console.log("Sending AT command for NR5G mode control change:", atCommand);
|
||||||
|
const response = await sendATCommand(atCommand);
|
||||||
|
console.log("AT command response:", response);
|
||||||
|
alert("NR5G mode control applied successfully!");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error applying NR5G mode control:", error);
|
||||||
|
alert("Error applying NR5G mode control. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to send settings to the modem
|
||||||
|
async function saveSettings() {
|
||||||
|
if (!haveSettingsChanged()) {
|
||||||
|
alert("No changes detected in the settings.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const atCommand = `AT+QMBNCFG="AutoSel",0;+CGDCONT=1,"${updatedSettings.pdpType}","${updatedSettings.apn}"`;
|
||||||
|
console.log("Sending AT command:", atCommand);
|
||||||
|
|
||||||
|
// Disable the input fields while the settings are being saved
|
||||||
|
const inputs = document.querySelectorAll("input, select");
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
input.disabled = true;
|
||||||
|
});
|
||||||
|
const response = await sendATCommand(atCommand);
|
||||||
|
console.log("AT command response:", response);
|
||||||
|
|
||||||
|
await sendATCommand(`AT+COPS=2`);
|
||||||
|
// Wait for 2 seconds before turning on the modem
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
await sendATCommand(`AT+COPS=0`);
|
||||||
|
|
||||||
|
// Re-enable the input fields after the settings are saved
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
input.disabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update current settings after successful save
|
||||||
|
currentSettings = { ...updatedSettings };
|
||||||
|
alert("Settings saved successfully!");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error saving settings:", error);
|
||||||
|
alert("Error saving settings. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resetAPN() {
|
||||||
|
atCommand = `AT+QMBNCFG="AutoSel",1`;
|
||||||
|
console.log("Sending AT command:", atCommand);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await sendATCommand(atCommand);
|
||||||
|
console.log("AT command response:", response);
|
||||||
|
|
||||||
|
// Restart connection after resetting APN settings
|
||||||
|
await sendATCommand("AT+COPS=2");
|
||||||
|
// Wait for 2 seconds before turning on the modem
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
await sendATCommand("AT+COPS=0");
|
||||||
|
alert("APN settings reset successfully!");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error resetting APN settings:", error);
|
||||||
|
alert("Error resetting APN settings. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendATCommand(command) {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/cgi-bin/atinout_handler.sh", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: "command=" + encodeURIComponent(command),
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending AT command:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fetch cell settings data
|
||||||
|
async function fetchCellSettings() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/cgi-bin/cell-settings.sh");
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("Full response:", data);
|
||||||
|
|
||||||
|
data.forEach((item) => {
|
||||||
|
if (item.response.includes("CGDCONT?")) {
|
||||||
|
const apn = item.response
|
||||||
|
.split("\n")[1]
|
||||||
|
.split(":")[1]
|
||||||
|
.split(",")[2]
|
||||||
|
.replace(/"/g, "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
currentSettings.apn = apn;
|
||||||
|
updatedSettings.apn = apn;
|
||||||
|
|
||||||
|
const apnInput = document.getElementById("currentAPN");
|
||||||
|
if (apnInput) {
|
||||||
|
apnInput.value = apn;
|
||||||
|
|
||||||
|
// Add event listener for APN changes
|
||||||
|
if (!apnInput.hasListener) {
|
||||||
|
apnInput.hasListener = true;
|
||||||
|
apnInput.addEventListener("input", (e) => {
|
||||||
|
updatedSettings.apn = e.target.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdpType = item.response
|
||||||
|
.split("\n")[1]
|
||||||
|
.split(":")[1]
|
||||||
|
.split(",")[1]
|
||||||
|
.replace(/"/g, "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
currentSettings.pdpType = pdpType;
|
||||||
|
updatedSettings.pdpType = pdpType;
|
||||||
|
|
||||||
|
const pdpTypeSelect = document.getElementById("apnPDP");
|
||||||
|
if (pdpTypeSelect) {
|
||||||
|
// Set initial value
|
||||||
|
pdpTypeSelect.value =
|
||||||
|
pdpType === "IPV4V6"
|
||||||
|
? "IPV4V6"
|
||||||
|
: pdpType === "IPV6"
|
||||||
|
? "IPV6"
|
||||||
|
: pdpType === "PPP"
|
||||||
|
? "PPP"
|
||||||
|
: "IP";
|
||||||
|
|
||||||
|
// Add event listener for PDP type changes
|
||||||
|
if (!pdpTypeSelect.hasListener) {
|
||||||
|
pdpTypeSelect.hasListener = true;
|
||||||
|
pdpTypeSelect.addEventListener("change", (e) => {
|
||||||
|
updatedSettings.pdpType = e.target.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item.response.includes("QNWPREFCFG")) {
|
||||||
|
console.log("QNWPREFCFG:", item.response);
|
||||||
|
const networkMode = item.response
|
||||||
|
.split("\n")[1]
|
||||||
|
.replace("+QNWPREFCFG: ", "")
|
||||||
|
.split(",")[1]
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
currentNetworkMode = networkMode;
|
||||||
|
updatedNetworkMode = networkMode;
|
||||||
|
|
||||||
|
const networkSelect = document.getElementById("networkPreference");
|
||||||
|
if (networkSelect) {
|
||||||
|
// Set initial value based on actual value from modem
|
||||||
|
networkSelect.value =
|
||||||
|
networkMode === "LTE:NR5G"
|
||||||
|
? "NR5G:LTE"
|
||||||
|
: networkMode === "NR5G"
|
||||||
|
? "NR5G"
|
||||||
|
: networkMode === "LTE"
|
||||||
|
? "LTE"
|
||||||
|
: "AUTO";
|
||||||
|
|
||||||
|
// Add event listener for network mode changes, if there is, run applyNetworkModeChange
|
||||||
|
if (!networkSelect.hasListener) {
|
||||||
|
networkSelect.hasListener = true;
|
||||||
|
networkSelect.addEventListener("change", (e) => {
|
||||||
|
updatedNetworkMode = e.target.value;
|
||||||
|
applyNetworkModeChange();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nr5GModeControl = item.response
|
||||||
|
.split("\n")[1]
|
||||||
|
.split(":")[1]
|
||||||
|
.split(",")[1]
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
console.log("NR5G mode control:", nr5GModeControl);
|
||||||
|
|
||||||
|
currentNr5GModeControl = nr5GModeControl;
|
||||||
|
updatedNr5GModeControl = nr5GModeControl;
|
||||||
|
|
||||||
|
const nr5GControlSelect = document.getElementById("nr5gModeControl");
|
||||||
|
|
||||||
|
if (nr5GControlSelect) {
|
||||||
|
// Set initial value based on actual value from modem
|
||||||
|
nr5GControlSelect.value =
|
||||||
|
nr5GModeControl === "0" ? "0" : nr5GModeControl === "1" ? "1" : "2";
|
||||||
|
|
||||||
|
// Add event listener for NR5G mode control changes, if there is, run applyNr5GModeControlChange
|
||||||
|
if (!nr5GControlSelect.hasListener) {
|
||||||
|
nr5GControlSelect.hasListener = true;
|
||||||
|
nr5GControlSelect.addEventListener("change", (e) => {
|
||||||
|
updatedNr5GModeControl = e.target.value;
|
||||||
|
applyNr5GModeControlChange();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching cell settings:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize when DOM is loaded
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
fetchCellSettings();
|
||||||
|
|
||||||
|
// Add event listener for both save buttons
|
||||||
|
const saveButtons = document.querySelectorAll(".card-footer-item");
|
||||||
|
saveButtons.forEach((button) => {
|
||||||
|
if (button.textContent.trim() === "Save APN") {
|
||||||
|
button.addEventListener("click", saveSettings);
|
||||||
|
} else if (button.textContent.trim() === "Reset APN") {
|
||||||
|
button.addEventListener("click", resetAPN);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// For every alert and close button, add event listener to refetch cell settings
|
||||||
|
const alertButtons = document.querySelectorAll(".delete");
|
||||||
|
alertButtons.forEach((button) => {
|
||||||
|
button.addEventListener("click", fetchCellSettings);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -202,9 +202,9 @@ function startPeriodicRefresh(refreshRate = DEFAULT_REFRESH_RATE) {
|
|||||||
async function fetchATCommandData() {
|
async function fetchATCommandData() {
|
||||||
try {
|
try {
|
||||||
const jsonData = await fetchAndParseData();
|
const jsonData = await fetchAndParseData();
|
||||||
processATCommandData(jsonData);
|
|
||||||
console.log("Data fetched and processed successfully");
|
console.log("Data fetched and processed successfully");
|
||||||
console.log(jsonData);
|
console.log(jsonData);
|
||||||
|
processATCommandData(jsonData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("There was a problem with the fetch operation:", error);
|
console.error("There was a problem with the fetch operation:", error);
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,13 @@ function processNetworkData(jsonData) {
|
|||||||
|
|
||||||
// APN
|
// APN
|
||||||
const apnData = extractValue(jsonData[7].response).split(",");
|
const apnData = extractValue(jsonData[7].response).split(",");
|
||||||
setText("apn", apnData[2].replace(/"/g, "").trim());
|
const apn = apnData[2].replace(/"/g, "").trim();
|
||||||
|
if (apn === "") {
|
||||||
|
const automaticAPN = jsonData[12].response.split("\n")[1].split(":")[1].split(",")[2].replace(/"/g, "").trim();
|
||||||
|
setText("apn", automaticAPN);
|
||||||
|
} else {
|
||||||
|
setText("apn", apnData[2].replace(/"/g, "").trim());
|
||||||
|
}
|
||||||
|
|
||||||
// Operator State
|
// Operator State
|
||||||
const operatorState = extractValue(jsonData[8].response).split(",")[1].trim();
|
const operatorState = extractValue(jsonData[8].response).split(",")[1].trim();
|
||||||
@@ -645,7 +651,9 @@ function createBandTableRow(bandData, networkType, servingCellJSON) {
|
|||||||
<div class="cell-card">
|
<div class="cell-card">
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">Name</span>
|
<span class="cell-card__label">Name</span>
|
||||||
<span class="cell-card__value">${formattedBandNumber || "N/A"}</span>
|
<span class="cell-card__value">${
|
||||||
|
formattedBandNumber || "N/A"
|
||||||
|
}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">EARFCN</span>
|
<span class="cell-card__label">EARFCN</span>
|
||||||
@@ -661,15 +669,21 @@ function createBandTableRow(bandData, networkType, servingCellJSON) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">RSRP</span>
|
<span class="cell-card__label">RSRP</span>
|
||||||
<span class="cell-card__value">${rsrp ? createSignalTag(rsrp, "RSRP") : "N/A"}</span>
|
<span class="cell-card__value">${
|
||||||
|
rsrp ? createSignalTag(rsrp, "RSRP") : "N/A"
|
||||||
|
}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">RSRQ</span>
|
<span class="cell-card__label">RSRQ</span>
|
||||||
<span class="cell-card__value">${rsrq ? createSignalTag(rsrq, "RSRQ") : "N/A"}</span>
|
<span class="cell-card__value">${
|
||||||
|
rsrq ? createSignalTag(rsrq, "RSRQ") : "N/A"
|
||||||
|
}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">SINR</span>
|
<span class="cell-card__label">SINR</span>
|
||||||
<span class="cell-card__value">${sinr ? createSignalTag(sinr, "SINR") : "N/A"}</span>
|
<span class="cell-card__value">${
|
||||||
|
sinr ? createSignalTag(sinr, "SINR") : "N/A"
|
||||||
|
}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1147,7 +1161,7 @@ function initMobileCarousel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add CSS class for smooth transitions
|
// Add CSS class for smooth transitions
|
||||||
const style = document.createElement('style');
|
const style = document.createElement("style");
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
.cell-carousel__container {
|
.cell-carousel__container {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1171,10 +1185,10 @@ function updateCarouselContent(rows) {
|
|||||||
|
|
||||||
// Preserve existing transform to maintain current slide position
|
// Preserve existing transform to maintain current slide position
|
||||||
const currentTransform = carouselContainer.style.transform;
|
const currentTransform = carouselContainer.style.transform;
|
||||||
|
|
||||||
// Clear existing content
|
// Clear existing content
|
||||||
carouselContainer.innerHTML = '';
|
carouselContainer.innerHTML = "";
|
||||||
|
|
||||||
// Create and append all slides at once
|
// Create and append all slides at once
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
const slide = document.createElement("div");
|
const slide = document.createElement("div");
|
||||||
@@ -1182,13 +1196,13 @@ function updateCarouselContent(rows) {
|
|||||||
slide.innerHTML = row.getAttribute("data-mobile");
|
slide.innerHTML = row.getAttribute("data-mobile");
|
||||||
carouselContainer.appendChild(slide);
|
carouselContainer.appendChild(slide);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Restore transform to maintain position
|
// Restore transform to maintain position
|
||||||
carouselContainer.style.transform = currentTransform;
|
carouselContainer.style.transform = currentTransform;
|
||||||
|
|
||||||
// Update indicators
|
// Update indicators
|
||||||
updateIndicators(rows.length);
|
updateIndicators(rows.length);
|
||||||
|
|
||||||
// Ensure current slide is within bounds
|
// Ensure current slide is within bounds
|
||||||
if (currentSlide >= rows.length) {
|
if (currentSlide >= rows.length) {
|
||||||
currentSlide = Math.max(0, rows.length - 1);
|
currentSlide = Math.max(0, rows.length - 1);
|
||||||
@@ -1197,25 +1211,31 @@ function updateCarouselContent(rows) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateSlideValues(slide, newDataHtml) {
|
function updateSlideValues(slide, newDataHtml) {
|
||||||
const tempDiv = document.createElement('div');
|
const tempDiv = document.createElement("div");
|
||||||
tempDiv.innerHTML = newDataHtml;
|
tempDiv.innerHTML = newDataHtml;
|
||||||
const newCard = tempDiv.querySelector('.cell-card');
|
const newCard = tempDiv.querySelector(".cell-card");
|
||||||
const currentCard = slide.querySelector('.cell-card');
|
const currentCard = slide.querySelector(".cell-card");
|
||||||
|
|
||||||
if (!currentCard || !newCard) {
|
if (!currentCard || !newCard) {
|
||||||
slide.innerHTML = newDataHtml;
|
slide.innerHTML = newDataHtml;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentItems = currentCard.querySelectorAll('.cell-card__item');
|
const currentItems = currentCard.querySelectorAll(".cell-card__item");
|
||||||
const newItems = newCard.querySelectorAll('.cell-card__item');
|
const newItems = newCard.querySelectorAll(".cell-card__item");
|
||||||
|
|
||||||
currentItems.forEach((item, index) => {
|
currentItems.forEach((item, index) => {
|
||||||
const currentValueSpan = item.querySelector('span:not(.cell-card__label)');
|
const currentValueSpan = item.querySelector("span:not(.cell-card__label)");
|
||||||
const newItem = newItems[index];
|
const newItem = newItems[index];
|
||||||
const newValueSpan = newItem ? newItem.querySelector('span:not(.cell-card__label)') : null;
|
const newValueSpan = newItem
|
||||||
|
? newItem.querySelector("span:not(.cell-card__label)")
|
||||||
if (currentValueSpan && newValueSpan && currentValueSpan.innerHTML !== newValueSpan.innerHTML) {
|
: null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentValueSpan &&
|
||||||
|
newValueSpan &&
|
||||||
|
currentValueSpan.innerHTML !== newValueSpan.innerHTML
|
||||||
|
) {
|
||||||
currentValueSpan.innerHTML = newValueSpan.innerHTML;
|
currentValueSpan.innerHTML = newValueSpan.innerHTML;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1224,7 +1244,7 @@ function updateSlideValues(slide, newDataHtml) {
|
|||||||
function updateIndicators(slideCount) {
|
function updateIndicators(slideCount) {
|
||||||
const carouselWrapper = document.querySelector(".cell-carousel");
|
const carouselWrapper = document.querySelector(".cell-carousel");
|
||||||
let indicators = carouselWrapper.querySelector(".cell-carousel__indicators");
|
let indicators = carouselWrapper.querySelector(".cell-carousel__indicators");
|
||||||
|
|
||||||
if (indicators) {
|
if (indicators) {
|
||||||
indicators.remove();
|
indicators.remove();
|
||||||
}
|
}
|
||||||
@@ -1254,14 +1274,13 @@ function updateCarouselPosition() {
|
|||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
container.style.transform = `translateX(-${currentSlide * 100}%)`;
|
container.style.transform = `translateX(-${currentSlide * 100}%)`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const dots = document.querySelectorAll(".cell-carousel__dot");
|
const dots = document.querySelectorAll(".cell-carousel__dot");
|
||||||
dots.forEach((dot, index) => {
|
dots.forEach((dot, index) => {
|
||||||
dot.classList.toggle("cell-carousel__dot--active", index === currentSlide);
|
dot.classList.toggle("cell-carousel__dot--active", index === currentSlide);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Touch handling functions remain the same
|
// Touch handling functions remain the same
|
||||||
let touchStartX = 0;
|
let touchStartX = 0;
|
||||||
let touchEndX = 0;
|
let touchEndX = 0;
|
||||||
@@ -1302,4 +1321,4 @@ function goToSlide(index) {
|
|||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
window.addEventListener("load", initMobileCarousel);
|
window.addEventListener("load", initMobileCarousel);
|
||||||
window.addEventListener("resize", initMobileCarousel);
|
window.addEventListener("resize", initMobileCarousel);
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
throw new Error(`HTTP error! status: ${response1.status}`);
|
throw new Error(`HTTP error! status: ${response1.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for 2 seconds
|
// Wait for 3 seconds
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
// Send AT+CFUN=1
|
// Send AT+CFUN=1
|
||||||
const response2 = await fetch('/cgi-bin/atinout_handler.sh', {
|
const response2 = await fetch('/cgi-bin/atinout_handler.sh', {
|
||||||
|
|||||||
Reference in New Issue
Block a user