feat: stationMode removed

This commit is contained in:
SQ2CPA 2024-03-07 17:46:38 +01:00
parent 8a7d91a7f6
commit a46a97691d
22 changed files with 991 additions and 700 deletions

View file

@ -1,46 +1,43 @@
{
"callsign": "NOCALL-10",
"stationMode": 2,
"iGateComment": "LoRa_APRS_iGate",
"wifi": {
"autoAP": {
"password": "1234567890",
"powerOff": 10
},
"AP": [
{
"ssid": "WIFI_1",
"password": "WIFI_1_password",
"latitude": 0.0,
"longitude": 0.0
},
{
"ssid": "WIFI_2",
"password": "WIFI_2_password",
"latitude": 0.0,
"longitude": 0.0
}
]
"AP": []
},
"beacon": {
"latitude": 0.0,
"longitude": 0.0,
"comment": "LoRa APRS",
"interval": 15,
"overlay": "L",
"symbol": "#",
"path": "WIDE1-1",
"sendViaAPRSIS": false,
"sendViaRF": false
},
"digi": {
"comment": "LoRa_APRS_Digirepeater",
"latitude": 0.0,
"longitude": 0.0
"mode": 0
},
"aprs_is": {
"active": false,
"passcode": "XYZVW",
"server": "rotate.aprs2.net",
"port": 14580,
"reportingDistance": 30
"filter": "",
"toRF": false
},
"lora": {
"iGateFreq": 433775000,
"digirepeaterTxFreq": 433775000,
"digirepeaterRxFreq": 433900000,
"txFreq": 433775000,
"rxFreq": 433775000,
"spreadingFactor": 12,
"signalBandwidth": 125000,
"codingRate4": 5,
"power": 20
"power": 20,
"txActive": false,
"rxActive": true
},
"display": {
"alwaysOn": true,
@ -60,9 +57,6 @@
"password": ""
},
"other": {
"beaconInterval": 15,
"igateSendsLoRaBeacons": false,
"igateRepeatsLoRaPackets": false,
"rememberStationTime": 30,
"sendBatteryVoltage": false,
"externalVoltageMeasurement": false,

View file

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>LoRa iGate</title>
<title>LoRa iGate & Digi software &minus; Ricardo Guzman CA2RXU</title>
<link rel="stylesheet" href="/bootstrap.css" />
<link rel="stylesheet" href="/style.css" />
</head>
@ -18,6 +18,7 @@
>CA2RXU's LoRa iGate Configuration</a
>
<div class="d-flex">
<a href="/update" class="btn btn-warning mx-2"> OTA </a>
<button
class="btn btn-primary mx-2"
type="button"
@ -45,7 +46,7 @@
<div class="container">
<main>
<div class="col-10 my-5 mx-auto">
<div class="row">
<!-- <div class="row">
<div class="d-flex align-items-center">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ6SURBVHgB7d0/axRBGMfx50IMWPoKkpA02gUsLfZdqOCLOPBFWAliHbCUVNpaxQNrIY0WVjZaJlUsIsZ5uDu9bGb/zMwzs/PM/L7wIG4Ocflwl7ndvVsihBBCmTajunpk5uHG33+aOSGkvhdmLs1cW+bKzDEhle2a+UZ22Pacrx6PlMRYXc/arrkkIKvIBxfISgrBBXLmSeACOdMkcYGcWTFwgZxJMXGBPHEpcIE8USlxgSzcbGD2KD0ukIXKGRfIAuWOC+TANOACOSAtuEAemQ10a2P2KV9cIA+0ZZltMzurOaT8cYHcUx+wJlwgd9QFrBEXyJZswAekFxfIrdq4GhZUQO7Itlq+QzoXVEC21AdcIm51yF3AJeNWhWwDLmFBBeRVmg4/Atmj2nGLR/bCbZrm2qWx/+7Ekwx5i9LGO/XFzF2qO97/r5QAOSUwcG+WBDkVMHDtRUdOAcz/ed4J4NqLihwbGLjjioYcExi4bkVBjgUMXL/EkWMAAzcsUWRpYODKJIYsCQxc2USQpYCBG6dgZAlg4MYtCDkUGLhp8kYOAQZu2ryQfYGT4S7PAKJVzsg+wEmfubNZbd+XOpgTsiswXpbzaDSyCzBw82oU8lhg4ObZIPIYYODmXS/yEDBwdcQ+72w/6AMGrq6OaHnLghv1AQNXX6/bG7qAPxNwNbbf3mAD5qf5EaEisgG/IVRMNuA9QsVkA94mpLWP7Q2pP5uE4vayvQHA5bQw86m90Qb8i5C22Kyx/cAG/IGQphj3ftcPbcBzM78JaWiN+73rATZgfvAzWn4SHeXbIC7Xtcg6MfOUgJxro3C5vlU0kPNsNC439DYJyHnlhMuNeR8M5DxyxuXGHugA8rR54XIuR7KAPE3euJzroUogpy0Il/M5Fg3kNAXjcr4nG4AcNxFcLuTc78nqz7e0/A7KLDo9PbV+nkn6Q2xnZ2c0n88pQmK4XOjJ/eyQm6YhxYnichLng/FyLZM4Lid1wh/IYUXB5SSv6ACyX9FwOelLdoDsVlRcLsY1WUAeV3RcLtZFd0Duj3EfUGRcLuZVlUC2lwyXi32Re/D75IuLC1osFtYDFXxAo73dts21MV/8wgc6PEqKm7LHZv5QnndASTV8p5U9unl7oaJ6QvUi23CLA+YdqhGZcQ/Jfmu/olrvVE3Ia9wdqgB4sxp+JzPuPv2/+XV1lYzcxq32Q34lvlzbcKsF5h0vCZlxD+g2btXApSCvF1TbBOB/ba4oNSOvn7lr3KpWzC5pXHgVf4RKOk3P5CqOUEmn5eW6CxfAA2n4ndyHC+AR5YwMXOFyWngx7i4h8XJABm7kpkQGbqKmQAZu4lIiA3eiUiADd+JiIgM3k2IgAzezJJGBm2kSyMDNvBBk4CrJBxm4ynJB/kHAVRnf3OucumGvzBxTBZV+eouhn5u5t7HtvZlXhBBCCCEUsb+qGDWF0d8l5AAAAABJRU5ErkJggg=="
@ -103,7 +104,7 @@
</div>
</div>
</div>
</div>
</div> -->
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@ -124,7 +125,7 @@
d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"
/>
</svg>
Identification
Station
</h5>
<small
>Add your ham callsign and SSID. Optionally,
@ -133,30 +134,129 @@
>
</div>
<div class="col-lg-9 col-sm-12">
<div class="col-12">
<label for="callsign" class="form-label"
>Callsign</label
<div class="row">
<div class="col-12">
<label for="callsign" class="form-label"
>Callsign and SSID</label
>
<input
type="text"
name="callsign"
id="callsign"
class="form-control"
placeholder="N0CALL-10"
required=""
/>
</div>
<div class="col-12 mt-3">
<label
for="beacon.comment"
class="form-label"
>Beacon Comment</label
>
<input
type="text"
name="beacon.comment"
id="beacon.comment"
class="form-control"
placeholder="LoRa APRS"
/>
</div>
<div class="col-12 mt-3">
<label
for="beacon.path"
class="form-label"
>Beacon path</label
>
<input
type="text"
name="beacon.path"
id="beacon.path"
class="form-control"
placeholder="WIDE1-1"
required=""
/>
</div>
<div class="col-8 mt-3">
<input
type="hidden"
name="beacon.overlay"
id="beacon.overlay"
class="form-control"
size="1"
required=""
/>
<input
type="hidden"
name="beacon.symbol"
id="beacon.symbol"
class="form-control"
size="1"
required=""
/>
<label
for="action.symbol"
class="form-label"
>Symbol</label
>
<select
class="form-select form-select"
name="action.symbol"
id="action.symbol"
>
<option value="L#">
Green star with L
</option>
<option value="L_">
Blue circle with L
</option>
<option value="L&">
Black diamond with L
</option>
<option value="La">
Red diamond with L
</option>
</select>
</div>
<div
class="col-4 mt-3"
style="text-align: center"
>
<input
type="text"
name="callsign"
id="callsign"
class="form-control"
placeholder="N0CALL-10"
required=""
/>
</div>
<div class="col-12 mt-3">
<label for="iGateComment" class="form-label"
>APRS Beacon Comment</label
>
<input
type="text"
name="iGateComment"
id="iGateComment"
class="form-control"
placeholder="LoRa_APRS_iGate"
/>
<img
src=""
width="60"
height="60"
class="me-2"
/>
</div>
<div class="col-6 mt-3">
<label
for="beacon.latitude"
class="form-label"
>Latitude</label
>
<input
type="text"
name="beacon.latitude"
id="beacon.latitude"
placeholder="-33.440"
class="form-control"
/>
</div>
<div class="col-6 mt-3">
<label
for="beacon.longitude"
class="form-label"
>Longitude</label
>
<input
type="text"
name="beacon.longitude"
id="beacon.longitude"
placeholder="-70.613"
class="form-control"
/>
</div>
</div>
</div>
</div>
@ -204,7 +304,7 @@
>Password</label
>
<input
type="text"
type="password"
name="wifi.autoAP.password"
id="wifi.autoAP.password"
class="form-control"
@ -327,6 +427,54 @@
</div>
<div class="col-lg-9 col-sm-12">
<div class="row">
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="aprs_is.active"
id="aprs_is.active"
class="form-check-input"
/>
<label
for="aprs_is.active"
class="form-label"
>Enable APRS-IS
connection</label
>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="aprs_is.toRF"
id="aprs_is.toRF"
class="form-check-input"
/>
<label
for="aprs_is.toRF"
class="form-label"
>Gate APRS-IS traffic to
RF</label
>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.sendViaAPRSIS"
id="beacon.sendViaAPRSIS"
class="form-check-input"
/>
<label
for="beacon.sendViaAPRSIS"
class="form-label"
>Send our beacon to
APRS-IS</label
>
</div>
</div>
<div class="col-8">
<label
for="aprs_is.server"
@ -370,22 +518,18 @@
class="form-control"
/>
</div>
<div class="col-4" class="form-label">
<label for="aprs_is.reportingDistance"
>Reporting Distance</label
<div class="col-4">
<label
for="aprs_is.filter"
class="form-label"
>Filter</label
>
<div class="input-group mt-2">
<input
type="text"
class="form-control"
placeholder="30"
name="aprs_is.reportingDistance"
id="aprs_is.reportingDistance"
/>
<span class="input-group-text"
>Km</span
>
</div>
<input
type="text"
class="form-control"
name="aprs_is.filter"
id="aprs_is.filter"
/>
</div>
</div>
</div>
@ -427,6 +571,8 @@
>Always On</label
>
</div>
</div>
<div class="col-6">
<div
class="form-check form-switch mt-1"
>
@ -443,19 +589,45 @@
>
</div>
</div>
<div class="form-floating col-6 p-1">
<input
type="text"
name="display.timeout"
id="display.timeout"
value="4"
class="form-control"
/>
</div>
<div class="row mt-2">
<div class="col-6">
<label
for="display.timeout"
class="form-label"
>Display Timeout</label
>
<div class="input-group">
<input
type="text"
name="display.timeout"
id="display.timeout"
value="4"
class="form-control"
/>
<span class="input-group-text"
>seconds</span
>
</div>
</div>
<div class="col-6">
<label
for="other.rememberStationTime"
class="form-label"
>Remember Station Time</label
>
<div class="input-group">
<input
type="text"
name="other.rememberStationTime"
id="other.rememberStationTime"
placeholder="30"
class="form-control"
/>
<span class="input-group-text"
>minutes</span
>
</div>
</div>
</div>
</div>
@ -479,55 +651,62 @@
</svg>
Digipeating
</h5>
<small
>Define the location coordinates for the
Digipeater mode, and a special comment if
you like.</small
>
<small>Define the Digipeater mode</small>
</div>
<div class="col-9 mt-2">
<div class="row">
<div class="col-6">
<div class="col-12">
<label
for="digi.latitude"
for="digi.mode"
class="form-label"
>Latitude</label
>Repeater Mode</label
>
<input
type="text"
name="digi.latitude"
id="digi.latitude"
placeholder="-33.440"
class="form-control"
/>
</div>
<div class="col-6">
<label
for="digi.longitude"
class="form-label"
>Longitude</label
<select
class="form-select form-select"
name="digi.mode"
>
<input
type="text"
name="digi.longitude"
id="digi.longitude"
placeholder="-70.613"
class="form-control"
/>
<option value="0">
off
</option>
<option value="2">
WIDE1 (fill-in) Digi
</option>
</select>
</div>
</div>
<div class="col-12 mt-3">
<label for="digi.comment" class="form-label"
>Digipeater APRS Comment</label
>
<input
type="text"
name="digi.comment"
id="digi.comment"
class="form-control"
placeholder="LoRa_APRS_Digipeater"
/>
</div>
<!-- <div class="row mt-3">
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.igateSendsLoRaBeacon"
id="beacon.igateSendsLoRaBeacon"
class="form-check-input"
/>
<label
for="beacon.igateSendsLoRaBeacon"
class="form-label"
>IGate sends LoRa beacon</label
>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.igateRepeatLoRaPackets"
id="beacon.igateRepeatLoRaPackets"
class="form-check-input"
/>
<label
for="beacon.igateRepeatLoRaPackets"
class="form-label"
>IGate repeat LoRa
packets</label
>
</div>
</div>
</div> -->
</div>
</div>
<hr />
@ -572,7 +751,7 @@
>Password</label
>
<input
type="text"
type="password"
name="ota.password"
id="ota.password"
class="form-control"
@ -582,6 +761,52 @@
</div>
<hr />
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
<h5>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="currentColor"
class="bi bi-broadcast-pin"
viewBox="0 0 16 16"
>
<path
d="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707m2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708m5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708m2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8"
/>
</svg>
Telemetry
</h5>
<small>Define the telemetry</small>
</div>
<div class="col-9 mt-2">
<div class="row">
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="bme.active"
id="bme.active"
class="form-check-input"
/>
<label
for="bme.active"
class="form-label"
><b>Activate Wx Telemetry</b>
<small
>Requires a BME/BMP280 or
BME680 sensor
installed</small
></label
>
</div>
</div>
</div>
</div>
</div>
<hr />
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
<h5>
@ -606,17 +831,34 @@
</div>
<div class="col-lg-9 col-sm-12">
<div class="row">
<div class="col-6">
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.sendViaRF"
id="beacon.sendViaRF"
class="form-check-input"
/>
<label
for="beacon.sendViaRF"
class="form-label"
>Send beacon via RF</label
>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<label
for="other.beaconInterval"
for="beacon.interval"
class="form-label"
>Interval</label
>
<div class="input-group">
<input
type="text"
name="other.beaconInterval"
id="other.beaconInterval"
name="beacon.interval"
id="beacon.interval"
placeholder="15"
class="form-control"
/>
@ -625,25 +867,6 @@
>
</div>
</div>
<div class="col-6">
<label
for="other.rememberStationTime"
class="form-label"
>Remember Station Time</label
>
<div class="input-group">
<input
type="text"
name="other.rememberStationTime"
id="other.rememberStationTime"
placeholder="30"
class="form-control"
/>
<span class="input-group-text"
>minutes</span
>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-6">
@ -693,39 +916,6 @@
>
</div>
</div>
<div class="row mt-3">
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="other.igateSendsLoRaBeacon"
id="other.igateSendsLoRaBeacon"
class="form-check-input"
/>
<label
for="other.igateSendsLoRaBeacon"
class="form-label"
>IGate sends LoRa beacon</label
>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="other.igateRepeatLoRaPackets"
id="other.igateRepeatLoRaPackets"
class="form-check-input"
/>
<label
for="other.igateRepeatLoRaPackets"
class="form-label"
>IGate repeat LoRa
packets</label
>
</div>
</div>
</div>
</div>
</div>
<hr />
@ -763,7 +953,7 @@
<label
for="syslog.active"
class="form-label"
>Active</label
>Enable syslog</label
>
</div>
<div class="row mt-3">
@ -825,17 +1015,47 @@
</div>
<div class="col-lg-9 col-sm-12">
<div class="row">
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="lora.txActive"
id="lora.txActive"
class="form-check-input"
/>
<label
for="lora.txActive"
class="form-label"
>Enable LoRa TX</label
>
</div>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="lora.rxActive"
id="lora.rxActive"
class="form-check-input"
/>
<label
for="lora.rxActive"
class="form-label"
>Enable LoRa RX</label
>
</div>
</div>
<div class="col-6">
<label
for="lora.digirepeaterTxFreq"
for="lora.txFreq"
class="form-label"
>Tx Frequency</label
>
<div class="input-group">
<input
type="text"
name="lora.digirepeaterTxFreq"
id="lora.digirepeaterTxFreq"
name="lora.txFreq"
id="lora.txFreq"
placeholder="433775000"
class="form-control"
/>
@ -853,18 +1073,17 @@
</div>
<div class="col-6">
<label
for="lora.digirepeaterRxFreq"
for="lora.rxFreq"
class="form-label"
>Rx Frequency</label
>
<div class="input-group">
<input
type="text"
name="lora.digirepeaterRxFreq"
id="lora.digirepeaterRxFreq"
name="lora.rxFreq"
id="lora.rxFreq"
placeholder="433775000"
class="form-control"
disabled
/>
<span class="input-group-text"
>Hz</span
@ -872,7 +1091,43 @@
</div>
</div>
</div>
<div class="row mt-3">
<div class="row mt-4">
<div class="col-12 mb-4">
<label
for="action.speed"
class="form-label"
>Predefined speeds</label
>
<select
class="form-select form-select"
name="action.speed"
id="action.speed"
>
<option value="300">
BW 125khz CR 4:5 SF 12 (Slow
Standard, 300bps)
</option>
<option value="244">
BW 125khz CR 4:6 SF 12 (244bps)
</option>
<option value="209">
BW 125khz CR 4:7 SF 12 (209bps)
</option>
<option value="183">
BW 125khz CR 4:8 SF 12 (183bps)
</option>
<option value="610">
BW 125khz CR 4:8 SF 10 (610bps)
</option>
<option value="1200">
BW 125khz CR 4:7 SF 9 (Fast
Standard, 1200bps)
</option>
<option value="">
User defined
</option>
</select>
</div>
<div class="col-5">
<label
for="lora.signalBandwidth"
@ -937,9 +1192,10 @@
required=""
>
<option value="4">4</option>
<option value="5" selected>
5
</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
</select>
</div>
<div class="col-6">
@ -950,10 +1206,13 @@
>
<div class="input-group">
<input
type="text"
type="number"
name="lora.power"
id="lora.power"
placeholder="20"
min="0"
max="23"
step="1"
class="form-control"
required=""
/>

View file

@ -75,9 +75,13 @@ function loadSettings(settings) {
currentSettings = settings;
// General
document.getElementById("callsign").value = settings.callsign;
document.getElementById("stationMode").value = settings.stationMode;
// document.getElementById("stationMode").value = settings.stationMode;
document.getElementById("bme.active").checked = settings.bme.active;
document.getElementById("iGateComment").value = settings.iGateComment;
document.getElementById("beacon.comment").value = settings.beacon.comment;
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
document.getElementById("beacon.overlay").value = settings.beacon.overlay;
document.getElementById("action.symbol").value = settings.beacon.overlay + settings.beacon.symbol;
document.querySelector(".list-networks").innerHTML = "";
@ -94,23 +98,15 @@ function loadSettings(settings) {
// Increment the name, id, and for attributes
const attributeName = `wifi.AP.${networkCount}`;
networkElement.innerHTML = `
<div class="form-floating col-6 col-md-3 px-1 mb-2">
<div class="form-floating col-5 px-1 mb-2">
<input type="text" class="form-control form-control-sm" name="${attributeName}.ssid" id="${attributeName}.ssid" value="${network.ssid}">
<label for="${attributeName}.ssid">SSID</label>
</div>
<div class="form-floating col-6 col-md-3 px-1 mb-2">
<input type="text" class="form-control form-control-sm" name="${attributeName}.password" id="${attributeName}.password" value="${network.password}">
<div class="form-floating col-5 px-1 mb-2">
<input type="password" class="form-control form-control-sm" name="${attributeName}.password" id="${attributeName}.password" value="${network.password}">
<label for="${attributeName}.password">Passphrase</label>
</div>
<div class="col-4 col-md-2 form-floating px-1 mb-2">
<input type="text" class="form-control form-control-sm latitude" name="${attributeName}.latitude" id="${attributeName}.latitude" value="${network.latitude}">
<label for="${attributeName}.latitude">Latitude</label>
</div>
<div class="col-4 col-md-2 form-floating px-1 mb-2">
<input type="text" class="form-control form-control-sm longitude" name="${attributeName}.longitude" id="${attributeName}.longitude" value="${network.longitude}">
<label for="${attributeName}.longitude">Longitude</label>
</div>
<div class="col-4 col-md-2 d-flex align-items-center justify-content-end">
<div class="col-2 d-flex align-items-center justify-content-end">
<div class="btn-group" role="group">
<button type="button" class="btn btn-sm btn-danger" title="Delete" onclick="return this.parentNode.parentNode.parentNode.remove();"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3-fill" viewBox="0 0 16 16">
<path d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5m-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5M4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06m6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528M8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5"/>
@ -123,10 +119,11 @@ function loadSettings(settings) {
});
// APRS-IS
document.getElementById("aprs_is.active").checked = settings.aprs_is.active;
document.getElementById("aprs_is.toRF").checked = settings.aprs_is.toRF;
document.getElementById("aprs_is.server").value = settings.aprs_is.server;
document.getElementById("aprs_is.port").value = settings.aprs_is.port;
document.getElementById("aprs_is.reportingDistance").value =
settings.aprs_is.reportingDistance;
document.getElementById("aprs_is.filter").value = settings.aprs_is.filter;
document.getElementById("aprs_is.passcode").value =
settings.aprs_is.passcode;
@ -148,17 +145,16 @@ function loadSettings(settings) {
settings.wifi.autoAP.powerOff;
// Digi
document.getElementById("digi.comment").value = settings.digi.comment;
document.getElementById("digi.latitude").value = settings.digi.latitude;
document.getElementById("digi.longitude").value = settings.digi.longitude;
// document.getElementById("digi.comment").value = settings.digi.comment;
// document.getElementById("digi.latitude").value = settings.digi.latitude;
// document.getElementById("digi.longitude").value = settings.digi.longitude;
// OTA
document.getElementById("ota.username").value = settings.ota.username;
document.getElementById("ota.password").value = settings.ota.password;
// Beacon
document.getElementById("other.beaconInterval").value =
settings.other.beaconInterval;
document.getElementById("beacon.interval").value = settings.beacon.interval;
document.getElementById("other.rememberStationTime").value =
settings.other.rememberStationTime;
document.getElementById("other.sendBatteryVoltage").checked =
@ -167,10 +163,18 @@ function loadSettings(settings) {
settings.other.externalVoltageMeasurement;
document.getElementById("other.externalVoltagePin").value =
settings.other.externalVoltagePin;
document.getElementById("other.igateSendsLoRaBeacon").value =
settings.other.igateSendsLoRaBeacon;
document.getElementById("other.igateRepeatLoRaPackets").value =
settings.other.igateRepeatLoRaPackets;
// document.getElementById("beacon.igateSendsLoRaBeacon").value =
// settings.beacon.igateSendsLoRaBeacon;
// document.getElementById("beacon.igateRepeatLoRaPackets").value =
// settings.beacon.igateRepeatLoRaPackets;
document.getElementById("beacon.path").value = settings.beacon.path;
document.getElementById("beacon.latitude").value = settings.beacon.latitude;
document.getElementById("beacon.longitude").value =
settings.beacon.longitude;
document.getElementById("beacon.sendViaAPRSIS").checked =
settings.beacon.sendViaAPRSIS;
document.getElementById("beacon.sendViaRF").checked =
settings.beacon.sendViaRF;
// Syslog
document.getElementById("syslog.active").checked = settings.syslog.active;
@ -183,11 +187,15 @@ function loadSettings(settings) {
}
// LoRa
document.getElementById("lora.digirepeaterTxFreq").value =
settings.lora.digirepeaterTxFreq;
document.getElementById("lora.iGateFreq").value = settings.lora.iGateFreq;
document.getElementById("lora.digirepeaterRxFreq").value =
settings.lora.digirepeaterRxFreq;
// document.getElementById("lora.digirepeaterTxFreq").value =
// settings.lora.digirepeaterTxFreq;
// document.getElementById("lora.iGateFreq").value = settings.lora.iGateFreq;
// document.getElementById("lora.digirepeaterRxFreq").value =
// settings.lora.digirepeaterRxFreq;
document.getElementById("lora.txFreq").value = settings.lora.txFreq;
document.getElementById("lora.rxFreq").value = settings.lora.rxFreq;
document.getElementById("lora.txActive").checked = settings.lora.txActive;
document.getElementById("lora.rxActive").checked = settings.lora.rxActive;
document.getElementById("lora.spreadingFactor").value =
settings.lora.spreadingFactor;
document.getElementById("lora.signalBandwidth").value =
@ -197,65 +205,38 @@ function loadSettings(settings) {
document.getElementById("lora.power").value = settings.lora.power;
updateImage();
refreshSpeedStandard();
}
const bmeCheckbox = document.querySelector("input[name='bme.active']");
const stationModeSelect = document.querySelector("select[name='stationMode']");
const digirepeaterTxFreqInput = document.querySelector(
"input[name='lora.digirepeaterRxFreq']"
);
function updateImage() {
const value = document.getElementById("beacon.overlay").value + document.getElementById("beacon.symbol").value;
const image = document.querySelector("img");
const isChecked = bmeCheckbox.checked;
if (isChecked) {
image.src =
"data:image/png;base64,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";
} else {
const selectedValue = stationModeSelect.value;
if (selectedValue === "1") {
if (bmeCheckbox.checked) {
image.src =
"data:image/png;base64,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";
} else {
image.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ6SURBVHgB7d0/axRBGMfx50IMWPoKkpA02gUsLfZdqOCLOPBFWAliHbCUVNpaxQNrIY0WVjZaJlUsIsZ5uDu9bGb/zMwzs/PM/L7wIG4Ocflwl7ndvVsihBBCmTajunpk5uHG33+aOSGkvhdmLs1cW+bKzDEhle2a+UZ22Pacrx6PlMRYXc/arrkkIKvIBxfISgrBBXLmSeACOdMkcYGcWTFwgZxJMXGBPHEpcIE8USlxgSzcbGD2KD0ukIXKGRfIAuWOC+TANOACOSAtuEAemQ10a2P2KV9cIA+0ZZltMzurOaT8cYHcUx+wJlwgd9QFrBEXyJZswAekFxfIrdq4GhZUQO7Itlq+QzoXVEC21AdcIm51yF3AJeNWhWwDLmFBBeRVmg4/Atmj2nGLR/bCbZrm2qWx/+7Ekwx5i9LGO/XFzF2qO97/r5QAOSUwcG+WBDkVMHDtRUdOAcz/ed4J4NqLihwbGLjjioYcExi4bkVBjgUMXL/EkWMAAzcsUWRpYODKJIYsCQxc2USQpYCBG6dgZAlg4MYtCDkUGLhp8kYOAQZu2ryQfYGT4S7PAKJVzsg+wEmfubNZbd+XOpgTsiswXpbzaDSyCzBw82oU8lhg4ObZIPIYYODmXS/yEDBwdcQ+72w/6AMGrq6OaHnLghv1AQNXX6/bG7qAPxNwNbbf3mAD5qf5EaEisgG/IVRMNuA9QsVkA94mpLWP7Q2pP5uE4vayvQHA5bQw86m90Qb8i5C22Kyx/cAG/IGQphj3ftcPbcBzM78JaWiN+73rATZgfvAzWn4SHeXbIC7Xtcg6MfOUgJxro3C5vlU0kPNsNC439DYJyHnlhMuNeR8M5DxyxuXGHugA8rR54XIuR7KAPE3euJzroUogpy0Il/M5Fg3kNAXjcr4nG4AcNxFcLuTc78nqz7e0/A7KLDo9PbV+nkn6Q2xnZ2c0n88pQmK4XOjJ/eyQm6YhxYnichLng/FyLZM4Lid1wh/IYUXB5SSv6ACyX9FwOelLdoDsVlRcLsY1WUAeV3RcLtZFd0Duj3EfUGRcLuZVlUC2lwyXi32Re/D75IuLC1osFtYDFXxAo73dts21MV/8wgc6PEqKm7LHZv5QnndASTV8p5U9unl7oaJ6QvUi23CLA+YdqhGZcQ/Jfmu/olrvVE3Ia9wdqgB4sxp+JzPuPv2/+XV1lYzcxq32Q34lvlzbcKsF5h0vCZlxD+g2btXApSCvF1TbBOB/ba4oNSOvn7lr3KpWzC5pXHgVf4RKOk3P5CqOUEmn5eW6CxfAA2n4ndyHC+AR5YwMXOFyWngx7i4h8XJABm7kpkQGbqKmQAZu4lIiA3eiUiADd+JiIgM3k2IgAzezJJGBm2kSyMDNvBBk4CrJBxm4ynJB/kHAVRnf3OucumGvzBxTBZV+eouhn5u5t7HtvZlXhBBCCCEUsb+qGDWF0d8l5AAAAABJRU5ErkJggg==";
}
digirepeaterTxFreqInput.disabled = true;
} else if (selectedValue === "2") {
if (bmeCheckbox.checked) {
image.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAlUSURBVHgB7Z1LiBxFGMe/nt1s1nd8Pw4uERVfCJqDB8XsSUHER1DiTYweRBCTgBdBETyIh6AQDx6SoAc1EjRCCOJBkg1CDoaYBSGHRDQhia+8dJdN9jVtfTXduz09X01XdVd3V/V+P/g2mZqame7+d1V99VV1FQDDMAzjKAE0lnCt+HNz9OI+YbcTmfYL+yv6/wFxOX6EhtEAgaWQLwgbEbZS2FVQ7LzmhE0KG4fODbC7icI7DAoa7hR2TlhYkc0KOyJsi7ARYGwjRT0YXejQAZuKbrJHgMkLlhR5EaccEVVlp4S9D4wuWCpkddh2XFiqGt8JXIWrWBDWF0FVhjfmXhZ6AVkVN0FYSugtsLSRVZpvVbGpoQ+xHpYW0it23XmybdgLGIHmI9snX0SxbbNVl+YKI1ny7j0kbAUwY+LSj0IFtKASZDjxNzAWNyzBnGA1dCJxI1AyFQgsPcntYFxbOCNGWeDNfjS6+Uuj5CoaHQt4AHJRlsDOja/giW4Ux/URlECJZ4t9W3KITvfzUA7ODqBtFcf2ClimpCq6qLhLkpehhMBICbdzXnFDzbQ26BEAfXq6abVhtSRbPrO84rYVaVT6LOiBldMAkT5IpKluhtqwJrLFKhoDGFwtW2JdAe+6lTRLAsu2YzUwtsDq5EuwMKHAQr0k77TtUAiuohVcEHa3OLZjBp/pKrQFz0pGYkRnnbxqBrDAfRDXN7jDIL9VgU/B4tRU3c8QaXNE+sXI0vwNelwWWRoqWoqiO+1dmzhdLeULM3As11RcJifriPa4pWM5BZY/9jQwVYFVyS7IQd4SvAsa/VSEk6yIak0jcggsp4jymG49PG06xGg6hGfBa6acrBlh86m0icjSHAU9rokszS1E2nKg73UnK6nYq1YVzq50U6E+g8JdIop56BUYu4D/LbwaHb0C9uzB89ILlgXBbqAP9UYizauxZ3EBpkXsYfkO+u3n83rRsvQ+CkwNpGelLPtEkbGVmdAHLL3sWLmB8IHm39DJqCkwl173CN7RyaVbgksuvdTkOAxTziVs3vA7Z1Kfj83ZiXimiFJ8IXMwQtdhehisoRrETwuIYcrJxOtlYMZZ6DwLnmZe8fvpe92H1mhom/hzZ3faP6ZetOz3luA5M8WQBeU2gOMrAW6NR5taq1ZNGHvRLwLjKqKauemtfhkyBJbOFQ8oOM3Amn7vZpXgt4FxHeFsTSh9pCyBn4BKoDxbdIZmEzYHZlxMfT62xnjRCYY3qN7p4zxx9VwPJjfcQt6HIBr/PXPmzFAyR78S/CownhDcpHqnn8CPA+MRk69Tqf0EvgsYjxh8ikzt84lLoHYW26MwzOMMNcGB0mXwfjKVzuzeoiGBceSw6eL29AAwLtuanp7u0lRVRa8GxiG0Vi8QReDwI+12u5U0lcBG834YV7i252F7lcArgfGQ4Z7hQ5XAy4HxkODqdIrKi3bAg2bMGbhd9Da63FEe5/UWKo7evgQdq2QKUUXzKqlNgmqDnwXGUwaG0ikWl3Bg6icYTqc0uA1WjfXqPmxuskqPivon7rGT5QWqJabCnrTTp0NbD4AzPsACN4qwZ14TJfABYDylPZVOIdpg3MatCUNteDPPEOnUwi6D0HspVE7WgGaaqnKs1vFqsJOlEniaSFMJ3FLkTbNMkbeOh8r1nCzTOaqME0z/kk5RCTwJTCNQCXwaGA+Z2J1OUbXBJ8H7lWOx/b1ApFOVE0ax0pciXkssjWqofIB4XXUka6pnGUCVwN+C9/OysBKiBLqUSMPhb0ogyju+mki7DnqFx7AwJXCZjtc93wBcc1nWryHGC24xdTP/b+ffs+2kKQSWy9eyJ+0VbXLJ4X6hyt+B8YipH6jUfgKPAeMRP22jUvtFsj4FudVLFVBhQXRwkguvmAbdTgC9tvQJIg2/O32v428PEXmpGcX4GNeVqTR0xignzXQxGR3aIv765HEgLlKfqyZj0tjP4BmWTpIsEPM4QBTPWujynbKKxffCngEP2bPnXQiC3hYoDHUHBlSx6O5ZMePjZ2H9+vNQL2eVG2plCbwJPBV4dPReqI46BcYx4JGvVe9mDPhjNU2GgxhnmPmu37s6Mzq+gNKJq8OkoTMynLAhYChObO73ro7A74HVGQABYdR+EizwItQ1Q+b/FOHJ/YmM6GR1PVOqIbCMav0KjGOgyFMfwqL3TJrupLuXgHEMdK6u+zgrl6bA0tnS3SyBqYSZz3VymUybLbEUU+0w9uCWJ6yMCJANsF8d+whJi8eDqbazMKL0Xq61jplB/E9GtrAUlzARAA8j7cddAUlRz58fhLGxWRGo6J0VGQRtkd5OpeVdmWfhG8R3BIpjXWR8HPPcAPR4cFlzGuc26eY03VYHlwjYB4VuRd29C7H7TU1xpWLJk9A7uolrXZrsFp5GtbmlyYD/MJF3Wcbvqx5TWUBEVQauB/ruwYPWXsqQOhBsi/cBUyMXXjPJbSgwEowCTwaoifYh0fbuMPlEDoElbwJTNaJQ/fEcGFKkLT0o/jwAVjDZIJp6MgHb295HKYuT7WR1oJ5sUM3KzCpTqjZ4dqNo0zdnHEhPG1xEYFzL4zBYGS9mgfuDVfPAKsg+kJ4fzVtFQxTCxL7xUlrxsw5Ed2JiDeSkgMBI8JX4sw2YssDC8xjAimOQk4ICI3JveQ5jlsMHUdc0NxafrQjPQe6No1WOBdUGq3Yuq6qlMHk+uNAiLlujwhN/WRqtNtimwBadLvl9JeUtSiWr7MSbQMeovLVML86iwIhNkZeswGlxERN33JYXTSE967uB53HlhRK3EJYFRljknFgXFylBYMSGyJW0dSVidEw/lyEuUpLAyILIBbpQgYG1KjLd49EGveUHwW/CvTj8ztZlom9XaHcb1R04mLKqwJORJ+WTCGXZFHQmTxRBS+CKGy/ZjRKB87wBkUYwFo2pF6WOblIW2C7LjSNwDZAQlhY4SWKDJXF9AKuo8JQnVWpR2wv2ca0NViHb5lmPxDKxUxbaWlPSgrtCuKVBQp+D+vZ/dFXgGK+FrlPYGNcFjpFVtw9tNHb9DkL1VbEKXwSOkc7YTuj0HV0SFm++LeAevgmcZEHsOko2ltQjHVGd3jzMZ4HTyGp8byS47RJ+LiHoWvAUF4dhCiLFuBk6i6nGDxLdCfQkBFyx9GT0fxwUwQW1DxSdB8UwDMMwDMM0nP8Bl3lxJTtDbOQAAAAASUVORK5CYII=";
} else {
image.src =
"data:image/png;base64,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";
}
digirepeaterTxFreqInput.disabled = true;
} else if (selectedValue === "3" || selectedValue === "4") {
switch (value) {
case "L&":
image.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ6SURBVHgB7d0/axRBGMfx50IMWPoKkpA02gUsLfZdqOCLOPBFWAliHbCUVNpaxQNrIY0WVjZaJlUsIsZ5uDu9bGb/zMwzs/PM/L7wIG4Ocflwl7ndvVsihBBCmTajunpk5uHG33+aOSGkvhdmLs1cW+bKzDEhle2a+UZ22Pacrx6PlMRYXc/arrkkIKvIBxfISgrBBXLmSeACOdMkcYGcWTFwgZxJMXGBPHEpcIE8USlxgSzcbGD2KD0ukIXKGRfIAuWOC+TANOACOSAtuEAemQ10a2P2KV9cIA+0ZZltMzurOaT8cYHcUx+wJlwgd9QFrBEXyJZswAekFxfIrdq4GhZUQO7Itlq+QzoXVEC21AdcIm51yF3AJeNWhWwDLmFBBeRVmg4/Atmj2nGLR/bCbZrm2qWx/+7Ekwx5i9LGO/XFzF2qO97/r5QAOSUwcG+WBDkVMHDtRUdOAcz/ed4J4NqLihwbGLjjioYcExi4bkVBjgUMXL/EkWMAAzcsUWRpYODKJIYsCQxc2USQpYCBG6dgZAlg4MYtCDkUGLhp8kYOAQZu2ryQfYGT4S7PAKJVzsg+wEmfubNZbd+XOpgTsiswXpbzaDSyCzBw82oU8lhg4ObZIPIYYODmXS/yEDBwdcQ+72w/6AMGrq6OaHnLghv1AQNXX6/bG7qAPxNwNbbf3mAD5qf5EaEisgG/IVRMNuA9QsVkA94mpLWP7Q2pP5uE4vayvQHA5bQw86m90Qb8i5C22Kyx/cAG/IGQphj3ftcPbcBzM78JaWiN+73rATZgfvAzWn4SHeXbIC7Xtcg6MfOUgJxro3C5vlU0kPNsNC439DYJyHnlhMuNeR8M5DxyxuXGHugA8rR54XIuR7KAPE3euJzroUogpy0Il/M5Fg3kNAXjcr4nG4AcNxFcLuTc78nqz7e0/A7KLDo9PbV+nkn6Q2xnZ2c0n88pQmK4XOjJ/eyQm6YhxYnichLng/FyLZM4Lid1wh/IYUXB5SSv6ACyX9FwOelLdoDsVlRcLsY1WUAeV3RcLtZFd0Duj3EfUGRcLuZVlUC2lwyXi32Re/D75IuLC1osFtYDFXxAo73dts21MV/8wgc6PEqKm7LHZv5QnndASTV8p5U9unl7oaJ6QvUi23CLA+YdqhGZcQ/Jfmu/olrvVE3Ia9wdqgB4sxp+JzPuPv2/+XV1lYzcxq32Q34lvlzbcKsF5h0vCZlxD+g2btXApSCvF1TbBOB/ba4oNSOvn7lr3KpWzC5pXHgVf4RKOk3P5CqOUEmn5eW6CxfAA2n4ndyHC+AR5YwMXOFyWngx7i4h8XJABm7kpkQGbqKmQAZu4lIiA3eiUiADd+JiIgM3k2IgAzezJJGBm2kSyMDNvBBk4CrJBxm4ynJB/kHAVRnf3OucumGvzBxTBZV+eouhn5u5t7HtvZlXhBBCCCEUsb+qGDWF0d8l5AAAAABJRU5ErkJggg==";
break;
case "L#":
image.src =
"data:image/png;base64,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";
digirepeaterTxFreqInput.disabled = selectedValue === "3";
} else if (selectedValue === "5") {
if (bmeCheckbox.checked) {
image.src =
"data:image/png;base64,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";
} else {
image.src =
"data:image/png;base64,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";
}
digirepeaterTxFreqInput.disabled = true;
}
break;
case "L_":
image.src =
"data:image/png;base64,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";
break;
case "La":
image.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAcvSURBVHgB7Z0/bxxFFMDfnS+OAwQCQiAqhCAGQYGgQ6LwV6CI6GhCQ+eWClMRIQo+AHwGKgoqKxUdUgrEn1yEkCyQEIossBTH9t0yD+/C3uwb78zu/Hkz937SyLnJ/dm9372Zt7MzuwCCIAgCUyawBlQA76o/z6nyldrhX0HIHyV1V5XfVKm0cqrKd6q8DUKeKHl3CbF6WaryBQh5YSm3XURyLgyQK5JzYYRckcwdD3JFMlc8yhXJ3AggVyRzIaBckZyaCHJFcioiyhXJAZlQZankqlINKSKZD97lehAskj3iXa4nwSLZE97lehQskj3gXa5nwVlJ5nDCn9qGyQLgJ/X3paZiCfZvNjHU29Q58KV6/fvAnNSCp1TdMcCPasNebFeegv0bbhD1M6LO9GNwgL3kKTDjhJDLmJvcm2tWgrFZzkhuA2vJM2CC3udmBkoGJs311PggFZnLbWAZyTGTLOqzZiqh+qHdLB/XRecPsOPRuuhcI+pmUGR2zSeCH2pyC4FVJCcTrI5rfy5QbgMbyUkEo1zIv8/tg4Xk6ILXRG5DcslRD5N0uTj8uNCe80CVv4nXHoAdTxHviTxG1OGIV4QsM+khVDTBVOQugBb8V+vx1Z0duL6/bx3yX08m5E49S9RVEI1kkqM00Wrn7sL6NMsmkjTXwQWL3BWiSw7aRItcktDN9cqZ1WCCbeRW0O0HcevOWo8X4MaJ9vr2ZzEiWp8cRDAll/qCqSwahymPWo8vgRv3VXmCqF8YPl/voyKO3UaR7L0PlmbZieB9slfBIncQQSV7EyxyRxFMshfBItcLQSSPTrLGyKWyaEyG2hPszsCNY6An6DHLok14T7xGRbBEbhC8RvJgwSI3KN4kDxIscqPgRbKzYJEbldGSnZKsWHLbCVFVuadHmSRUtoxKvKwjOFnkTtwGDwuT2zA4kq0ES7PMgkGSe5tokcsKm+bafl60yGWJUyQbBYtc1lhLJgWL3CywktwRrF60CyI3F3olUxH8EQg5cbMOSpIVweqJzwO9EE/gjTEo9Qh+B4QcuVad31mmA7trdIylMpTlyFI5lER8QFUWJ1hYZUWwGiH5HISioCL4dxCyRe8uKMGfgpAj31KVnZMN2Ewr8++pf74BGYKT9E6IeurCLjPofgGmq99tWNaZkprAKybO1Pt/SP3HzLAxb+Y6XGkS/JCoMwmeGp6rc8nwXKousODPTP9hzKLVBl1Xf+YgcGduil7kwvPBKFlOPPBFHZ/fU93Ey9AK1I9dr5MlkcyTWu523/OsJt3lFMnY/z4g6o+IOhyh0r+AKdC/+stAs0E8jrAEdV5Hbi/Wsypzkfwn0IIeIequAC2Iyo6fJOqehq74LaAFe0y85nWrajUK6TRUKc11chq51jiPRYvkZDjLRQatLpTsOjq2cqff3/B0tVmJ5GgMityGUeuDx0YyNSyICU77wiuuG3gA9LWlD4g6fG/9F46fvUk89wWi7hVVHtfqMBmjkjTXi8nUjJKLjD4fLJEcjNFykdEr/BFOffLe/j5MifVMG8QiNtOhC1W/pT2+f+cOHO4a57qNxYtcxItghIvk13Z2IBaHEARvchGvU3akuR6NV7mI9zlZLpKb5rBdMBnZapVNWBu8y0WCTLqjJFM3BZ6CCK4JIhcJNqtSmmtrgslFgk6bFcm9BJWLBJ8XLZKNBJeLeDtMugjckSVxCEUdc+IGtU/BDRwBCg6OVlE5guX54PnU4mS9D6IIRnCH9Btz4Ifrww9XQRuqPDyE09u34ZgYqFiqAY2lXq/qhlyZ57+X//sWXUWdyXlqoOMZoM8H93yp0eQiFj82v5/VlowzIHUVOBuDmuJKjSUfQfdalgtwu1u4jukG0y4n/LeI59Y/Wl3umKVM5ITOG77OJg2l3sF17JOjRm5DdMH1h66VZBWm91LIRZIIrj94G3ccCgf3UTXZr0IioiVZQPQ3qv/a1m8Ojff+vUK8mJo0tyDe1Mf6XPJGx0QdtbJBm5XZnv2YZOlwsghuqL+AEptr66mtIUkuGClQMgu5CAvBSCmSq/+Xk7CAjWAEv5icEy/c9s3zqVpsiJlkUXQSD/UFbZ8Qt3+nThsuIV7m0rc+GOVePpcbc7N6YScY2Twfu14Z1tywfXEgeob8fI5QeYVVE90mo8GQJCNUtrAVjGQgmbVchLVghLFk9nIRjoI7/ZdJcsxTYRoXyWXT/yKpkywTlGRy3nUCyVFmYviCfRPdhsH0n6zkIlkJRhJKzk4ukrAbG0fkZTIc5ZLBued6lR2uRIzkLCO3IVvBSATJWctFshaMBJScvVwke8FIAMlFyEWKEIx4lFyMXKQYwYgHyUXJRYoSjIyQXJxcpDjByADJRcpFihSM1MJuQXd1Sxsc875Vqlwk25EsF5TFT9Sft1R5va76RZVvLrqQdiZ0AnSveycdoTDKGKoU7BDBhSOCC0cEF84/ey2tg1yFQhMAAAAASUVORK5CYII=";
break;
}
}
stationModeSelect.addEventListener("change", updateImage);
bmeCheckbox.addEventListener("change", updateImage);
function toggleFields() {
const sendBatteryVoltageCheckbox = document.querySelector(
'input[name="other.sendBatteryVoltage"]'
@ -301,22 +282,14 @@ document.querySelector(".new button").addEventListener("click", function () {
// Increment the name, id, and for attributes
const attributeName = `wifi.AP.${networkCount}`;
networkElement.innerHTML = `
<div class="form-floating col-6 col-md-3 px-1 mb-2">
<div class="form-floating col-6 col-md-5 px-1 mb-2">
<input type="text" class="form-control form-control-sm" name="${attributeName}.ssid" id="${attributeName}.ssid" placeholder="" >
<label for="${attributeName}.ssid">SSID</label>
</div>
<div class="form-floating col-6 col-md-3 px-1 mb-2">
<input type="text" class="form-control form-control-sm" name="${attributeName}.password" id="${attributeName}.password" placeholder="">
<div class="form-floating col-6 col-md-5 px-1 mb-2">
<input type="password" class="form-control form-control-sm" name="${attributeName}.password" id="${attributeName}.password" placeholder="">
<label for="${attributeName}.password">Passphrase</label>
</div>
<div class="col-4 col-md-2 form-floating px-1 mb-2">
<input type="text" class="form-control form-control-sm latitude" name="${attributeName}.latitude" id="${attributeName}.latitude" placeholder="">
<label for="${attributeName}.latitude">Latitude</label>
</div>
<div class="col-4 col-md-2 form-floating px-1 mb-2">
<input type="text" class="form-control form-control-sm longitude" name="${attributeName}.longitude" id="${attributeName}.longitude" placeholder="">
<label for="${attributeName}.longitude">Longitude</label>
</div>
<div class="col-4 col-md-2 d-flex align-items-center justify-content-end">
<div class="btn-group" role="group">
<button type="button" class="btn btn-sm btn-danger" title="Delete" onclick="return this.parentNode.parentNode.parentNode.remove();"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3-fill" viewBox="0 0 16 16">
@ -333,6 +306,77 @@ document.querySelector(".new button").addEventListener("click", function () {
document.querySelector(".new").before(networkElement);
});
document
.getElementById("action.symbol")
.addEventListener("change", function () {
const value = document.getElementById("action.symbol").value;
document.getElementById("beacon.overlay").value = value[0];
document.getElementById("beacon.symbol").value = value[1];
updateImage();
});
const speedStandards = {
300: [125, 5, 12],
244: [125, 6, 12],
209: [125, 7, 12],
183: [125, 8, 12],
610: [125, 8, 10],
1200: [125, 7, 9],
};
function refreshSpeedStandard() {
const bw = Number(document.getElementById("lora.signalBandwidth").value);
const cr4 = Number(document.getElementById("lora.codingRate4").value);
const sf = Number(document.getElementById("lora.spreadingFactor").value);
let found = false;
for (const speed in speedStandards) {
const standard = speedStandards[speed];
if (standard[0] !== bw / 1000) continue;
if (standard[1] !== cr4) continue;
if (standard[2] !== sf) continue;
document.getElementById("action.speed").value = speed;
found = true;
break;
}
if (!found) {
document.getElementById("action.speed").value = "";
}
}
document
.getElementById("lora.signalBandwidth")
.addEventListener("focusout", refreshSpeedStandard);
document
.getElementById("lora.codingRate4")
.addEventListener("focusout", refreshSpeedStandard);
document
.getElementById("lora.spreadingFactor")
.addEventListener("focusout", refreshSpeedStandard);
document.getElementById("action.speed").addEventListener("change", function () {
const speed = document.getElementById("action.speed").value;
if (speed !== "") {
const value = speedStandards[Number(speed)];
const bw = value[0];
const cr4 = value[1];
const sf = value[2];
document.getElementById("lora.signalBandwidth").value = bw * 1000;
document.getElementById("lora.codingRate4").value = cr4;
document.getElementById("lora.spreadingFactor").value = sf;
}
});
toggleFields();
const form = document.querySelector("form");
@ -382,7 +426,7 @@ form.addEventListener("submit", async (event) => {
saveModal.show();
setTimeout(checkConnection, 0);
setTimeout(checkConnection, 2000);
});
fetchSettings();

View file

@ -16,17 +16,18 @@
#include "web_utils.h"
#include "display.h"
#include "utils.h"
#include <ElegantOTA.h>
Configuration Config;
WiFiClient espClient;
String versionDate = "2024.02.25";
String versionDate = "2024.03.07";
int myWiFiAPIndex = 0;
int myWiFiAPSize = Config.wifiAPs.size();
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
int stationMode = Config.stationMode;
bool isUpdatingOTA = false;
bool statusAfterBoot = true;
bool beaconUpdate = true;
uint32_t lastBeaconTx = 0;
@ -36,7 +37,6 @@ uint32_t lastScreenOn = millis();
uint32_t lastWiFiCheck = 0;
bool WiFiConnect = true;
bool WiFiConnected = false;
int lastStationModeState = 1;
bool WiFiAutoAPStarted = false;
long WiFiAutoAPTime = false;
@ -69,47 +69,56 @@ void setup() {
#endif
delay(1000);
Utils::setupDisplay();
Config.check();
WIFI_Utils::setup();
LoRa_Utils::setup();
Utils::validateDigiFreqs();
Utils::validateFreqs();
iGateBeaconPacket = GPS_Utils::generateBeacon();
iGateLoRaBeaconPacket = GPS_Utils::generateiGateLoRaBeacon();
SYSLOG_Utils::setup();
BME_Utils::setup();
WEB_Utils::setup();
}
void loop() {
WEB_Utils::loop();
WIFI_Utils::checkIfAutoAPShouldPowerOff();
if (stationMode==1 || stationMode==2 ) { // iGate (1 Only Rx / 2 Rx+Tx)
if (!WiFiConnected) {
thirdLine = Utils::getLocalIP();
}
WIFI_Utils::checkWiFi();
if (!espClient.connected()) {
APRS_IS_Utils::connect();
}
APRS_IS_Utils::loop();
} else if (stationMode==3 || stationMode==4) { // DigiRepeater (3 RxFreq=TxFreq / 4 RxFreq!=TxFreq)
DIGI_Utils::loop();
} else if (stationMode==5) { // iGate when WiFi and APRS available , DigiRepeater when not (RxFreq=TxFreq)
Utils::checkWiFiInterval();
thirdLine = Utils::getLocalIP();
if (WiFi.status() == WL_CONNECTED) { // iGate Mode
if (!espClient.connected()) {
APRS_IS_Utils::connect();
}
if (lastStationModeState == 1) {
iGateBeaconPacket = GPS_Utils::generateBeacon();
lastStationModeState = 0;
}
APRS_IS_Utils::loop();
} else { // DigiRepeater Mode
DIGI_Utils::loop();
}
if (isUpdatingOTA) {
ElegantOTA.loop();
return; // Don't process IGate and Digi during OTA update
}
thirdLine = Utils::getLocalIP();
WIFI_Utils::checkWiFi(); // Always use WiFi, not related to IGate/Digi mode
// Utils::checkWiFiInterval();
if (Config.aprs_is.active && !espClient.connected()) {
APRS_IS_Utils::connect();
}
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
String packet;
if (Config.loramodule.rxActive) {
packet = LoRa_Utils::receivePacket(); // We need to fetch LoRa packet above APRSIS and Digi
}
APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func?
if (Config.aprs_is.active) { // If APRSIS enabled
APRS_IS_Utils::loop(packet); // Send received packet to APRSIS
}
if (Config.digi.mode == 2) { // If Digi enabled
DIGI_Utils::loop(packet); // Send received packet to Digi
}
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
}

View file

@ -1,4 +1,3 @@
#include <ElegantOTA.h>
#include <WiFi.h>
#include "configuration.h"
#include "aprs_is_utils.h"
@ -14,7 +13,6 @@ extern Configuration Config;
extern WiFiClient espClient;
extern int internalLedPin;
extern uint32_t lastScreenOn;
extern int stationMode;
extern String firstLine;
extern String secondLine;
extern String thirdLine;
@ -48,7 +46,10 @@ namespace APRS_IS_Utils {
Serial.println("Tried: " + String(count) + " FAILED!");
} else {
Serial.println("Connected!\n(Server: " + String(Config.aprs_is.server) + " / Port: " + String(Config.aprs_is.port) +")");
aprsauth = "user " + Config.callsign + " pass " + Config.aprs_is.passcode + " vers CA2RXU_LoRa_iGate 1.3 filter t/m/" + Config.callsign + "/" + (String)Config.aprs_is.reportingDistance;// + "\r\n";
// String filter = "t/m/" + Config.callsign + "/" + (String)Config.aprs_is.reportingDistance;
aprsauth = "user " + Config.callsign + " pass " + Config.aprs_is.passcode + " vers CA2RXU_LoRa_iGate 1.3 filter " + Config.aprs_is.filter;// + "\r\n";
upload(aprsauth);
delay(200);
}
@ -60,25 +61,33 @@ namespace APRS_IS_Utils {
wifiState = "OK";
} else {
wifiState = "AP";
if (!Config.display.alwaysOn) {
display_toggle(true);
}
lastScreenOn = millis();
}
if (espClient.connected()) {
if (!Config.aprs_is.active) {
aprsisState = "OFF";
} else if (espClient.connected()) {
aprsisState = "OK";
} else {
aprsisState = "--";
if (!Config.display.alwaysOn) {
display_toggle(true);
}
lastScreenOn = millis();
}
secondLine = "WiFi: " + wifiState + " APRS-IS: " + aprsisState;
secondLine = "WiFi: " + wifiState + " APRS-IS: " + aprsisState;
}
String createPacket(String packet) {
if (stationMode>1) {
if (!(Config.aprs_is.active && Config.digi.mode == 0)) { // Check if NOT only IGate
return packet.substring(3, packet.indexOf(":")) + ",qAR," + Config.callsign + packet.substring(packet.indexOf(":"));// + "\n";
} else {
return packet.substring(3, packet.indexOf(":")) + ",qAO," + Config.callsign + packet.substring(packet.indexOf(":"));// + "\n";
@ -103,14 +112,6 @@ namespace APRS_IS_Utils {
AddresseeAndMessage = packet.substring(packet.indexOf("::")+2);
Addressee = AddresseeAndMessage.substring(0,AddresseeAndMessage.indexOf(":"));
Addressee.trim();
if (stationMode!=1 && Config.igateRepeatsLoRaPackets && Addressee != Config.callsign) { // if its not for me
String digiRepeatedPacket = DIGI_Utils::generateDigiRepeatedPacket(packet.substring(3), Config.callsign);
if (digiRepeatedPacket != "X") {
delay(500);
LoRa_Utils::sendNewPacket("APRS", digiRepeatedPacket);
}
}
if (packet.indexOf("::") > 10 && Addressee == Config.callsign) { // its a message for me!
if (AddresseeAndMessage.indexOf("{")>0) { // ack?
@ -208,7 +209,8 @@ namespace APRS_IS_Utils {
#ifndef TextSerialOutputForApp
Serial.print("Received from APRS-IS : " + packet);
#endif
if ((stationMode==2 || stationMode==5) && STATION_Utils::wasHeard(Addressee)) {
if (Config.aprs_is.toRF && STATION_Utils::wasHeard(Addressee)) {
LoRa_Utils::sendNewPacket("APRS", LoRa_Utils::generatePacket(packet));
display_toggle(true);
lastScreenOn = millis();
@ -220,19 +222,17 @@ namespace APRS_IS_Utils {
}
}
void loop() {
checkStatus();
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
while (espClient.connected()) {
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
processLoRaPacket(LoRa_Utils::receivePacket());
void loop(String packet) {
if (espClient.connected()) {
processLoRaPacket(packet);
if (espClient.available()) {
String aprsisPacket;
aprsisPacket.concat(espClient.readStringUntil('\r'));
String aprsisPacket = espClient.readStringUntil('\r');
// Serial.println(aprsisPacket);
processAPRSISPacket(aprsisPacket);
}
ElegantOTA.loop();
}
}

View file

@ -19,7 +19,7 @@ namespace APRS_IS_Utils {
String createPacket(String unprocessedPacket);
void processLoRaPacket(String packet);
void processAPRSISPacket(String packet);
void loop();
void loop(String packet);
}

View file

@ -3,6 +3,15 @@
#include "configuration.h"
#include "display.h"
void Configuration::check() {
if (reload) {
show_display("------- UPDATE ------", "config is old", "device will update", "and then reboot", 1000);
writeFile();
ESP.restart();
}
}
void Configuration::writeFile() {
Serial.println("Saving config..");
@ -14,8 +23,8 @@ void Configuration::writeFile() {
for (int i = 0; i < wifiAPs.size(); i++) {
data["wifi"]["AP"][i]["ssid"] = wifiAPs[i].ssid;
data["wifi"]["AP"][i]["password"] = wifiAPs[i].password;
data["wifi"]["AP"][i]["latitude"] = wifiAPs[i].latitude;
data["wifi"]["AP"][i]["longitude"] = wifiAPs[i].longitude;
// data["wifi"]["AP"][i]["latitude"] = wifiAPs[i].latitude;
// data["wifi"]["AP"][i]["longitude"] = wifiAPs[i].longitude;
}
}
@ -23,33 +32,52 @@ void Configuration::writeFile() {
data["wifi"]["autoAP"]["powerOff"] = wifiAutoAP.powerOff;
data["callsign"] = callsign;
data["stationMode"] = stationMode;
data["iGateComment"] = iGateComment;
// data["stationMode"] = stationMode; // only check for config version
// data["iGateComment"] = iGateComment;
data["other"]["beaconInterval"] = beaconInterval;
data["other"]["igateSendsLoRaBeacons"] = igateSendsLoRaBeacons;
data["other"]["igateRepeatsLoRaPackets"] = igateRepeatsLoRaPackets;
// data["other"]["beaconInterval"] = beaconInterval;
// data["other"]["igateSendsLoRaBeacons"] = igateSendsLoRaBeacons;
// data["other"]["igateRepeatsLoRaPackets"] = igateRepeatsLoRaPackets;
data["other"]["rememberStationTime"] = rememberStationTime;
data["other"]["sendBatteryVoltage"] = sendBatteryVoltage;
data["other"]["externalVoltageMeasurement"] = externalVoltageMeasurement;
data["other"]["externalVoltagePin"] = externalVoltagePin;
data["digi"]["comment"] = digi.comment;
data["digi"]["latitude"] = digi.latitude;
data["digi"]["longitude"] = digi.longitude;
data["digi"]["mode"] = digi.mode;
// data["digi"]["comment"] = digi.comment;
// data["digi"]["latitude"] = digi.latitude;
// data["digi"]["longitude"] = digi.longitude;
data["aprs_is"]["active"] = aprs_is.active;
data["aprs_is"]["passcode"] = aprs_is.passcode;
data["aprs_is"]["server"] = aprs_is.server;
data["aprs_is"]["port"] = aprs_is.port;
data["aprs_is"]["reportingDistance"] = aprs_is.reportingDistance;
data["aprs_is"]["filter"] = aprs_is.filter;
data["aprs_is"]["toRF"] = aprs_is.toRF;
data["lora"]["iGateFreq"] = loramodule.iGateFreq;
data["lora"]["digirepeaterTxFreq"] = loramodule.digirepeaterTxFreq;
data["lora"]["digirepeaterRxFreq"] = loramodule.digirepeaterRxFreq;
data["beacon"]["comment"] = beacon.comment;
// data["beacon"]["igateRepeatsLoRaPackets"] = beacon.igateRepeatsLoRaPackets;
// data["beacon"]["igateSendsLoRaBeacons"] = beacon.igateSendsLoRaBeacons;
data["beacon"]["interval"] = beacon.interval;
data["beacon"]["latitude"] = beacon.latitude;
data["beacon"]["longitude"] = beacon.longitude;
data["beacon"]["overlay"] = beacon.overlay;
data["beacon"]["symbol"] = beacon.symbol;
data["beacon"]["sendViaAPRSIS"] = beacon.sendViaAPRSIS;
data["beacon"]["sendViaRF"] = beacon.sendViaRF;
data["beacon"]["path"] = beacon.path;
// data["lora"]["iGateFreq"] = loramodule.iGateFreq;
// data["lora"]["digirepeaterTxFreq"] = loramodule.digirepeaterTxFreq;
// data["lora"]["digirepeaterRxFreq"] = loramodule.digirepeaterRxFreq;
data["lora"]["rxFreq"] = loramodule.rxFreq;
data["lora"]["txFreq"] = loramodule.txFreq;
data["lora"]["spreadingFactor"] = loramodule.spreadingFactor;
data["lora"]["signalBandwidth"] = loramodule.signalBandwidth;
data["lora"]["codingRate4"] = loramodule.codingRate4;
data["lora"]["power"] = loramodule.power;
data["lora"]["txActive"] = loramodule.txActive;
data["lora"]["rxActive"] = loramodule.rxActive;
data["display"]["alwaysOn"] = display.alwaysOn;
data["display"]["timeout"] = display.timeout;
@ -63,7 +91,7 @@ void Configuration::writeFile() {
data["ota"]["username"] = ota.username;
data["ota"]["password"] = ota.password;
serializeJson(data, configFile);
configFile.close();
@ -89,8 +117,6 @@ bool Configuration::readFile() {
WiFi_AP wifiap;
wifiap.ssid = WiFiArray[i]["ssid"].as<String>();
wifiap.password = WiFiArray[i]["password"].as<String>();
wifiap.latitude = WiFiArray[i]["latitude"].as<double>();
wifiap.longitude = WiFiArray[i]["longitude"].as<double>();
wifiAPs.push_back(wifiap);
}
@ -99,28 +125,15 @@ bool Configuration::readFile() {
wifiAutoAP.powerOff = data["wifi"]["autoAP"]["powerOff"].as<int>();
callsign = data["callsign"].as<String>();
stationMode = data["stationMode"].as<int>();
iGateComment = data["iGateComment"].as<String>();
beaconInterval = data["other"]["beaconInterval"].as<int>();
igateSendsLoRaBeacons = data["other"]["igateSendsLoRaBeacons"].as<bool>();
igateRepeatsLoRaPackets = data["other"]["igateRepeatsLoRaPackets"].as<bool>();
rememberStationTime = data["other"]["rememberStationTime"].as<int>();
sendBatteryVoltage = data["other"]["sendBatteryVoltage"].as<bool>();
externalVoltageMeasurement = data["other"]["externalVoltageMeasurement"].as<bool>();
externalVoltagePin = data["other"]["externalVoltagePin"].as<int>();
digi.comment = data["digi"]["comment"].as<String>();
digi.latitude = data["digi"]["latitude"].as<double>();
digi.longitude = data["digi"]["longitude"].as<double>();
aprs_is.passcode = data["aprs_is"]["passcode"].as<String>();
aprs_is.server = data["aprs_is"]["server"].as<String>();
aprs_is.port = data["aprs_is"]["port"].as<int>();
aprs_is.reportingDistance = data["aprs_is"]["reportingDistance"].as<int>();
loramodule.iGateFreq = data["lora"]["iGateFreq"].as<long>();
loramodule.digirepeaterTxFreq = data["lora"]["digirepeaterTxFreq"].as<long>();
loramodule.digirepeaterRxFreq = data["lora"]["digirepeaterRxFreq"].as<long>();
loramodule.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
loramodule.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
loramodule.codingRate4 = data["lora"]["codingRate4"].as<int>();
@ -139,12 +152,87 @@ bool Configuration::readFile() {
ota.username = data["ota"]["username"].as<String>();
ota.password = data["ota"]["password"].as<String>();
int stationMode = data["stationMode"].as<int>(); // deprecated but need to specify config version
if (stationMode == 0) {
// Load new settings
beacon.latitude = data["beacon"]["latitude"].as<double>();
beacon.longitude = data["beacon"]["longitude"].as<double>();
beacon.comment = data["beacon"]["comment"].as<String>();
beacon.overlay = data["beacon"]["overlay"].as<String>();
beacon.symbol = data["beacon"]["symbol"].as<String>();
beacon.interval = data["beacon"]["interval"].as<int>();
// beacon.igateSendsLoRaBeacons = data["beacon"]["igateSendsLoRaBeacons"].as<bool>();
// beacon.igateRepeatsLoRaPackets = data["beacon"]["igateRepeatsLoRaPackets"].as<bool>();
beacon.sendViaAPRSIS = data["beacon"]["sendViaAPRSIS"].as<bool>();
beacon.sendViaRF = data["beacon"]["sendViaRF"].as<bool>();
beacon.path = data["beacon"]["path"].as<String>();
digi.mode = data["digi"]["mode"].as<int>();
aprs_is.active = data["aprs_is"]["active"].as<bool>();
aprs_is.filter = data["aprs_is"]["filter"].as<String>();
aprs_is.toRF = data["aprs_is"]["toRF"].as<bool>();
loramodule.txFreq = data["lora"]["txFreq"].as<long>();
loramodule.rxFreq = data["lora"]["rxFreq"].as<long>();
loramodule.txActive = data["lora"]["txActive"].as<bool>();
loramodule.rxActive = data["lora"]["rxActive"].as<bool>();
} else {
// Load old settings and put into new variables not actual config
String iGateComment = data["iGateComment"].as<String>();
int beaconInterval = data["other"]["beaconInterval"].as<int>();
// bool igateSendsLoRaBeacons = data["other"]["igateSendsLoRaBeacons"].as<bool>();
// bool igateRepeatsLoRaPackets = data["other"]["igateRepeatsLoRaPackets"].as<bool>();
long iGateFreq = data["lora"]["iGateFreq"].as<long>();
long digirepeaterTxFreq = data["lora"]["digirepeaterTxFreq"].as<long>();
long digirepeaterRxFreq = data["lora"]["digirepeaterRxFreq"].as<long>();
String digiComment = data["digi"]["comment"].as<String>();
double digiLatitude = data["digi"]["latitude"].as<double>();
double digiLongitude = data["digi"]["longitude"].as<double>();
beacon.latitude = digiLatitude;
beacon.longitude = digiLongitude;
beacon.interval = beaconInterval;
// beacon.igateSendsLoRaBeacons = igateSendsLoRaBeacons;
// beacon.igateRepeatsLoRaPackets = igateRepeatsLoRaPackets;
loramodule.txFreq = digirepeaterTxFreq;
loramodule.rxFreq = digirepeaterRxFreq;
loramodule.rxActive = true;
beacon.sendViaAPRSIS = true;
beacon.sendViaRF = false;
switch (stationMode) {
case 1: // IGate only
// aprs_is.active = true; // better don't do that automatically
beacon.comment = iGateComment;
loramodule.rxFreq = iGateFreq;
break;
case 5: // Digi + IGate
case 2: // Digi + IGate
// aprs_is.active = true; // better don't do that automatically
// digi.mode = 2; // better don't do that automatically
beacon.comment = digiComment;
loramodule.rxFreq = iGateFreq;
break;
case 3: // Digi
case 4: // Digi
// digi.mode = 2; // better don't do that automatically
beacon.comment = digiComment;
break;
}
reload = true;
}
if (wifiAPs.size() == 0) { // If we don't have any WiFi's from config we need to add "empty" SSID for AUTO AP
WiFi_AP wifiap;
wifiap.ssid = "";
wifiap.password = "";
wifiap.latitude = 0.0;
wifiap.longitude = 0.0;
wifiAPs.push_back(wifiap);
}
@ -158,36 +246,57 @@ bool Configuration::readFile() {
}
void Configuration::init() {
reload = false;
WiFi_AP wifiap;
wifiap.ssid = "";
wifiap.password = "";
wifiap.latitude = 0.0;
wifiap.longitude = 0.0;
// wifiap.latitude = 0.0; // deprecated
// wifiap.longitude = 0.0; // deprecated
wifiAPs.push_back(wifiap);
wifiAutoAP.password = "1234567890";
wifiAutoAP.powerOff = 15;
callsign = "N0CALL";
stationMode = 1;
iGateComment = "LoRa_APRS_iGate Development";
// stationMode = 1; // deprecated
// iGateComment = "LoRa_APRS_iGate Development"; // deprecated
digi.comment = "LoRa_APRS_iGate Development";
digi.latitude = 0.0;
digi.longitude = 0.0;
beacon.comment = "LoRa APRS"; // new
beacon.latitude = 0.0; // new
beacon.longitude = 0.0; // new
beacon.interval = 15; // new
// beacon.igateRepeatsLoRaPackets = false; // new
// beacon.igateSendsLoRaBeacons = false; // new
beacon.overlay = "L"; // new
beacon.symbol = "#"; // new
beacon.sendViaAPRSIS = true; // new
beacon.sendViaRF = false; // new
beacon.path = "WIDE1-1"; // new
digi.mode = 0; // new
// digi.comment = "LoRa_APRS_iGate Development"; // deprecated
// digi.latitude = 0.0; // deprecated
// digi.longitude = 0.0; // deprecated
aprs_is.active = false; // new
aprs_is.passcode = "XYZVW";
aprs_is.server = "rotate.aprs2.net";
aprs_is.port = 14580;
aprs_is.reportingDistance = 30;
aprs_is.filter = ""; // new
aprs_is.toRF = false; // new
loramodule.iGateFreq = 433775000;
loramodule.digirepeaterTxFreq = 433775000;
loramodule.digirepeaterRxFreq = 433900000;
// loramodule.iGateFreq = 433775000; // deprecated
// loramodule.digirepeaterTxFreq = 433775000; // deprecated
// loramodule.digirepeaterRxFreq = 433900000; // deprecated
loramodule.txFreq = 433775000; // new
loramodule.rxFreq = 433775000; // new
loramodule.spreadingFactor = 12;
loramodule.signalBandwidth = 125000;
loramodule.codingRate4 = 5;
loramodule.power = 20;
loramodule.txActive = false; // new
loramodule.rxActive = true; // new
display.alwaysOn = true;
display.timeout = 4;
@ -202,9 +311,9 @@ void Configuration::init() {
ota.username = "";
ota.password = "";
beaconInterval = 15;
igateSendsLoRaBeacons = false;
igateRepeatsLoRaPackets = false;
// beaconInterval = 15; // deprecated
// igateSendsLoRaBeacons = false; // deprecated
// igateRepeatsLoRaPackets = false; // deprecated
rememberStationTime = 30;
sendBatteryVoltage = false;
externalVoltageMeasurement = false;
@ -218,13 +327,15 @@ Configuration::Configuration() {
Serial.println("SPIFFS Mount Failed");
return;
} else {
Serial.println("montado");
Serial.println("SPIFFS Mounted");
}
bool exists = SPIFFS.exists("/igate_conf.json");
if (!exists) {
init();
writeFile();
ESP.restart();
}
readFile();
}

View file

@ -9,8 +9,8 @@ class WiFi_AP {
public:
String ssid;
String password;
double latitude;
double longitude;
// double latitude; // deprecated
// double longitude; // deprecated
};
class WiFi_Auto_AP {
@ -19,27 +19,47 @@ public:
int powerOff;
};
class Beacon {
public:
double latitude; // new
double longitude; // new
String comment; // new
String overlay; // new
String symbol; // new
int interval; // new
bool sendViaRF; // new
bool sendViaAPRSIS; // new
String path; // new
};
class DIGI {
public:
String comment;
double latitude;
double longitude;
int mode; // new
// String comment; // deprecated
// double latitude; // deprecated
// double longitude; // deprecated
};
class APRS_IS {
public:
bool active; // new
String passcode;
String server;
int port;
int reportingDistance;
// int reportingDistance; // deprecated
String filter; // new
bool toRF; // new
};
class LoraModule {
public:
long iGateFreq;
long digirepeaterTxFreq;
long digirepeaterRxFreq;
// long iGateFreq; // deprecated
// long digirepeaterTxFreq; // deprecated
// long digirepeaterRxFreq; // deprecated
long txFreq; // new
long rxFreq; // new
bool txActive; // new
bool rxActive; // new
int spreadingFactor;
long signalBandwidth;
int codingRate4;
@ -76,18 +96,20 @@ public:
class Configuration {
public:
bool reload;
String callsign;
int stationMode;
String iGateComment;
int beaconInterval;
bool igateSendsLoRaBeacons;
bool igateRepeatsLoRaPackets;
// int stationMode; // deprecated
// String iGateComment; // deprecated
// int beaconInterval; // deprecated
// bool igateSendsLoRaBeacons; // deprecated
// bool igateRepeatsLoRaPackets; // deprecated
int rememberStationTime;
bool sendBatteryVoltage;
bool externalVoltageMeasurement;
int externalVoltagePin;
std::vector<WiFi_AP> wifiAPs;
WiFi_Auto_AP wifiAutoAP;
Beacon beacon; // new
DIGI digi;
APRS_IS aprs_is;
LoraModule loramodule;
@ -98,6 +120,7 @@ public:
void init();
void writeFile();
void check();
Configuration();
private:

View file

@ -10,9 +10,7 @@
#include "utils.h"
extern Configuration Config;
extern int stationMode;
extern uint32_t lastScreenOn;
extern int lastStationModeState;
extern String iGateBeaconPacket;
extern String firstLine;
extern String secondLine;
@ -43,13 +41,13 @@ namespace DIGI_Utils {
String repeatedPacket = sender + ">" + tocall + "," + path + packet.substring(packet.indexOf(":"));
return repeatedPacket;
} else {
return "X";
return "";
}
} else {
return "X";
return "";
}
} else {
return "X";
return "";
}
}
@ -62,32 +60,16 @@ namespace DIGI_Utils {
String sender = packet.substring(3,packet.indexOf(">"));
STATION_Utils::updateLastHeard(sender);
STATION_Utils::updatePacketBuffer(packet);
Utils::typeOfPacket(packet, "Digi");
if ((stationMode==3 || stationMode==5) && (packet.indexOf("WIDE1-") > 10)) {
Utils::typeOfPacket(packet.substring(3), "Digi");
if (packet.indexOf("WIDE1-") > 10 && Config.digi.mode == 2) { // If should repeat packet (WIDE1 Digi)
loraPacket = generateDigiRepeatedPacket(packet.substring(3), Config.callsign);
if (loraPacket != "X") {
if (loraPacket != "") {
delay(500);
Serial.println(loraPacket);
LoRa_Utils::sendNewPacket("APRS", loraPacket);
display_toggle(true);
lastScreenOn = millis();
}
} else if (stationMode==4){
if (packet.indexOf("WIDE1-") == -1) {
loraPacket = packet.substring(3,packet.indexOf(":")) + "," + Config.callsign + "*" + packet.substring(packet.indexOf(":"));
} else {
loraPacket = packet.substring(3,packet.indexOf(",")+1) + Config.callsign + "*" + packet.substring(packet.indexOf(","));
}
delay(500);
if (stationMode==4) {
LoRa_Utils::changeFreqTx();
}
LoRa_Utils::sendNewPacket("APRS", loraPacket);
if (stationMode==4) {
LoRa_Utils::changeFreqRx();
}
display_toggle(true);
lastScreenOn = millis();
}
} else {
Serial.println(" ---> LoRa Packet Ignored (first 3 bytes or NOGATE)\n");
@ -95,21 +77,8 @@ namespace DIGI_Utils {
}
}
void loop() {
if (stationMode==3 || stationMode==4 || stationMode==5) {
if (lastStationModeState==0 && stationMode==5) {
iGateBeaconPacket = GPS_Utils::generateBeacon();
lastStationModeState = 1;
String Tx = String(Config.loramodule.digirepeaterTxFreq);
secondLine = "Rx:" + String(Tx.substring(0,3)) + "." + String(Tx.substring(3,6));
secondLine += " Tx:" + String(Tx.substring(0,3)) + "." + String(Tx.substring(3,6));
thirdLine = "<< DigiRepeater >>";
}
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
processPacket(LoRa_Utils::receivePacket());
}
void loop(String packet) {
processPacket(packet);
}
}

View file

@ -8,7 +8,7 @@ namespace DIGI_Utils {
String generateDigiRepeatedPacket(String packet, String callsign);
void processPacket(String packet);
void loop();
void loop(String packet);
}

View file

@ -4,9 +4,7 @@
#include "gps_utils.h"
extern Configuration Config;
extern WiFi_AP *currentWiFi;
extern WiFiClient espClient;
extern int stationMode;
String distance;
@ -80,49 +78,32 @@ namespace GPS_Utils {
}
String generateBeacon() {
String stationLatitude, stationLongitude, beaconPacket;
if (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status()==WL_CONNECTED && espClient.connected())) {
stationLatitude = processLatitudeAPRS(currentWiFi->latitude);
stationLongitude = processLongitudeAPRS(currentWiFi->longitude);
beaconPacket = Config.callsign + ">APLRG1,WIDE1-1";
if (stationMode!=6) {
beaconPacket += ",qAC";
}
beaconPacket += ":=" + stationLatitude + "L" + stationLongitude;
if (stationMode==1) {
beaconPacket += "&";
} else {
beaconPacket += "a";
}
beaconPacket += Config.iGateComment;
} else { //stationMode 3, 4 and 5
if (stationMode==5) {
stationLatitude = processLatitudeAPRS(currentWiFi->latitude);
stationLongitude = processLongitudeAPRS(currentWiFi->longitude);
} else {
stationLatitude = processLatitudeAPRS(Config.digi.latitude);
stationLongitude = processLongitudeAPRS(Config.digi.longitude);
}
beaconPacket = Config.callsign + ">APLRG1,WIDE1-1:=" + stationLatitude + "L" + stationLongitude + "#" + Config.digi.comment;
}
String stationLatitude = processLatitudeAPRS(Config.beacon.latitude);
String stationLongitude = processLongitudeAPRS(Config.beacon.longitude);
String beaconPacket = Config.callsign + ">APLRG1," + Config.beacon.path;
if (Config.aprs_is.active && Config.digi.mode == 0) { // If APRSIS enabled and Digi disabled
beaconPacket += ",qAC";
} else {}
beaconPacket += ":=" + stationLatitude + Config.beacon.overlay + stationLongitude + Config.beacon.symbol;
beaconPacket += Config.beacon.comment;
return beaconPacket;
}
String generateiGateLoRaBeacon() {
String stationLatitude, stationLongitude, beaconPacket;
stationLatitude = processLatitudeAPRS(currentWiFi->latitude);
stationLongitude = processLongitudeAPRS(currentWiFi->longitude);
beaconPacket = Config.callsign + ">APLRG1,RFONLY:=" + stationLatitude + "L" + stationLongitude;
if (Config.bme.active) {
beaconPacket += "_";
} else {
beaconPacket += "a";
}
String stationLatitude = processLatitudeAPRS(Config.beacon.latitude);
String stationLongitude = processLongitudeAPRS(Config.beacon.longitude);
String beaconPacket = Config.callsign + ">APLRG1," + Config.beacon.path + ":=" + stationLatitude + Config.beacon.overlay + stationLongitude + Config.beacon.symbol;
return beaconPacket;
}
double calculateDistanceTo(double latitude, double longitude) {
return TinyGPSPlus::distanceBetween(currentWiFi->latitude,currentWiFi->longitude, latitude, longitude) / 1000.0;
return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0;
}
String decodeEncodedGPS(String packet) {

View file

@ -8,7 +8,6 @@
#include "display.h"
extern Configuration Config;
extern int stationMode;
#if defined(HELTEC_V3) || defined(TTGO_T_Beam_V1_2_SX1262)
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
@ -37,12 +36,7 @@ namespace LoRa_Utils {
#ifdef HAS_SX127X
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ);
long freq;
if (stationMode==1 || stationMode==2) {
freq = Config.loramodule.iGateFreq;
} else {
freq = Config.loramodule.digirepeaterTxFreq;
}
long freq = Config.loramodule.rxFreq;
if (!LoRa.begin(freq)) {
Serial.println("Starting LoRa failed!");
show_display("ERROR", "Starting LoRa failed!");
@ -59,7 +53,7 @@ namespace LoRa_Utils {
#endif
#ifdef HAS_SX126X
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
float freq = (float)Config.loramodule.iGateFreq/1000000;
float freq = (float)Config.loramodule.rxFreq/1000000;
int state = radio.begin(freq);
if (state == RADIOLIB_ERR_NONE) {
Serial.print("Initializing SX126X LoRa Module");
@ -90,7 +84,35 @@ namespace LoRa_Utils {
#endif
}
void changeFreqTx() {
delay(500);
#ifdef HAS_SX127X
LoRa.setFrequency(Config.loramodule.txFreq);
#endif
#ifdef HAS_SX126X
float freq = (float)Config.loramodule.txFreq/1000000;
radio.setFrequency(freq);
#endif
}
void changeFreqRx() {
delay(500);
#ifdef HAS_SX127X
LoRa.setFrequency(Config.loramodule.rxFreq);
#endif
#ifdef HAS_SX126X
float freq = (float)Config.loramodule.rxFreq/1000000;
radio.setFrequency(freq);
#endif
}
void sendNewPacket(const String &typeOfMessage, const String &newPacket) {
if (!Config.loramodule.txActive) return;
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
changeFreqTx();
}
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(HELTEC_V3) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
digitalWrite(internalLedPin,HIGH);
#endif
@ -125,6 +147,10 @@ namespace LoRa_Utils {
SYSLOG_Utils::log("Tx", newPacket,0,0,0);
Serial.print("---> LoRa Packet Tx : ");
Serial.println(newPacket);
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
changeFreqRx();
}
}
String generatePacket(String aprsisPacket) {
@ -194,32 +220,10 @@ namespace LoRa_Utils {
}
#endif
if (Config.syslog.active && (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status()==WL_CONNECTED)) && loraPacket!="") {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED && loraPacket != "") {
SYSLOG_Utils::log("Rx", loraPacket, rssi, snr, freqError);
}
return loraPacket;
}
void changeFreqTx() {
delay(500);
#ifdef HAS_SX127X
LoRa.setFrequency(Config.loramodule.digirepeaterTxFreq);
#endif
#ifdef HAS_SX126X
float freq = (float)Config.loramodule.digirepeaterTxFreq/1000000;
radio.setFrequency(freq);
#endif
}
void changeFreqRx() {
delay(500);
#ifdef HAS_SX127X
LoRa.setFrequency(Config.loramodule.digirepeaterRxFreq);
#endif
#ifdef HAS_SX126X
float freq = (float)Config.loramodule.digirepeaterRxFreq/1000000;
radio.setFrequency(freq);
#endif
}
}

View file

@ -7,6 +7,7 @@
extern Configuration Config;
extern uint32_t lastScreenOn;
extern bool isUpdatingOTA;
unsigned long ota_progress_millis = 0;
@ -31,6 +32,7 @@ namespace OTA_Utils {
display_toggle(true);
lastScreenOn = millis();
show_display("", "", "", " OTA update started!", "", "", "", 1000);
isUpdatingOTA = true;
}
void onOTAProgress(size_t current, size_t final) {
@ -53,6 +55,7 @@ namespace OTA_Utils {
Serial.println("There was an error during OTA update!");
show_display("", "", " OTA update fail!", "", "", "", "", 4000);
}
isUpdatingOTA = false;
}
}

View file

@ -127,14 +127,4 @@ namespace POWER_Utils {
#endif
}
/*void lowerCpuFrequency() {
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2) || defined(ESP32_DIY_LoRa_GPS) || defined(TTGO_T_LORA32_V2_1_GPS) || defined(TTGO_T_LORA32_V2_1_TNC) || defined(ESP32_DIY_1W_LoRa_GPS) || defined(TTGO_T_Beam_V1_2_SX1262)
if (setCpuFrequencyMhz(80)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "CPU frequency set to 80MHz");
} else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "Main", "CPU frequency unchanged");
}
#endif
}*/
}

View file

@ -12,7 +12,6 @@ namespace POWER_Utils {
void deactivateLoRa();
bool begin(TwoWire &port);
void setup();
//void lowerCpuFrequency();
}

View file

@ -2,11 +2,9 @@
#include "query_utils.h"
extern Configuration Config;
extern WiFi_AP *currentWiFi;
extern std::vector<String> lastHeardStation;
extern std::vector<String> lastHeardStation_temp;
extern String versionDate;
extern int stationMode;
namespace QUERY_Utils {
@ -16,9 +14,9 @@ namespace QUERY_Utils {
if (query=="?APRS?" || query=="?aprs?" || query=="?Aprs?" || query=="H" || query=="h" || query=="HELP" || query=="Help" || query=="help" || query=="?") {
answer = "?APRSV ?APRSP ?APRSL ?APRSH ?WHERE callsign";
} else if (query=="?APRSV" || query=="?aprsv" || query=="?Aprsv") {
answer = "CA2RXU_LoRa_iGate 1.3 v" + versionDate + " sM" + String(stationMode);
answer = "CA2RXU_LoRa_iGate 1.3 v" + versionDate;
} else if (query=="?APRSP" || query=="?aprsp" || query=="?Aprsp") {
answer = "iGate QTH: " + String(currentWiFi->latitude,2) + " " + String(currentWiFi->longitude,2);
answer = "iGate QTH: " + String(Config.beacon.latitude,2) + " " + String(Config.beacon.longitude,2);
} else if (query=="?APRSL" || query=="?aprsl" || query=="?Aprsl") {
if (lastHeardStation.size() == 0) {
answer = "No Station Listened in the last " + String(Config.rememberStationTime) + "min.";

View file

@ -5,7 +5,6 @@
#include "gps_utils.h"
extern Configuration Config;
extern int stationMode;
WiFiUDP udpClient;
@ -14,7 +13,7 @@ namespace SYSLOG_Utils {
void log(String type, String packet, int rssi, float snr, int freqError) {
String syslogPacket = "<165>1 - " + Config.callsign + " CA2RXU_LoRa_iGate_1.2" + " - - - "; //RFC5424 The Syslog Protocol
if (Config.syslog.active && (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status()==WL_CONNECTED))) {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
if (type == "APRSIS Tx") {
if (packet.indexOf(":>") > 10) {
syslogPacket += type + " / StartUp_Status / " + packet.substring(packet.indexOf(":>")+2);
@ -67,7 +66,7 @@ namespace SYSLOG_Utils {
}
void setup() {
if (Config.syslog.active && (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status()==WL_CONNECTED))) {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
udpClient.begin(WiFi.localIP(), 0);
Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")");
}

View file

@ -26,7 +26,6 @@ extern String seventhLine;
extern uint32_t lastBeaconTx;
extern uint32_t lastScreenOn;
extern bool beaconUpdate;
extern int stationMode;
extern String iGateBeaconPacket;
extern String iGateLoRaBeaconPacket;
extern std::vector<String> lastHeardStation;
@ -42,23 +41,21 @@ extern bool WiFiConnected;
namespace Utils {
void processStatus() {
String status = Config.callsign + ">APLRG1,WIDE1-1";
if (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status() == WL_CONNECTED)) {
String status = Config.callsign + ">APLRG1," + Config.beacon.path;
if (Config.aprs_is.active && Config.digi.mode == 0) { // If only IGate
delay(1000);
status += ",qAC:>https://github.com/richonguzman/LoRa_APRS_iGate " + versionDate;
APRS_IS_Utils::upload(status);
SYSLOG_Utils::log("APRSIS Tx", status,0,0,0);
} else {
delay(5000);
status += ":>https://github.com/richonguzman/LoRa_APRS_iGate " + versionDate;
if (stationMode==4) {
LoRa_Utils::changeFreqTx();
}
LoRa_Utils::sendNewPacket("APRS", status);
if (stationMode==4) {
LoRa_Utils::changeFreqRx();
}
}
// Comment this for now we will need this in the future
// } else if (Config.digi.mode == 2) {
// delay(5000);
// status += ":>https://github.com/richonguzman/LoRa_APRS_iGate " + versionDate;
// LoRa_Utils::sendNewPacket("APRS", status);
// }
statusAfterBoot = false;
}
@ -95,125 +92,60 @@ namespace Utils {
void checkBeaconInterval() {
uint32_t lastTx = millis() - lastBeaconTx;
String beaconPacket, secondaryBeaconPacket;
if (lastTx >= Config.beaconInterval*60*1000) {
if (lastTx >= Config.beacon.interval*60*1000) {
beaconUpdate = true;
}
if (beaconUpdate) {
display_toggle(true);
Serial.println("---- Sending iGate Beacon ----");
Serial.println("-- Sending Beacon to APRSIS --");
STATION_Utils::deleteNotHeard();
activeStations();
if (Config.bme.active) {
String sensorData = BME_Utils::readDataSensor();
beaconPacket = iGateBeaconPacket.substring(0,iGateBeaconPacket.indexOf(":=")+20) + "_" + sensorData + iGateBeaconPacket.substring(iGateBeaconPacket.indexOf(":=")+21) + " + WX";
if (Config.igateSendsLoRaBeacons && stationMode!=1) {
secondaryBeaconPacket = iGateLoRaBeaconPacket + sensorData + Config.iGateComment + " + WX";
}
beaconPacket = iGateBeaconPacket.substring(0,iGateBeaconPacket.indexOf(":=")+20) + "_" + sensorData + iGateBeaconPacket.substring(iGateBeaconPacket.indexOf(":=")+21);
secondaryBeaconPacket = iGateLoRaBeaconPacket + sensorData + Config.beacon.comment;
} else {
beaconPacket = iGateBeaconPacket;
if (Config.igateSendsLoRaBeacons && stationMode!=1) {
secondaryBeaconPacket = iGateLoRaBeaconPacket + Config.iGateComment;
}
secondaryBeaconPacket = iGateLoRaBeaconPacket + Config.beacon.comment;
}
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
if (Config.sendBatteryVoltage) {
beaconPacket += " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
sixthLine = " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
}
#endif
if (Config.externalVoltageMeasurement) {
beaconPacket += " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
sixthLine = " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
}
if (stationMode==1 || stationMode==2) {
thirdLine = getLocalIP();
if (!Config.bme.active) {
fifthLine = "";
}
sixthLine = "";
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING iGate BEACON", 1000);
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
if (Config.sendBatteryVoltage) {
sixthLine = " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
}
#endif
if (Config.externalVoltageMeasurement) {
sixthLine = " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
}
if (Config.aprs_is.active && Config.beacon.sendViaAPRSIS) {
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING IGATE BEACON", 0);
seventhLine = " listening...";
APRS_IS_Utils::upload(beaconPacket);
if (Config.igateSendsLoRaBeacons && stationMode==2) {
LoRa_Utils::sendNewPacket("APRS", secondaryBeaconPacket);
}
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
} else if (stationMode==3 || stationMode==4) {
String Rx = String(Config.loramodule.digirepeaterRxFreq);
String Tx = String(Config.loramodule.digirepeaterTxFreq);
if (stationMode==3) {
secondLine = "Rx:" + String(Tx.substring(0,3)) + "." + String(Tx.substring(3,6));
} else {
secondLine = "Rx:" + String(Rx.substring(0,3)) + "." + String(Rx.substring(3,6));
}
secondLine += " Tx:" + String(Tx.substring(0,3)) + "." + String(Tx.substring(3,6));
thirdLine = "<< DigiRepeater >>";
fifthLine = "";
sixthLine = "";
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING iGate BEACON", 0);
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
if (Config.sendBatteryVoltage) {
sixthLine = " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
}
#endif
if (Config.externalVoltageMeasurement) {
sixthLine = " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
}
seventhLine = " listening...";
if (stationMode==4) {
LoRa_Utils::changeFreqTx();
}
LoRa_Utils::sendNewPacket("APRS", beaconPacket);
if (stationMode==4) {
LoRa_Utils::changeFreqRx();
}
} else if (stationMode==5) {
if (!Config.bme.active) {
fifthLine = "";
}
sixthLine = "";
if (WiFi.status() == WL_CONNECTED && espClient.connected()) {
APRS_IS_Utils::checkStatus();
thirdLine = getLocalIP();
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING iGate BEACON", 1000);
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
if (Config.sendBatteryVoltage) {
sixthLine = " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
}
#endif
if (Config.externalVoltageMeasurement) {
sixthLine = " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
}
seventhLine = " listening...";
APRS_IS_Utils::upload(beaconPacket);
if (Config.igateSendsLoRaBeacons) {
LoRa_Utils::sendNewPacket("APRS", secondaryBeaconPacket);
}
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
} else {
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING iGate BEACON", 0);
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
if (Config.sendBatteryVoltage) {
sixthLine = " (Batt=" + String(BATTERY_Utils::checkBattery(),2) + "V)";
}
#endif
if (Config.externalVoltageMeasurement) {
sixthLine = " (Ext V=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V)";
}
seventhLine = " listening...";
LoRa_Utils::sendNewPacket("APRS", beaconPacket);
}
}
if (Config.beacon.sendViaRF) {
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING DIGI BEACON", 0);
seventhLine = " listening...";
LoRa_Utils::sendNewPacket("APRS", secondaryBeaconPacket);
}
lastBeaconTx = millis();
lastScreenOn = millis();
beaconUpdate = false;
}
if (statusAfterBoot) {
processStatus();
}
@ -241,21 +173,19 @@ namespace Utils {
}
}
void validateDigiFreqs() {
if (stationMode==4) {
if (abs(Config.loramodule.digirepeaterTxFreq - Config.loramodule.digirepeaterRxFreq) < 125000) {
Serial.println("Tx Freq less than 125kHz from Rx Freq ---> NOT VALID");
show_display("Tx Freq is less than ", "125kHz from Rx Freq", "device will autofix", "and then reboot", 1000);
Config.loramodule.digirepeaterTxFreq = Config.loramodule.digirepeaterRxFreq; // Inform about that but then change the digirepeaterTxFreq to digirepeaterRxFreq and reset the device
Config.writeFile();
ESP.restart();
}
void validateFreqs() {
if (Config.loramodule.txFreq != Config.loramodule.rxFreq && abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) < 125000) {
Serial.println("Tx Freq less than 125kHz from Rx Freq ---> NOT VALID");
show_display("Tx Freq is less than ", "125kHz from Rx Freq", "device will autofix", "and then reboot", 1000);
Config.loramodule.txFreq = Config.loramodule.rxFreq; // Inform about that but then change the TX QRG to RX QRG and reset the device
Config.writeFile();
ESP.restart();
}
}
void typeOfPacket(String packet, String packetType) {
String sender;
if (stationMode==1 || stationMode==2 || (stationMode==5 && WiFi.status()==WL_CONNECTED)) {
if (WiFi.status() == WL_CONNECTED) { // If mode 1 2 5
if (packetType == "LoRa-APRS") {
fifthLine = "LoRa Rx ----> APRS-IS";
} else if (packetType == "APRS-LoRa") {

View file

@ -13,7 +13,7 @@ namespace Utils {
void checkBeaconInterval();
void checkDisplayInterval();
void checkWiFiInterval();
void validateDigiFreqs();
void validateFreqs();
void typeOfPacket(String packet, String packetType);
void onOTAStart();
void onOTAProgress(size_t current, size_t final);

View file

@ -29,10 +29,6 @@ namespace WEB_Utils {
AsyncWebServer server(80);
void loop() {
}
void handleNotFound(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse(404, "text/plain", "Not found");
response->addHeader("Cache-Control", "max-age=3600");
@ -71,42 +67,47 @@ namespace WEB_Utils {
WiFi_AP wifiap;
wifiap.ssid = request->getParam("wifi.AP." + String(i) + ".ssid", true)->value();
wifiap.password = request->getParam("wifi.AP." + String(i) + ".password", true)->value();
wifiap.latitude = request->getParam("wifi.AP." + String(i) + ".latitude", true)->value().toDouble();
wifiap.longitude = request->getParam("wifi.AP." + String(i) + ".longitude", true)->value().toDouble();
// wifiap.latitude = request->getParam("wifi.AP." + String(i) + ".latitude", true)->value().toDouble();
// wifiap.longitude = request->getParam("wifi.AP." + String(i) + ".longitude", true)->value().toDouble();
Config.wifiAPs.push_back(wifiap);
}
Config.callsign = request->getParam("callsign", true)->value();
Config.stationMode = request->getParam("stationMode", true)->value().toInt();
Config.iGateComment = request->getParam("iGateComment", true)->value();
// Config.iGateComment = request->getParam("iGateComment", true)->value();
Config.wifiAutoAP.password = request->getParam("wifi.autoAP.password", true)->value();
Config.wifiAutoAP.powerOff = request->getParam("wifi.autoAP.powerOff", true)->value().toInt();
Config.digi.comment = request->getParam("digi.comment", true)->value();
Config.digi.latitude = request->getParam("digi.latitude", true)->value().toDouble();
Config.digi.longitude = request->getParam("digi.longitude", true)->value().toDouble();
Config.digi.mode = request->getParam("digi.mode", true)->value().toInt();
// Config.digi.comment = request->getParam("digi.comment", true)->value();
// Config.digi.latitude = request->getParam("digi.latitude", true)->value().toDouble();
// Config.digi.longitude = request->getParam("digi.longitude", true)->value().toDouble();
Config.aprs_is.active = request->hasParam("aprs_is.active", true);
Config.aprs_is.passcode = request->getParam("aprs_is.passcode", true)->value();
Config.aprs_is.server = request->getParam("aprs_is.server", true)->value();
Config.aprs_is.port = request->getParam("aprs_is.port", true)->value().toInt();
Config.aprs_is.reportingDistance = request->getParam("aprs_is.reportingDistance", true)->value().toInt();
Config.loramodule.iGateFreq = request->getParam("lora.iGateFreq", true)->value().toInt();
if (request->hasParam("lora.digirepeaterTxFreq", true)) {
Config.loramodule.digirepeaterTxFreq = request->getParam("lora.digirepeaterTxFreq", true)->value().toInt();
}
if (request->hasParam("lora.digirepeaterRxFreq", true)) {
Config.loramodule.digirepeaterRxFreq = request->getParam("lora.digirepeaterRxFreq", true)->value().toInt();
}
// Config.aprs_is.reportingDistance = request->getParam("aprs_is.reportingDistance", true)->value().toInt();
Config.aprs_is.filter = request->getParam("aprs_is.filter", true)->value();
Config.aprs_is.toRF = request->hasParam("aprs_is.toRF", true);
// Config.loramodule.iGateFreq = request->getParam("lora.iGateFreq", true)->value().toInt();
// if (request->hasParam("lora.digirepeaterTxFreq", true)) {
// Config.loramodule.digirepeaterTxFreq = request->getParam("lora.digirepeaterTxFreq", true)->value().toInt();
// }
// if (request->hasParam("lora.digirepeaterRxFreq", true)) {
// Config.loramodule.digirepeaterRxFreq = request->getParam("lora.digirepeaterRxFreq", true)->value().toInt();
// }
Config.loramodule.txFreq = request->getParam("lora.txFreq", true)->value().toInt();
Config.loramodule.rxFreq = request->getParam("lora.rxFreq", true)->value().toInt();
Config.loramodule.spreadingFactor = request->getParam("lora.spreadingFactor", true)->value().toInt();
Config.loramodule.signalBandwidth = request->getParam("lora.signalBandwidth", true)->value().toInt();
Config.loramodule.codingRate4 = request->getParam("lora.codingRate4", true)->value().toInt();
Config.loramodule.power = request->getParam("lora.power", true)->value().toInt();
Config.loramodule.txActive = request->hasParam("lora.txActive", true);
Config.loramodule.rxActive = request->hasParam("lora.rxActive", true);
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
@ -128,9 +129,19 @@ namespace WEB_Utils {
Config.ota.username = request->getParam("ota.username", true)->value();
Config.ota.password = request->getParam("ota.password", true)->value();
Config.beaconInterval = request->getParam("other.beaconInterval", true)->value().toInt();
Config.igateSendsLoRaBeacons = request->hasParam("other.igateSendsLoRaBeacons", true);
Config.igateRepeatsLoRaPackets = request->hasParam("other.igateRepeatsLoRaPackets", true);
Config.beacon.interval = request->getParam("beacon.interval", true)->value().toInt();
Config.beacon.sendViaAPRSIS = request->hasParam("beacon.sendViaAPRSIS", true);
Config.beacon.sendViaRF = request->hasParam("beacon.sendViaRF", true);
Config.beacon.latitude = request->getParam("beacon.latitude", true)->value().toDouble();
Config.beacon.longitude = request->getParam("beacon.longitude", true)->value().toDouble();
Config.beacon.comment = request->getParam("beacon.comment", true)->value();
Config.beacon.overlay = request->getParam("beacon.overlay", true)->value();
Config.beacon.symbol = request->getParam("beacon.symbol", true)->value();
Config.beacon.path = request->getParam("beacon.path", true)->value();
// Config.beaconInterval = request->getParam("other.beaconInterval", true)->value().toInt();
// Config.igateSendsLoRaBeacons = request->hasParam("other.igateSendsLoRaBeacons", true);
// Config.igateRepeatsLoRaPackets = request->hasParam("other.igateRepeatsLoRaPackets", true);
Config.rememberStationTime = request->getParam("other.rememberStationTime", true)->value().toInt();
Config.sendBatteryVoltage = request->hasParam("other.sendBatteryVoltage", true);
Config.externalVoltageMeasurement = request->hasParam("other.externalVoltageMeasurement", true);

View file

@ -9,8 +9,6 @@
namespace WEB_Utils {
void loop();
void handleNotFound(AsyncWebServerRequest *request);
void handleStatus(AsyncWebServerRequest *request);

View file

@ -9,7 +9,6 @@ extern Configuration Config;
extern WiFi_AP *currentWiFi;
extern int myWiFiAPIndex;
extern int myWiFiAPSize;
extern int stationMode;
extern uint32_t previousWiFiMillis;
extern bool WiFiConnected;
extern long WiFiAutoAPTime;
@ -32,7 +31,7 @@ namespace WIFI_Utils {
WiFi.mode(WIFI_MODE_NULL);
WiFi.mode(WIFI_AP);
WiFi.softAP(Config.callsign + " AP", "1234567890");
WiFi.softAP(Config.callsign + " AP", Config.wifiAutoAP.password);
WiFiAutoAPTime = millis();
WiFiAutoAPStarted = true;
@ -65,9 +64,7 @@ namespace WIFI_Utils {
delay(1000);
if(myWiFiAPIndex >= (myWiFiAPSize-1)) {
myWiFiAPIndex = 0;
if (stationMode==5) {
wifiCounter++;
}
wifiCounter++;
} else {
myWiFiAPIndex++;
}
@ -123,36 +120,8 @@ namespace WIFI_Utils {
}
void setup() {
if (stationMode==1 || stationMode==2) {
if (stationMode==1) {
Serial.println("stationMode ---> iGate (only Rx)");
} else {
Serial.println("stationMode ---> iGate (Rx + Tx)");
}
startWiFi();
btStop();
} else if (stationMode==3 || stationMode==4) {
if (stationMode==3) {
Serial.println("stationMode ---> DigiRepeater (Rx freq == Tx freq)");
} else {
Serial.println("stationMode ---> DigiRepeater (Rx freq != Tx freq)");
}
startAutoAP();
btStop();
} else if (stationMode==5) {
Serial.println("stationMode ---> iGate when Wifi/APRS available (DigiRepeater when not)");
startWiFi();
btStop();
} else {
Serial.println("stationMode ---> NOT VALID");
show_display("------- ERROR -------", "stationMode Not Valid", "device will autofix", "and then reboot", 1000);
Config.stationMode = 1; // Inform about that but then change the station mode to 1 and reset the device
Config.writeFile();
ESP.restart();
}
startWiFi();
btStop();
}
}