2024-08-15 21:28:45 -06:00
|
|
|
{%
|
|
|
|
/*
|
|
|
|
* Part of AREDN® -- Used for creating Amateur Radio Emergency Data Networks
|
|
|
|
* Copyright (C) 2024 Tim Wilkinson
|
|
|
|
* See Contributors file for additional contributors
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation version 3 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Additional Terms:
|
|
|
|
*
|
|
|
|
* Additional use restrictions exist on the AREDN® trademark and logo.
|
|
|
|
* See AREDNLicense.txt for more info.
|
|
|
|
*
|
|
|
|
* Attributions to the AREDN® Project must be retained in the source code.
|
|
|
|
* If importing this code into a new or existing project attribution
|
|
|
|
* to the AREDN® project must be added to the source code.
|
|
|
|
*
|
|
|
|
* You must not misrepresent the origin of the material contained within.
|
|
|
|
*
|
|
|
|
* Modified versions must be modified to attribute to the original source
|
|
|
|
* and be marked in reasonable ways as differentiate it from the original
|
|
|
|
* version
|
|
|
|
*/
|
|
|
|
%}
|
|
|
|
{%
|
|
|
|
if (request.env.REQUEST_METHOD === "PUT") {
|
|
|
|
configuration.prepareChanges();
|
|
|
|
if ("radio0_mode" in request.args || "radio1_mode" in request.args) {
|
|
|
|
const wlan = radios.getConfiguration();
|
|
|
|
let radio0_mode = "radio0_mode" in request.args ? int(request.args.radio0_mode) : wlan[0].mode;
|
|
|
|
let radio1_mode = "radio1_mode" in request.args ? int(request.args.radio1_mode) : wlan[1]?.mode;
|
|
|
|
if (radio0_mode === radio1_mode) {
|
|
|
|
if ("radio0_mode" in request.args) {
|
|
|
|
radio1_mode = radios.RADIO_OFF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
radio0_mode = radios.RADIO_OFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
configuration.setSetting("wifi_enable", "0");
|
|
|
|
configuration.setSetting("wifi2_enable", "0");
|
|
|
|
configuration.setSetting("wifi3_enable", "0");
|
|
|
|
switch (radio0_mode) {
|
|
|
|
case radios.RADIO_MESH:
|
|
|
|
configuration.setSetting("wifi_enable", "1");
|
|
|
|
if (configuration.setSetting("wifi_intf", "wlan0")) {
|
|
|
|
configuration.setSetting("wifi_channel", wlan[0].def.channel);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case radios.RADIO_LAN:
|
|
|
|
configuration.setSetting("wifi2_enable", "1");
|
|
|
|
if (configuration.setSetting("wifi2_hwmode", wlan[0].def.band === "5GHz" ? "11a" : "11g")) {
|
|
|
|
configuration.setSetting("wifi2_channel", wlan[0].def.channel);
|
|
|
|
}
|
|
|
|
if (configuration.getSettingAsString("wifi2_key", "") === "") {
|
|
|
|
configuration.setSetting("wifi2_key", hexenc("AREDN"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case radios.RADIO_WAN:
|
|
|
|
configuration.setSetting("wifi3_enable", "1");
|
|
|
|
configuration.setSetting("wifi3_hwmode", wlan[0].def.band === "5GHz" ? "11a" : "11g");
|
|
|
|
break;
|
|
|
|
case radios.RADIO_OFF:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (radio1_mode) {
|
|
|
|
case radios.RADIO_MESH:
|
|
|
|
configuration.setSetting("wifi_enable", "1");
|
|
|
|
if (configuration.setSetting("wifi_intf", "wlan1")) {
|
|
|
|
configuration.setSetting("wifi_channel", wlan[1].def.channel);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case radios.RADIO_LAN:
|
|
|
|
configuration.setSetting("wifi2_enable", "1");
|
|
|
|
if (configuration.setSetting("wifi2_hwmode", wlan[1].def.band === "5GHz" ? "11a" : "11g")) {
|
|
|
|
configuration.setSetting("wifi2_channel", wlan[1].def.channel);
|
|
|
|
}
|
|
|
|
if (configuration.getSettingAsString("wifi2_key", "") === "") {
|
|
|
|
configuration.setSetting("wifi2_key", hexenc("AREDN"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case radios.RADIO_WAN:
|
|
|
|
configuration.setSetting("wifi3_enable", "1");
|
|
|
|
configuration.setSetting("wifi3_hwmode", wlan[1].def.band === "5GHz" ? "11a" : "11g");
|
|
|
|
break;
|
|
|
|
case radios.RADIO_OFF:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ("radio_channel" in request.args) {
|
|
|
|
configuration.setSetting("wifi_channel", request.args.radio_channel);
|
|
|
|
}
|
|
|
|
if ("radio0_bandwidth" in request.args || "radio1_bandwidth" in request.args) {
|
|
|
|
configuration.setSetting("wifi_chanbw", request.args.radio0_bandwidth || request.args.radio1_bandwidth);
|
|
|
|
}
|
|
|
|
if ("radio_txpower" in request.args) {
|
|
|
|
configuration.setSetting("wifi_txpower", request.args.radio_txpower);
|
|
|
|
}
|
|
|
|
if ("radio0_ssid" in request.args || "radio1_ssid" in request.args) {
|
|
|
|
configuration.setSetting("wifi_ssid", request.args.radio0_ssid || request.args.radio1_ssid);
|
|
|
|
}
|
|
|
|
if ("radio_minsnr" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "min_snr", request.args.radio_minsnr);
|
|
|
|
}
|
|
|
|
if ("radio_maxdistance" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "max_distance", units.distance2meters(request.args.radio_maxdistance));
|
|
|
|
}
|
|
|
|
if ("radio_minquality" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "min_quality", request.args.radio_minquality);
|
|
|
|
}
|
|
|
|
if ("radio_lan_ssid" in request.args) {
|
|
|
|
configuration.setSetting("wifi2_ssid", hexenc(request.args.radio_lan_ssid));
|
|
|
|
}
|
|
|
|
if ("radio_lan_channel" in request.args) {
|
|
|
|
configuration.setSetting("wifi2_channel", request.args.radio_lan_channel);
|
|
|
|
}
|
|
|
|
if ("radio_lan_encryption" in request.args) {
|
|
|
|
const encrypt = [ "psk", "psk2", "none" ];
|
|
|
|
configuration.setSetting("wifi2_encryption", encrypt[int(request.args.radio_lan_encryption)]);
|
|
|
|
}
|
|
|
|
if ("radio_lan_password" in request.args) {
|
|
|
|
configuration.setSetting("wifi2_key", hexenc(request.args.radio_lan_password));
|
|
|
|
}
|
|
|
|
if ("radio_wan_ssid" in request.args) {
|
|
|
|
configuration.setSetting("wifi3_ssid", hexenc(request.args.radio_wan_ssid));
|
|
|
|
}
|
|
|
|
if ("radio_wan_password" in request.args) {
|
|
|
|
configuration.setSetting("wifi3_key", hexenc(request.args.radio_wan_password));
|
|
|
|
}
|
|
|
|
if ("radio_antenna" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@location[0]", "antenna", request.args.radio_antenna);
|
|
|
|
}
|
|
|
|
if ("radio_azimuth" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@location[0]", "azimuth", request.args.radio_azimuth);
|
|
|
|
}
|
|
|
|
if ("radio_height" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@location[0]", "height", request.args.radio_height);
|
|
|
|
}
|
|
|
|
if ("radio_elevation" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@location[0]", "elevation", request.args.radio_elevation);
|
|
|
|
}
|
|
|
|
if ("radio_lqm_enable" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "lqm_enable", request.args.radio_lqm_enable === "on" ? 1 : 0);
|
|
|
|
}
|
|
|
|
if ("radio_mindistance" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "min_distance", request.args.radio_mindistance);
|
|
|
|
}
|
|
|
|
if ("radio_rts_threshold" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "rts_threshold", request.args.radio_rts_threshold);
|
|
|
|
}
|
|
|
|
if ("radio_mtu" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "mtu", request.args.radio_mtu);
|
|
|
|
}
|
|
|
|
if ("radio_margin_snr" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "margin_snr", request.args.radio_margin_snr);
|
|
|
|
}
|
|
|
|
if ("radio_margin_quality" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "margin_quality", request.args.radio_margin_quality);
|
|
|
|
}
|
|
|
|
if ("radio_ping_penalty" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "ping_penalty", request.args.radio_ping_penalty);
|
|
|
|
}
|
|
|
|
if ("radio_min_routes" in request.args) {
|
|
|
|
uciMesh.set("aredn", "@lqm[0]", "min_routes", request.args.radio_min_routes);
|
|
|
|
}
|
|
|
|
uciMesh.commit("aredn");
|
|
|
|
configuration.saveSettings();
|
|
|
|
print(_R("changes"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (request.env.REQUEST_METHOD === "DELETE") {
|
|
|
|
configuration.revertModalChanges();
|
|
|
|
print(_R("changes"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
{% const wlan = radios.getConfiguration(); %}
|
|
|
|
<div class="dialog radio-and-antenna">
|
|
|
|
{{_R("dialog-header", "Radios & Antennas")}}
|
|
|
|
<div>
|
|
|
|
{%
|
|
|
|
const hasradios = length(wlan) > 0;
|
|
|
|
if (hasradios) {
|
|
|
|
for (let w = 0; w < length(wlan); w++) {
|
|
|
|
const prefix = `radio${w}_`;
|
|
|
|
if (w !== 0) {
|
|
|
|
print("<hr>");
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
<div id="radio{{w}}" class="hideable compact">
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o" {{length(wlan) > 1 ? "style='font-weight:bold'" : ""}}>Radio {{wlan[w].def.band}}</div>
|
|
|
|
<div class="m">Radio purpose</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="{{prefix}}mode">
|
|
|
|
<option value="0" {{wlan[w].mode === radios.RADIO_OFF ? "selected" : ""}}>Off</option>
|
|
|
|
<option value="1" {{wlan[w].mode === radios.RADIO_MESH ? "selected" : ""}}>Mesh</option>
|
|
|
|
<option value="2" {{wlan[w].mode === radios.RADIO_LAN ? "selected" : ""}}>LAN Hotspot</option>
|
|
|
|
<option value="3" {{wlan[w].mode === radios.RADIO_WAN ? "selected" : ""}}>WAN Client</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Select the purpose of the radio. Each radio can be assigned to a specific purpose, but devices with multiple radios
|
|
|
|
cannot have the same purpose for multiple radios (except <b>off</b>).")}}
|
|
|
|
<div class="hideable1" {{length(wlan) > 1 ? "style='padding-left:10px'" : ""}}>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Channel</div>
|
|
|
|
<div class="m">Channel and frequency of this connection</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="radio_channel" style="direction:ltr">
|
|
|
|
{%
|
|
|
|
const channel = wlan[w].modes[1].channel;
|
|
|
|
for (let i = 0; i < length(wlan[w].channels); i++) {
|
|
|
|
print(`<option value="${wlan[w].channels[i].number}" ${wlan[w].channels[i].number == channel ? "selected" : ""}>${wlan[w].channels[i].label}</option>`);
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Select the central channel/frequency for the radio.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Channel Width</div>
|
|
|
|
<div class="m">Channel bandwidth</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="{{prefix}}bandwidth" style="direction:ltr">
|
|
|
|
{%
|
|
|
|
const bandwidth = wlan[w].modes[1].bandwidth;
|
|
|
|
for (let i = 0; i < length(wlan[w].bws); i++) {
|
|
|
|
print(`<option value="${wlan[w].bws[i]}" ${wlan[w].bws[i] == bandwidth ? "selected" : ""}>${wlan[w].bws[i]} MHz</option>`);
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Select the bandwidth of the radio. Be aware that larger bandwidth settings will consume more channels. Avoid overlapping
|
|
|
|
channels as this will impact performance.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Transmit Power</div>
|
|
|
|
<div class="m">Transmit power</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="radio_txpower">
|
|
|
|
{%
|
|
|
|
const txpower = wlan[w].modes[1].txpower;
|
|
|
|
for (let i = wlan[w].txmaxpower; i > 0; i--) {
|
|
|
|
print(`<option value="${i}" ${i == txpower ? "selected" : ""}>${i + wlan[w].txpoweroffset}</option>`);
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Select the transmission power for the radio. Ideally use only enough power to maintain the link at the capacity required.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">SSID</div>
|
|
|
|
<div class="m">AREDN mesh identifier</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0;white-space:nowrap">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="{{prefix}}ssid" type="text" size="10" maxlength="32" pattern="[^!#;+\]\/"\t][^+\]\/"\t]{0,30}[^ !#;+\]\/"\t]$|^[^ !#;+\]\/"\t]" value="{{wlan[w].modes[1].ssid}}"><span style="color:var(--ctrl-modal-fg-color)">-{{wlan[w].modes[1].bandwidth}}-v3</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% if (uciMesh.get("aredn", "@lqm[0]", "lqm_enable") !== "0") { %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Minimum SNR</div>
|
|
|
|
<div class="m">Acceptable SNR for connection (dB)</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_minsnr" type="text" size="3" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "min_snr")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Low SNR results in higher latency, lower bandwidth and high retranmissions. Setting a minimum SNR allows links with
|
|
|
|
these characteristics to be ignored.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Maximum Distance</div>
|
|
|
|
<div class="m">Maximum distance allowed to other nodes in {{units.distanceUnit()}}</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_maxdistance" type="text" size="3" pattern="\d+" value="{{int(0.5 + units.meters2distance(uciMesh.get("aredn", "@lqm[0]", "max_distance")))}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Distance beyond which neighbor node connections will be ignored. Longer distances to nodes can result in poor performance.
|
|
|
|
This will effect all neighbors, not just the distant ones, so it often makes sense to keep this distance to a minimum.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Minimum Quality</div>
|
|
|
|
<div class="m">Minimum connection quaility percentage</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0;white-space:nowrap">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_minquality" type="text" size="3" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "min_quality")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("The node management system maintains an estimate of how well each neighbor link performs. This link <b>quality</b> is used
|
|
|
|
to determine which links to use. Lowering the minimum quality can impact performance, but may also be necessary under specific
|
|
|
|
circumstances.")}}
|
|
|
|
{% } %}
|
|
|
|
</div>
|
|
|
|
<div class="hideable2" {{length(wlan) > 1 ? "style='padding-left:10px'" : ""}}>
|
|
|
|
{{_H("In LAN Hotpot mode, the WiFi acts as a wireless hotspot. Any device connecting will appear as a LAN device attached to the node.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">SSID</div>
|
|
|
|
<div class="m">Hotspot SSID</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_lan_ssid" type="text" size="10" maxlength="32" pattern=[^!#;+\]\/"\t][^+\]\/"\t]{0,30}[^ !#;+\]\/"\t]$|^[^ !#;+\]\/"\t]" value="{{hexdec(wlan[w].modes[2].ssid)}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Channel</div>
|
|
|
|
<div class="m">Hotspot channel</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="radio_lan_channel">
|
|
|
|
{%
|
|
|
|
const channel = wlan[w].modes[2].channel;
|
|
|
|
for (let i = 0; i < length(wlan[w].channels); i++) {
|
|
|
|
print(`<option value="${wlan[w].channels[i].number}" ${wlan[w].channels[i].number == channel ? "selected" : ""}>${wlan[w].channels[i].number}</option>`);
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="hideable">
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Encryption</div>
|
|
|
|
<div class="m">Encryption algorithm</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="radio_lan_encryption">
|
|
|
|
<option value="0" {{wlan[w].modes[2].encryption == "psk" ? "selected" : ""}}>WPA PSK</option>
|
|
|
|
<option value="1" {{wlan[w].modes[2].encryption == "psk2" ? "selected" : ""}}>WPA2 PSK</option>
|
|
|
|
<option value="2" {{wlan[w].modes[2].encryption == "none" ? "selected" : ""}}>None</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="hideable0 hideable1">
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Password</div>
|
|
|
|
<div class="m">Hotspot password</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_lan_password" type="password" required size="10" maxlength="32" value="{{hexdec(wlan[w].modes[2].key) || "AREDN"}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="hideable3" {{length(wlan) > 1 ? "style='padding-left:10px'" : ""}}>
|
|
|
|
{{_H("In WAN Client mode, the WiFi connection is used to connect to another wireless network. This network is expected to provide
|
|
|
|
access to the Internet.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">SSID</div>
|
|
|
|
<div class="m">WAN client</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_wan_ssid" type="text" size="10" maxlength="32" pattern='[^!#;+\]\/"\t][^+\]\/"\t]{0,30}[^ !#;+\]\/"\t]$|^[^ !#;+\]\/"\t]' value="{{hexdec(wlan[w].modes[3].ssid)}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Password</div>
|
|
|
|
<div class="m">Client password</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_wan_password" type="password" size="10" maxlength="32" value="{{hexdec(wlan[w].modes[3].key)}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<div {{length(wlan) > 1 ? "style='padding-left:10px'" : ""}}>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Antenna</div>
|
|
|
|
<div class="m">Antenna</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0;white-space:nowrap">
|
|
|
|
{% if (length(wlan[w].ants) === 1) { %}
|
|
|
|
<span>{{wlan[w].ants[0].description}}<span>
|
|
|
|
{% } else { %}
|
|
|
|
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="radio_antenna">
|
|
|
|
{%
|
|
|
|
const model = wlan[w].ant?.model;
|
|
|
|
for (let i = 0; i < length(wlan[w].ants); i++) {
|
|
|
|
print(`<option value="${wlan[w].ants[i].model}" ${wlan[w].ants[i].model == model ? "selected" : ""}>${wlan[w].ants[i].description}</option>`);
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
</select>
|
|
|
|
{% } %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% if (length(wlan[w].ants) !== 1) { %}
|
|
|
|
{{_H("Select the external antenna attached to the primary radio.")}}
|
|
|
|
{% } %}
|
|
|
|
{% if (w === 0) { %}
|
|
|
|
{% if (!(length(wlan[w].ants) === 1 && wlan[w].ants[0].beamwidth === 360)) { %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Azimuth</div>
|
|
|
|
<div class="m">Antenna azimuth in degrees</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_azimuth" type="text" size="10" pattern="\d+" value="{{uciMesh.get("aredn", "@location[0]", "azimuth")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("The azimuth, or heading, of the primary radio antenna measured in degrees from north.")}}
|
|
|
|
{% } %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Height</div>
|
|
|
|
<div class="m">Antenna height in meters</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_height" type="text" size="10" pattern="\d+" value="{{uciMesh.get("aredn", "@location[0]", "height")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("The height of the antenna above ground level in meters.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Elevation</div>
|
|
|
|
<div class="m">Antenna elevation in degrees</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
2024-08-18 22:23:49 -06:00
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_elevation" type="text" size="10" pattern="-?\d+" value="{{uciMesh.get("aredn", "@location[0]", "elevation")}}">
|
2024-08-15 21:28:45 -06:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Elevation of the antenna, measured in degress, above or below the horizontal.")}}
|
|
|
|
{% } %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{%
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
%}
|
|
|
|
<div style="padding-bottom:24px">No Radios</div>
|
|
|
|
<div>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Minimum Quality</div>
|
|
|
|
<div class="m">Minimum connection quaility percentage</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0;white-space:nowrap">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_minquality" type="text" size="3" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "min_quality")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% } %}
|
|
|
|
{{_R("dialog-advanced")}}
|
|
|
|
<div>
|
|
|
|
{% if (includeAdvanced) { %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">LQM enable</div>
|
|
|
|
<div class="m">Enable Link Quality Management</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
{{_R("switch", { name: "radio_lqm_enable", value: uciMesh.get("aredn", "@lqm[0]", "lqm_enable") !== "0" })}}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Link Quality Management (LQM) is an automatic management system which monitors the efficiency of each neighbor link
|
|
|
|
and optimizes their use for best performance. When disabled, it still gathers data on each link, but this information is
|
|
|
|
not used to effect operation.")}}
|
|
|
|
{% if (hasradios) { %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Minimum Distance</div>
|
|
|
|
<div class="m">Minimum distance to other nodes in {{units.distanceUnit()}}</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_mindistance" type="text" size="3" pattern="\d+" value="{{int(0.5 + units.meters2distance(uciMesh.get("aredn", "@lqm[0]", "min_distance")))}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("Exclude nodes which are too close to this node.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">RTS Threshold</div>
|
|
|
|
<div class="m">RTS Threshold in bytes before using RTS/CTS when hidden nodes are detected</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_rts_threshold" type="text" size="4" pattern="([1-9]|[1-9]\d{1,2}|1\d{3}|2[0-2]\d{2}|23[0-3]\d|234[0-7])" value="{{uciMesh.get("aredn", "@lqm[0]", "rts_threshold")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("When hidden nodes are detected, the RTS/CTS protocol is automatically enabled to improve performance. By default this is used for all packets
|
|
|
|
being sent, but this can be optimized to only packets over a specific size (between 1 and 2347 bytes). Setting the value to
|
|
|
|
2347 disables the protocol.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Max Packet Size</div>
|
|
|
|
<div class="m">Maximum packet size in bytes sent over WiFi</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_mtu" type="text" size="4" pattern="(25[6-9]|2[6-9]\d|[3-9]\d{2}|1[0-4]\d{2}|1500)" placeholder="1500" value="{{uciMesh.get("aredn", "@lqm[0]", "mtu")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("By default, WiFi uses the same packet size (1500 bytes) as Ethernet. However, in some noisy environment performance can be
|
|
|
|
improved by reducing the packet size. A value must be between 256 and 1500.")}}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">SNR Margin</div>
|
|
|
|
<div class="m">SNR Margin in dB above Min SNR a signal must reach to be re-activated</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_margin_snr" type="text" size="1" pattern="\d" value="{{uciMesh.get("aredn", "@lqm[0]", "margin_snr")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_H("The SNR margin avoids a link switching quickly between blocked and unblocked when the SNR is the same as the minimum SNR. Once
|
|
|
|
a link falls below the minimum SNR, it must move above minimum SNR + SNR margin to become active again.")}}
|
|
|
|
{% } %}
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Quality Margin</div>
|
|
|
|
<div class="m">Quality Margin percentage increase before neighbor can be re-activated</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_margin_quality" type="text" size="2" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "margin_quality")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Ping Penalty</div>
|
|
|
|
<div class="m">Ping Penalty quality percentage to add when neighbor cannot be pinged</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_ping_penalty" type="text" size="2" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "ping_penalty")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="cols">
|
|
|
|
<div>
|
|
|
|
<div class="o">Minimum Routes</div>
|
|
|
|
<div class="m">Minimum number of routes on a link required to disable blocking</div>
|
|
|
|
</div>
|
|
|
|
<div style="flex:0">
|
|
|
|
<input hx-put="{{request.env.REQUEST_URI}}" name="radio_min_routes" type="text" size="2" pattern="\d\d?" value="{{uciMesh.get("aredn", "@lqm[0]", "min_routes")}}">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% } %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{_R("dialog-footer")}}
|
|
|
|
<script>
|
|
|
|
(function(){
|
|
|
|
{{_R("open")}}
|
|
|
|
{%
|
|
|
|
for (let w = 0; w < length(wlan); w++) { %}
|
|
|
|
const bws{{w}} = htmx.find(`#ctrl-modal .dialog.radio-and-antenna select[name=radio{{w}}_bandwidth]`);
|
|
|
|
const bwssid{{w}} = htmx.find(`#ctrl-modal .dialog.radio-and-antenna input[name=radio{{w}}_ssid] + span`);
|
|
|
|
bws{{w}}.addEventListener("change", function() {
|
|
|
|
bwssid{{w}}.innerHTML = `-${bws{{w}}.value}-v3`;
|
|
|
|
});
|
|
|
|
{% }
|
|
|
|
if (length(wlan) > 1) { %}
|
|
|
|
const radio0 = htmx.find("#radio0 select[name=radio0_mode]");
|
|
|
|
const radio1 = htmx.find("#radio1 select[name=radio1_mode]");
|
|
|
|
htmx.on(radio0, "htmx:beforeRequest", function() {
|
|
|
|
if (radio0.value === radio1.value && radio1.value !== 0) {
|
|
|
|
radio1.value = 0;
|
|
|
|
}
|
|
|
|
htmx.find("#radio0 select[name=radio_channel]").value = "{{wlan[0].def.channel}}";
|
|
|
|
htmx.find("#radio0 select[name=radio_lan_channel]").value = "{{wlan[0].def.channel}}";
|
|
|
|
});
|
|
|
|
htmx.on(radio1, "htmx:beforeRequest", function() {
|
|
|
|
if (radio1.value === radio0.value && radio0.value !== 0) {
|
|
|
|
radio0.value = 0;
|
|
|
|
}
|
|
|
|
htmx.find("#radio1 select[name=radio_channel]").value = "{{wlan[1].def.channel}}";
|
|
|
|
htmx.find("#radio1 select[name=radio_lan_channel]").value = "{{wlan[1].def.channel}}";
|
|
|
|
});
|
|
|
|
{% } %}
|
|
|
|
})();
|
|
|
|
</script>
|
|
|
|
</div>
|