Compare commits

...

59 Commits

Author SHA1 Message Date
richonguzman
a89181b5df update complete 2025-09-26 11:37:02 -03:00
richonguzman
9a94a193f9 update before release 2025-09-25 22:01:38 -03:00
richonguzman
9c7f6c7934 led update 2025-09-25 17:54:53 -03:00
richonguzman
53e8941262 blue led add 2025-09-25 17:33:59 -03:00
richonguzman
60a148d362 testing1 2025-09-25 15:55:18 -03:00
richonguzman
36cd1578cc adding basic stuff 2025-09-25 15:50:28 -03:00
richonguzman
c3036f290f TCPIP correction 2025-09-25 15:35:38 -03:00
richonguzman
8eb4ef1dc2 testeando ultimos valores 2025-09-17 17:00:49 -03:00
richonguzman
d5930380b4 testing new config init validation 2025-09-17 16:53:09 -03:00
richonguzman
e42f4b59ed prueba nueva web write desde formulario 2025-09-17 15:29:13 -03:00
richonguzman
2697f2a5f2 update a configuration cpp 2025-09-17 14:29:37 -03:00
richonguzman
36c970aed9 json file size fix 2025-09-14 20:00:56 -03:00
richonguzman
10e1581bc2 new board 2025-09-14 19:54:20 -03:00
Ricardo Guzman (Richonguzman)
bc57d1609a Merge pull request #321 from richonguzman/richonguzman-patch-6
Update README.md
2025-09-09 10:22:52 -03:00
Ricardo Guzman (Richonguzman)
37380c6b9d Update README.md 2025-09-09 10:22:27 -03:00
Ricardo Guzman (Richonguzman)
855c84c079 Merge pull request #320 from richonguzman/richonguzman-patch-5
Update build for Heltec wireless paper v1
2025-09-09 10:02:05 -03:00
Ricardo Guzman (Richonguzman)
bb4df08f06 Update build for Heltec wireless paper v1 2025-09-09 09:56:26 -03:00
richonguzman
6d0e98f4a2 version Date update 2025-09-09 09:42:25 -03:00
richonguzman
c5dcc4c7ab SensorRead with UEM fix 2025-09-08 21:28:54 -03:00
richonguzman
5c5c940d71 mDNS added 2025-09-08 19:00:23 -03:00
richonguzman
57decd2ac7 gpsAmbiguity fix 2025-09-03 18:00:15 -04:00
richonguzman
26a9d1fa99 not build 2025-09-02 10:17:34 -04:00
richonguzman
bf1ab1bfb4 v1_2 missing library update 2025-09-02 10:17:03 -04:00
richonguzman
d32f35ced1 epaper test1 2025-09-01 21:32:28 -04:00
richonguzman
db37567538 62.5K BW added 2025-08-31 13:00:44 -04:00
richonguzman
dc1bdbb703 mqtt without user and pass 2025-08-29 15:01:34 -04:00
richonguzman
74a8fa7969 updatedVersion 2025-08-29 14:51:07 -04:00
richonguzman
b65a6de018 ready for testing 2025-08-29 14:18:13 -04:00
richonguzman
1840ce2338 test with disabling boxes 2025-08-29 12:17:07 -04:00
richonguzman
b8ef262cc7 many switches fix 2025-08-29 10:33:35 -04:00
richonguzman
bb795816e1 corrected json 2025-08-27 18:10:03 -04:00
richonguzman
a046791722 more updates 2025-08-27 17:44:27 -04:00
richonguzman
88eda7b3fd test mqtt 2 2025-08-27 13:29:26 -04:00
richonguzman
03991e245d test MQTT 1 2025-08-27 13:25:11 -04:00
richonguzman
8a02e953c3 testNewTelemetry 2025-08-26 18:33:58 -04:00
richonguzman
4651938cb1 monitorMod1 2025-08-26 17:44:04 -04:00
richonguzman
83a39c2093 syslog decoding update 2025-08-20 13:01:36 -04:00
richonguzman
bc596f099d hidden Syslog enabled 2025-08-20 12:32:05 -04:00
richonguzman
438a6ee536 js update too 2025-08-19 12:52:18 -04:00
richonguzman
206c79f0a9 lora32 test ok 2025-08-19 12:30:40 -04:00
richonguzman
236cfa724e ready for testing 2025-08-17 22:04:22 -04:00
richonguzman
028a82a40e adcMods1 2025-08-15 15:53:19 -04:00
richonguzman
bb9a061266 better reading accuracy 2025-08-07 20:15:23 -04:00
richonguzman
fd24ce8598 versionDate update 2025-08-04 14:50:33 -04:00
richonguzman
6cbe8173e8 test1 2025-07-30 08:53:02 -04:00
richonguzman
b4261f37cb index Requires update 2025-07-26 10:23:46 -04:00
richonguzman
b5a68a6758 index date update 2025-07-26 10:03:06 -04:00
richonguzman
ce3d136954 versionDate 2025-07-26 09:58:38 -04:00
richonguzman
996a8976ba libraries order (looks) 2025-07-26 09:17:32 -04:00
richonguzman
ce4ace5f21 sent correction 2 2025-07-26 09:15:19 -04:00
richonguzman
93fe8aedc9 sent correction 1 2025-07-26 09:12:22 -04:00
richonguzman
892709e07d qAR corrections 2025-07-26 09:10:36 -04:00
richonguzman
2b90af1cf8 cleaning 2025-07-15 16:33:28 -04:00
richonguzman
a5f420d591 main update 2025-07-15 16:32:44 -04:00
richonguzman
368dd06e05 GPL v3 update 2025-07-15 16:28:23 -04:00
richonguzman
357483c44a images update for wiki 2025-06-20 16:44:07 -04:00
Ricardo Guzman (Richonguzman)
6f9d71c1d8 Merge pull request #298 from richonguzman/richonguzman-patch-4
Update README with new boards
2025-06-19 12:47:13 -04:00
Ricardo Guzman (Richonguzman)
6bff66c67b Update README with new boards 2025-06-19 12:47:01 -04:00
Ricardo Guzman (Richonguzman)
d443218d50 Merge pull request #297 from richonguzman/richonguzman-patch-3
Update README.md
2025-06-19 12:45:17 -04:00
104 changed files with 3103 additions and 642 deletions

View File

@@ -67,7 +67,7 @@ jobs:
chip: esp32s3
- name: heltec_ht-ct62
chip: esp32c3
- name: heltec_wireless_paper
- name: heltec_wireless_paper_v1
chip: esp32s3
- name: OE5HWN_MeshCom
chip: esp32

View File

@@ -60,8 +60,11 @@ ____________________________________________________
## Timeline (Versions):
- 2025.06.20 Digipeaters now with updated EcoMode (Board Sleeps until packet Rx reducing current consumption to almost 10% at idle).
- 2025.06.19 DateVersion format Change. Licence changed into GNU GPLv3.
- 2025-09-26 Heltec Wireless Bridge support added.
- 2025-09-09 MQTT added (pub+sub), Status defined by Op now and many fixes more.
- 2025-06-20 Digipeaters now with updated EcoMode (Board Sleeps until packet Rx reducing current consumption to almost 10% at idle).
- 2025-06-20 New Boards Added: Heltec T114 MeshNode, Faketec V3 as Digipeaters and QRP Labs LightGateway Plus 1.0.
- 2025-06-19 DateVersion format Change. Licence changed into GNU GPLv3.
- 2025.03.20 Manager List added to enable/disable DigiEcoMode and Tx Control. Thanks LB5JJ.
- 2025.03.03 T-Beam Supreme board added and more BlackList rules added.
- 2025.02.28 Heltec Wireless Paper with Epaper working. Thanks SzymonPriv for pointing to the right library.

View File

@@ -33,9 +33,11 @@ lib_deps =
ayushsharma82/ElegantOTA @ 3.1.5
bblanchon/ArduinoJson @ 6.21.3
jgromes/RadioLib @ 7.1.0
knolleary/PubSubClient @ 2.8
mathieucarbou/AsyncTCP @ 3.2.5
mathieucarbou/ESPAsyncWebServer @ 3.2.3
mikalhart/TinyGPSPlus @ 1.0.3
mikalhart/TinyGPSPlus @ 1.0.3
richonguzman/APRSPacketLib @1.0.0
display_libs =
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10

View File

@@ -16,17 +16,23 @@
"symbol": "a",
"path": "WIDE1-1",
"sendViaAPRSIS": false,
"sendViaRF": false
"sendViaRF": false,
"statusActive": false,
"statusPacket": "",
"gpsActive": false,
"gpsAmbiguity": false
},
"aprs_is": {
"active": false,
"passcode": "XYZVW",
"server": "rotate.aprs2.net",
"port": 14580,
"filter": "m/10",
"messagesToRF": false,
"objectsToRF": false
"objectsToRF": false,
"server": "rotate.aprs2.net",
"passcode": "XYZVW",
"port": 14580,
"filter": "m/10"
},
"personalNote": "",
"blacklist": "",
"digi": {
"mode": 0,
"ecoMode": 0
@@ -66,13 +72,22 @@
"syslog": {
"active": false,
"server": "lora.link9.net",
"port": 1514
"port": 1514,
"logBeaconOverTCPIP": false
},
"tnc": {
"enableServer": false,
"enableSerial": false,
"acceptOwn": false
},
"mqtt": {
"active": false,
"server": "",
"topic": "",
"username": "",
"password": "",
"port": 1883
},
"ota": {
"username": "",
"password": ""
@@ -81,19 +96,17 @@
"username": "admin",
"password": ""
},
"ntp": {
"gmtCorrection": 0.0
},
"remoteManagement": {
"managers": "",
"rfOnly": true
},
},
"ntp": {
"gmtCorrection": 0.0
},
"other": {
"rememberStationTime": 30,
"backupDigiMode": false,
"rebootMode": false,
"rebootModeTime": 6
},
"personalNote": "",
"blacklist": ""
}
}

View File

@@ -80,7 +80,7 @@
<small>(Local Time is NTP-Time adjusted with your GMT Offset)</small>
</div>
</div>
<hr />
<hr>
</div>
<div class="container" id="configuration">
@@ -253,13 +253,43 @@
name="personalNote"
id="personalNote"
class="form-control"
placeholder="A Couple of words."
placeholder="A couple of words"
/>
</div>
<div class="col-12 mt-3">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.statusActive"
id="beacon.statusActive"
class="form-check-input"
/>
<label
for="beacon.statusActive"
class="form-label"
>Send Status at each Boot</label
>
</div>
</div>
<div class="col-12">
<label
for="beacon.statusPacket"
class="form-label"
>Status</label
>
<input
type="text"
name="beacon.statusPacket"
id="beacon.statusPacket"
class="form-control"
placeholder="Custom Status"
value=""
/>
</div>
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -316,7 +346,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -409,8 +439,9 @@
type="text"
name="aprs_is.server"
id="aprs_is.server"
placeholder="soam.aprs2.net"
placeholder="rotate.aprs2.net"
class="form-control"
value="rotate.aprs2.net"
/>
</div>
<div class="col-4">
@@ -425,6 +456,7 @@
id="aprs_is.port"
placeholder="14580"
class="form-control"
value="14580"
/>
</div>
</div>
@@ -440,6 +472,7 @@
name="aprs_is.passcode"
id="aprs_is.passcode"
class="form-control"
value="XYZWV"
/>
</div>
<div class="col-4">
@@ -453,12 +486,13 @@
class="form-control"
name="aprs_is.filter"
id="aprs_is.filter"
value="m/10"
/>
</div>
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -571,7 +605,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -612,7 +646,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -661,7 +695,10 @@
<label
for="digi.ecoMode"
class="form-label"
>Eco Mode</label
>Eco Mode
<small
>(Requires Digipeating enabled and APRS-IS connection disabled).</small
></label
>
<select
class="form-select form-select"
@@ -682,7 +719,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -834,7 +871,10 @@
name="lora.signalBandwidth"
id="lora.signalBandwidth"
required=""
>
>
<option value="62500" selected>
62.5 kHz
</option>
<option value="125000" selected>
125 kHz
</option>
@@ -917,7 +957,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -986,6 +1026,8 @@
name="display.timeout"
id="display.timeout"
value="4"
step="1"
min="2"
class="form-control"
/>
<span class="input-group-text"
@@ -1018,7 +1060,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1211,7 +1253,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1245,9 +1287,9 @@
<label
for="wxsensor.active"
class="form-label"
><b>Activate Wx Telemetry</b>
>Activate Wx Telemetry
<small
>Requires a BME/BMP280, BME680 or Si7021 sensor.</small
>(Requires a BME/BMP280, BME680 or Si7021 sensor).</small
></label
>
</div>
@@ -1296,7 +1338,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1347,7 +1389,6 @@
id="syslog.server"
placeholder="lora.link9.net"
class="form-control"
disabled
/>
</div>
<div class="col-6">
@@ -1362,13 +1403,27 @@
id="syslog.port"
placeholder="1514"
class="form-control"
disabled
/>
</div>
<div class="col-6">
<div class="form-check form-switch">
<input
type="checkbox"
name="syslog.logBeaconOverTCPIP"
id="syslog.logBeaconOverTCPIP"
class="form-check-input"
/>
<label
for="syslog.logBeaconOverTCPIP"
class="form-label"
>Log Beacon over TCP/IP</label
>
</div>
</div>
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1453,7 +1508,143 @@
</div>
</div>
</div>
<hr />
<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-database-fill"
viewBox="0 0 16 16"
>
<path
d="M3.904 1.777C4.978 1.289 6.427 1 8 1s3.022.289 4.096.777C13.125 2.245 14 2.993 14 4s-.875 1.755-1.904 2.223C11.022 6.711 9.573 7 8 7s-3.022-.289-4.096-.777C2.875 5.755 2 5.007 2 4s.875-1.755 1.904-2.223"
/>
<path
d="M2 6.161V7c0 1.007.875 1.755 1.904 2.223C4.978 9.71 6.427 10 8 10s3.022-.289 4.096-.777C13.125 8.755 14 8.007 14 7v-.839c-.457.432-1.004.751-1.49.972C11.278 7.693 9.682 8 8 8s-3.278-.307-4.51-.867c-.486-.22-1.033-.54-1.49-.972"
/>
<path
d="M2 9.161V10c0 1.007.875 1.755 1.904 2.223C4.978 12.711 6.427 13 8 13s3.022-.289 4.096-.777C13.125 11.755 14 11.007 14 10v-.839c-.457.432-1.004.751-1.49.972-1.232.56-2.828.867-4.51.867s-3.278-.307-4.51-.867c-.486-.22-1.033-.54-1.49-.972"
/>
<path
d="M2 12.161V13c0 1.007.875 1.755 1.904 2.223C4.978 15.711 6.427 16 8 16s3.022-.289 4.096-.777C13.125 14.755 14 14.007 14 13v-.839c-.457.432-1.004.751-1.49.972-1.232.56-2.828.867-4.51.867s-3.278-.307-4.51-.867c-.486-.22-1.033-.54-1.49-.972"
/>
</svg>
MQTT
</h5>
<small>Set your MQTT server</small>
</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="mqtt.active"
id="mqtt.active"
class="form-check-input"
/>
<label
for="mqtt.active"
class="form-label"
>Enable</label
>
</div>
</div>
<div class="col-12">
<label
for="mqtt.server"
class="form-label"
>Server</label
>
<div class="input-group">
<input
type="text"
name="mqtt.server"
id="mqtt.server"
class="form-control"
/>
</div>
</div>
<div class="col-12">
<label
for="mqtt.topic"
class="form-label"
>Topic</label
>
<div class="input-group">
<input
type="text"
name="mqtt.topic"
id="mqtt.topic"
class="form-control"
placeholder="aprs-igate"
/>
</div>
<div class="form-text">
Default is <strong>aprs-igate</strong>
</div>
</div>
<div class="col-12">
<label
for="mqtt.username"
class="form-label"
>Username</label
>
<div class="input-group">
<input
type="text"
name="mqtt.username"
id="mqtt.username"
class="form-control"
/>
</div>
</div>
<div class="col-12 mt-3">
<label
for="mqtt.password"
class="form-label"
>Password</label
>
<div class="input-group">
<input
type="password"
name="mqtt.password"
id="mqtt.password"
class="form-control"
/>
</div>
</div>
<div class="col-12 mt-3">
<label
for="mqtt.port"
class="form-label"
>Port</label
>
<div class="input-group">
<input
type="number"
name="mqtt.port"
id="mqtt.port"
class="form-control"
placeholder="1883"
required=""
step="1"
min="0"
/>
</div>
<div class="form-text">
Default is <strong>1883</strong>
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1520,7 +1711,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1596,7 +1787,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1646,7 +1837,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1715,7 +1906,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1774,7 +1965,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1823,7 +2014,7 @@
</div>
</div>
</div>
<hr />
<hr>
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
@@ -1889,7 +2080,7 @@
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.408 5.89c.681 0 1.138.47 1.187 1.107h1.147v-.11c-.053-1.187-1.024-2-2.343-2-1.604 0-2.518 1.05-2.518 2.751v.747c0 1.7.906 2.73 2.518 2.73 1.314 0 2.285-.792 2.343-1.939v-.114H6.595c-.049.615-.497 1.05-1.187 1.05-.84 0-1.318-.62-1.318-1.727v-.742c0-1.112.488-1.754 1.318-1.754Zm5.404 0c.68 0 1.138.47 1.186 1.107h1.147v-.11c-.053-1.187-1.024-2-2.342-2-1.604 0-2.518 1.05-2.518 2.751v.747c0 1.7.905 2.73 2.518 2.73 1.314 0 2.285-.792 2.342-1.939v-.114h-1.147c-.048.615-.496 1.05-1.186 1.05-.84 0-1.319-.62-1.319-1.727v-.742c0-1.112.488-1.754 1.319-1.754Z"
/>
</svg>
2023-24
2023-25
<b
><a href="https://github.com/richonguzman"
>CA2RXU</a

View File

@@ -49,27 +49,6 @@ function fetchSettings() {
});
}
const alwaysOnCheckbox = document.querySelector(
'input[name="display.alwaysOn"]'
);
const timeoutInput = document.querySelector('input[name="display.timeout"]');
alwaysOnCheckbox.addEventListener("change", function () {
timeoutInput.disabled = this.checked;
});
// timeoutInput.addEventListener("change", function () {
// alwaysOnCheckbox.disabled = this.value !== "";
// });
const logCheckbox = document.querySelector('input[name="syslog.active"]');
const serverField = document.querySelector('input[name="syslog.server"]');
const portField = document.querySelector('input[name="syslog.port"]');
logCheckbox.addEventListener("change", function () {
serverField.disabled = !this.checked;
portField.disabled = !this.checked;
});
function loadSettings(settings) {
currentSettings = settings;
@@ -125,6 +104,13 @@ function loadSettings(settings) {
document.getElementById("aprs_is.port").value = settings.aprs_is.port;
document.getElementById("aprs_is.filter").value = settings.aprs_is.filter;
document.getElementById("aprs_is.passcode").value = settings.aprs_is.passcode;
APRSISCheckbox.checked = settings.aprs_is.active;
APRSISGateMessages.disabled = !APRSISCheckbox.checked;
APRSISGateObjects.disabled = !APRSISCheckbox.checked;
APRSISServer.disabled = !APRSISCheckbox.checked;
APRSISPort.disabled = !APRSISCheckbox.checked;
APRSISPasscode.disabled = !APRSISCheckbox.checked;
APRSISFilter.disabled = !APRSISCheckbox.checked;
// Beacon
document.getElementById("beacon.latitude").value = settings.beacon.latitude;
@@ -134,6 +120,11 @@ function loadSettings(settings) {
document.getElementById("beacon.sendViaAPRSIS").checked = settings.beacon.sendViaAPRSIS;
document.getElementById("beacon.sendViaRF").checked = settings.beacon.sendViaRF;
document.getElementById("beacon.statusActive").checked = settings.beacon.statusActive;
document.getElementById("beacon.statusPacket").value = settings.beacon.statusPacket;
StatusCheckbox.checked = settings.beacon.statusActive;
StatusPacket.disabled = !StatusCheckbox.checked;
document.getElementById("beacon.gpsActive").checked = settings.beacon.gpsActive;
document.getElementById("beacon.gpsAmbiguity").checked = settings.beacon.gpsAmbiguity;
@@ -142,7 +133,7 @@ function loadSettings(settings) {
// Digi
document.getElementById("digi.mode").value = settings.digi.mode;
document.getElementById("digi.ecoMode").checked = settings.digi.ecoMode;
document.getElementById("digi.ecoMode").value = settings.digi.ecoMode;
// LoRa
document.getElementById("lora.txFreq").value = settings.lora.txFreq;
@@ -158,38 +149,50 @@ function loadSettings(settings) {
document.getElementById("display.alwaysOn").checked = settings.display.alwaysOn;
document.getElementById("display.turn180").checked = settings.display.turn180;
document.getElementById("display.timeout").value = settings.display.timeout;
if (settings.display.alwaysOn) {
timeoutInput.disabled = true;
}
DisplayAlwaysOnCheckbox.checked = settings.display.alwaysOn;
DisplayTimeout.disabled = DisplayAlwaysOnCheckbox.checked;
// BATTERY
document.getElementById("battery.sendInternalVoltage").checked = settings.battery.sendInternalVoltage;
document.getElementById("battery.monitorInternalVoltage").checked = settings.battery.monitorInternalVoltage;
document.getElementById("battery.internalSleepVoltage").value = settings.battery.internalSleepVoltage.toFixed(1);
MonitorInternalVoltageCheckbox.checked = settings.battery.monitorInternalVoltage;
MonitorInternalSleepVoltage.disabled = !MonitorInternalVoltageCheckbox.checked;
document.getElementById("battery.sendExternalVoltage").checked = settings.battery.sendExternalVoltage;
document.getElementById("battery.externalVoltagePin").value = settings.battery.externalVoltagePin;
document.getElementById("battery.voltageDividerR1").value = settings.battery.voltageDividerR1.toFixed(1);
document.getElementById("battery.voltageDividerR2").value = settings.battery.voltageDividerR2.toFixed(1);
SendExternalVoltageCheckbox.checked = settings.battery.sendExternalVoltage;
ExternalVoltagePin.disabled = !SendExternalVoltageCheckbox.checked;
ExternalVoltageDividerR1.disabled = !SendExternalVoltageCheckbox.checked;
ExternalVoltageDividerR2.disabled = !SendExternalVoltageCheckbox.checked;
document.getElementById("battery.monitorExternalVoltage").checked = settings.battery.monitorExternalVoltage;
document.getElementById("battery.externalSleepVoltage").value = settings.battery.externalSleepVoltage.toFixed(1);
MonitorExternalVoltageCheckbox.checked = settings.battery.monitorExternalVoltage;
MonitorExternalSleepVoltage.disabled = !MonitorExternalVoltageCheckbox.checked;
document.getElementById("battery.sendVoltageAsTelemetry").checked = settings.battery.sendVoltageAsTelemetry;
// TELEMETRY WX SENSOR
document.getElementById("wxsensor.active").checked = settings.wxsensor.active;
document.getElementById("wxsensor.heightCorrection").value = settings.wxsensor.heightCorrection;
document.getElementById("wxsensor.temperatureCorrection").value = settings.wxsensor.temperatureCorrection.toFixed(1);
TelemetryCheckbox.checked = settings.wxsensor.active;
TelemetryHeightCorrection.disabled = !TelemetryCheckbox.checked;
TelemetryTempCorrection.disabled = !TelemetryCheckbox.checked;
// SYSLOG
document.getElementById("syslog.active").checked = settings.syslog.active;
document.getElementById("syslog.server").value = settings.syslog.server;
document.getElementById("syslog.port").value = settings.syslog.port;
if (settings.syslog.active) {
serverField.disabled = false;
portField.disabled = false;
}
document.getElementById("syslog.logBeaconOverTCPIP").checked = settings.syslog.logBeaconOverTCPIP;
SyslogCheckbox.checked = settings.syslog.active;
SyslogServer.disabled = !SyslogCheckbox.checked;
SyslogPort.disabled = !SyslogCheckbox.checked;
SyslogBeaconOverTCPIP.disabled = !SyslogCheckbox.checked;
// TNC
if (settings.tnc) {
document.getElementById("tnc.enableServer").checked = settings.tnc.enableServer;
@@ -197,9 +200,25 @@ function loadSettings(settings) {
document.getElementById("tnc.acceptOwn").checked = settings.tnc.acceptOwn;
}
// MQTT
document.getElementById("mqtt.active").checked = settings.mqtt.active;
document.getElementById("mqtt.server").value = settings.mqtt.server;
document.getElementById("mqtt.topic").value = settings.mqtt.topic;
document.getElementById("mqtt.username").value = settings.mqtt.username;
document.getElementById("mqtt.password").value = settings.mqtt.password;
document.getElementById("mqtt.port").value = settings.mqtt.port;
MqttCheckbox.checked = settings.mqtt.active;
MqttServer.disabled = !MqttCheckbox.check;
MqttTopic.disabled = !MqttCheckbox.check;
MqttUsername.disabled = !MqttCheckbox.check;
MqttPassword.disabled = !MqttCheckbox.check;
MqttPort.disabled = !MqttCheckbox.check;
// Reboot
document.getElementById("other.rebootMode").checked = settings.other.rebootMode;
document.getElementById("other.rebootModeTime").value = settings.other.rebootModeTime;
RebootModeCheckbox.checked = settings.other.rebootMode;
RebootModeTime.disabled = !RebootModeCheckbox.check;
// WiFi Auto AP
document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password;
@@ -213,6 +232,13 @@ function loadSettings(settings) {
document.getElementById("webadmin.active").checked = settings.webadmin.active;
document.getElementById("webadmin.username").value = settings.webadmin.username;
document.getElementById("webadmin.password").value = settings.webadmin.password;
WebadminCheckbox.checked = settings.webadmin.active;
WebadminUsername.disabled = !WebadminCheckbox.check;
WebadminPassword.disabled = !WebadminCheckbox.check;
// Management over APRS
document.getElementById("remoteManagement.managers").value = settings.remoteManagement.managers;
document.getElementById("remoteManagement.rfOnly").checked = settings.remoteManagement.rfOnly;
// NTP
document.getElementById("ntp.gmtCorrection").value = settings.ntp.gmtCorrection;
@@ -220,13 +246,8 @@ function loadSettings(settings) {
// Experimental
document.getElementById("other.backupDigiMode").checked = settings.other.backupDigiMode;
// Management over APRS
document.getElementById("remoteManagement.managers").value = settings.remoteManagement.managers;
document.getElementById("remoteManagement.rfOnly").checked = settings.remoteManagement.rfOnly;
updateImage();
refreshSpeedStandard();
toggleFields();
}
function showToast(message) {
@@ -253,8 +274,6 @@ document.getElementById('reboot').addEventListener('click', function (e) {
showToast("Your device will be rebooted in a while");
});
const wxsensorCheckbox = document.querySelector("input[name='wxsensor.active']");
function updateImage() {
const value = document.getElementById("beacon.overlay").value + document.getElementById("beacon.symbol").value;
@@ -280,70 +299,111 @@ function updateImage() {
}
}
function toggleFields() {
const sendExternalVoltageCheckbox = document.querySelector(
'input[name="battery.sendExternalVoltage"]'
);
const externalVoltagePinInput = document.querySelector(
'input[name="battery.externalVoltagePin"]'
);
externalVoltagePinInput.disabled = !sendExternalVoltageCheckbox.checked;
voltageDividerR1.disabled = !sendExternalVoltageCheckbox.checked;
voltageDividerR2.disabled = !sendExternalVoltageCheckbox.checked;
const WebadminCheckbox = document.querySelector(
'input[name="webadmin.active"]'
);
const WebadminUsername = document.querySelector(
'input[name="webadmin.username"]'
);
const WebadminPassword = document.querySelector(
'input[name="webadmin.password"]'
);
WebadminUsername.disabled = !WebadminCheckbox.checked;
WebadminPassword.disabled = !WebadminCheckbox.checked;
}
const sendExternalVoltageCheckbox = document.querySelector(
'input[name="battery.sendExternalVoltage"]'
);
const externalVoltagePinInput = document.querySelector(
'input[name="battery.externalVoltagePin"]'
);
const voltageDividerR1 = document.querySelector(
'input[name="battery.voltageDividerR1"]'
);
const voltageDividerR2 = document.querySelector(
'input[name="battery.voltageDividerR2"]'
);
sendExternalVoltageCheckbox.addEventListener("change", function () {
externalVoltagePinInput.disabled = !this.checked;
voltageDividerR1.disabled = !this.checked;
voltageDividerR2.disabled = !this.checked;
// Status Switch
const StatusCheckbox = document.querySelector('input[name="beacon.statusActive"]');
const StatusPacket = document.querySelector('input[name="beacon.statusPacket"]');
StatusCheckbox.addEventListener("change", function() {
StatusPacket.disabled = !this.checked;
});
const WebadminCheckbox = document.querySelector(
'input[name="webadmin.active"]'
);
// APRS-IS Switches
const APRSISCheckbox = document.querySelector('input[name="aprs_is.active"]');
const APRSISGateMessages = document.querySelector('input[name="aprs_is.messagesToRF"]');
const APRSISGateObjects = document.querySelector('input[name="aprs_is.objectsToRF"]');
const APRSISServer = document.querySelector('input[name="aprs_is.server"]');
const APRSISPort = document.querySelector('input[name="aprs_is.port"]');
const APRSISPasscode = document.querySelector('input[name="aprs_is.passcode"]');
const APRSISFilter = document.querySelector('input[name="aprs_is.filter"]');
APRSISCheckbox.addEventListener("change", function() {
APRSISGateMessages.disabled = !this.checked;
APRSISGateObjects.disabled = !this.checked;
APRSISServer.disabled = !this.checked;
APRSISPort.disabled = !this.checked;
APRSISPasscode.disabled = !this.checked;
APRSISFilter.disabled = !this.checked;
});
const WebadminUsername = document.querySelector(
'input[name="webadmin.username"]'
);
// Display Switches
const DisplayAlwaysOnCheckbox = document.querySelector('input[name="display.alwaysOn"]');
const DisplayTimeout = document.querySelector('input[name="display.timeout"]');
DisplayAlwaysOnCheckbox.addEventListener("change", function () {
DisplayTimeout.disabled = this.checked;
});
const WebadminPassword = document.querySelector(
'input[name="webadmin.password"]'
);
// Battery Switches
const MonitorInternalVoltageCheckbox = document.querySelector('input[name="battery.monitorInternalVoltage"]');
const MonitorInternalSleepVoltage = document.querySelector('input[name="battery.internalSleepVoltage"]');
MonitorInternalVoltageCheckbox.addEventListener("change", function () {
MonitorInternalSleepVoltage.disabled = !this.checked;
});
const MonitorExternalVoltageCheckbox = document.querySelector('input[name="battery.monitorExternalVoltage"]');
const MonitorExternalSleepVoltage = document.querySelector('input[name="battery.externalSleepVoltage"]');
MonitorExternalVoltageCheckbox.addEventListener("change", function () {
MonitorExternalSleepVoltage.disabled = !this.checked;
});
const SendExternalVoltageCheckbox = document.querySelector('input[name="battery.sendExternalVoltage"]');
const ExternalVoltagePin = document.querySelector('input[name="battery.externalVoltagePin"]');
const ExternalVoltageDividerR1 = document.querySelector('input[name="battery.voltageDividerR1"]');
const ExternalVoltageDividerR2 = document.querySelector('input[name="battery.voltageDividerR2"]');
SendExternalVoltageCheckbox.addEventListener("change", function () {
ExternalVoltagePin.disabled = !this.checked;
ExternalVoltageDividerR1.disabled = !this.checked;
ExternalVoltageDividerR2.disabled = !this.checked;
});
// Telemetry Switches
const TelemetryCheckbox = document.querySelector('input[name="wxsensor.active"]');
const TelemetryHeightCorrection = document.querySelector('input[name="wxsensor.heightCorrection"]');
const TelemetryTempCorrection = document.querySelector('input[name="wxsensor.temperatureCorrection"]');
TelemetryCheckbox.addEventListener("change", function () {
TelemetryHeightCorrection.disabled = !this.checked;
TelemetryTempCorrection.disabled = !this.checked;
});
// Syslog Switches
const SyslogCheckbox = document.querySelector('input[name="syslog.active"]');
const SyslogServer = document.querySelector('input[name="syslog.server"]');
const SyslogPort = document.querySelector('input[name="syslog.port"]');
const SyslogBeaconOverTCPIP = document.querySelector('input[name="syslog.logBeaconOverTCPIP"]');
SyslogCheckbox.addEventListener("change", function () {
SyslogServer.disabled = !this.checked;
SyslogPort.disabled = !this.checked;
SyslogBeaconOverTCPIP.disabled = !this.checked
});
// MQTT Switches
const MqttCheckbox = document.querySelector('input[name="mqtt.active"]');
const MqttServer = document.querySelector('input[name="mqtt.server"]');
const MqttTopic = document.querySelector('input[name="mqtt.topic"]');
const MqttUsername = document.querySelector('input[name="mqtt.username"]');
const MqttPassword = document.querySelector('input[name="mqtt.password"]');
const MqttPort = document.querySelector('input[name="mqtt.port"]');
MqttCheckbox.addEventListener("change", function () {
MqttServer.disabled = !this.checked;
MqttTopic.disabled = !this.checked;
MqttUsername.disabled = !this.checked;
MqttPassword.disabled = !this.checked;
MqttPort.disabled = !this.checked;
});
// Reboot Switches
const RebootModeCheckbox = document.querySelector('input[name="other.rebootMode"]');
const RebootModeTime = document.querySelector('input[name="other.rebootModeTime"]');
RebootModeCheckbox.addEventListener("change", function() {
RebootModeTime.disabled = !this.checked;
});
// Web Admin Switches
const WebadminCheckbox = document.querySelector('input[name="webadmin.active"]');
const WebadminUsername = document.querySelector('input[name="webadmin.username"]');
const WebadminPassword = document.querySelector('input[name="webadmin.password"]');
WebadminCheckbox.addEventListener("change", function () {
WebadminUsername.disabled = !this.checked;
WebadminPassword.disabled = !this.checked;
WebadminUsername.disabled = !this.checked;
WebadminPassword.disabled = !this.checked;
});
document.querySelector(".new button").addEventListener("click", function () {
const networksContainer = document.querySelector(".list-networks");

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef A7670_UTILS_H_
#define A7670_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef APRS_IS_UTILS_H_
#define APRS_IS_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BATTERY_UTILS_H_
#define BATTERY_UTILS_H_
@@ -14,9 +32,6 @@ namespace BATTERY_Utils {
float checkExternalVoltage();
void startupBatteryHealth();
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType);
String generateEncodedTelemetry();
}
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef CONFIGURATION_H_
#define CONFIGURATION_H_
@@ -31,6 +49,8 @@ public:
bool sendViaAPRSIS;
bool gpsActive;
bool gpsAmbiguity;
bool statusActive;
String statusPacket;
};
class APRS_IS {
@@ -95,6 +115,7 @@ public:
bool active;
String server;
int port;
bool logBeaconOverTCPIP;
};
class TNC {
@@ -128,6 +149,16 @@ public:
bool rfOnly;
};
class MQTT {
public:
bool active;
String server;
String topic;
String username;
String password;
int port;
};
class Configuration {
public:
String callsign;
@@ -152,9 +183,10 @@ public:
WEBADMIN webadmin;
NTP ntp;
REMOTE_MANAGEMENT remoteManagement;
MQTT mqtt;
void init();
void writeFile();
void setDefaultValues();
bool writeFile();
Configuration();
private:

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef DIGI_UTILS_H_
#define DIGI_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef DISPLAY_H_
#define DISPLAY_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef GPS_UTILS_H_
#define GPS_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#define DCD_ON 0x03
#define FEND 0xC0

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef KISS_UTILS_H_
#define KISS_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef LORA_UTILS_H_
#define LORA_UTILS_H_

34
include/mqtt_utils.h Normal file
View File

@@ -0,0 +1,34 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MQTT_UTILS_H_
#define MQTT_UTILS_H_
#include <Arduino.h>
namespace MQTT_Utils {
void sendToMqtt(const String& packet);
void connect();
void loop();
void setup();
}
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef NTP_UTILS_H_
#define NTP_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef OTA_UTILS_H_
#define OTA_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef POWER_UTILS_H_
#define POWER_UTILS_H_
@@ -11,9 +29,18 @@
namespace POWER_Utils {
#ifdef VEXT_CTRL
void vext_ctrl_ON();
void vext_ctrl_OFF();
#endif
#ifdef ADC_CTRL
void adc_ctrl_ON();
void adc_ctrl_OFF();
#endif
double getBatteryVoltage();
bool isBatteryConnected();
void activateMeasurement();
void activateGPS();
void deactivateGPS();
void activateLoRa();

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef QUERY_UTILS_H_
#define QUERY_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef SLEEP_UTILS_H_
#define SLEEP_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef STATION_UTILS_H_
#define STATION_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef SYSLOG_H_
#define SYSLOG_H_

33
include/telemetry_utils.h Normal file
View File

@@ -0,0 +1,33 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TELEMETRY_UTILS_H_
#define TELEMETRY_UTILS_H_
#include <Arduino.h>
namespace TELEMETRY_Utils {
void sendEquationsUnitsParameters();
String generateEncodedTelemetryBytes(float value, bool counterBytes, byte telemetryType);
String generateEncodedTelemetry();
}
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TNC_UTILS_H_
#define TNC_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UTILS_H_
#define UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef WEB_UTILS_H_
#define WEB_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef WIFI_UTILS_H_
#define WIFI_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef WX_UTILS_H_
#define WX_UTILS_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include "configuration.h"
#include "aprs_is_utils.h"
#include "board_pinout.h"
@@ -21,9 +39,9 @@
bool modemStartUp = false;
bool serverStartUp = false;
bool userBytesSended = false;
bool beaconBytesSended = false;
bool beaconSended = false;
bool userBytesSent = false;
bool beaconBytesSent = false;
bool beaconSent = false;
bool stationBeacon = false;
extern bool modemLoggedToAPRSIS;
@@ -130,7 +148,7 @@
} else if (ATMessage.indexOf(Config.callsign) >= 3 && !modemLoggedToAPRSIS && response.indexOf("OK") >= 0 && !stationBeacon) { // login info
validAT = true;
delayATMessage = 0;
} else if (ATMessage.indexOf(Config.callsign) == 0 && !beaconSended && response.indexOf("OK") >= 0 && !stationBeacon) { // self beacon or querys
} else if (ATMessage.indexOf(Config.callsign) == 0 && !beaconSent && response.indexOf("OK") >= 0 && !stationBeacon) { // self beacon or querys
validAT = true;
i = 1;
delayATMessage = 0;
@@ -164,10 +182,10 @@
displayShow(firstLine, "Connecting APRS-IS...", " ", " ", 0);
serverStartUp = checkATResponse("AT+CIPOPEN=0,\"TCP\",\"" + String(Config.aprs_is.server) + "\"," + String(Config.aprs_is.port));
delay(2000);
} while (!userBytesSended) {
} while (!userBytesSent) {
Serial.print("Writing User Login Data ");
displayShow(firstLine, "Connecting APRS-IS...", "---> User Login Data", " ", 0);
userBytesSended = checkATResponse("AT+CIPSEND=0," + String(loginInfo.length()+1));
userBytesSent = checkATResponse("AT+CIPSEND=0," + String(loginInfo.length()+1));
delay(2000);
} while (!modemLoggedToAPRSIS) {
Serial.print(".");
@@ -177,19 +195,19 @@
}
void uploadToAPRSIS(const String& packet) {
beaconBytesSended = checkATResponse("AT+CIPSEND=0," + String(packet.length()+1));
beaconBytesSent = checkATResponse("AT+CIPSEND=0," + String(packet.length()+1));
delay(2000);
if (beaconBytesSended) {
if (beaconBytesSent) {
Serial.print(".");
beaconSended = checkATResponse(packet);
beaconSent = checkATResponse(packet);
}
if (!beaconSended) {
if (!beaconSent) {
Serial.println("------------------------------------> UPLOAD FAILED!!!");
} else {
Serial.println("Packet Uploaded to APRS-IS!");
}
beaconBytesSended = false;
beaconSended = false;
beaconBytesSent = false;
beaconSent = false;
}
void listenAPRSIS() {

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
/*___________________________________________________________________
██╗ ██████╗ ██████╗ █████╗ █████╗ ██████╗ ██████╗ ███████╗
@@ -16,7 +34,7 @@
Ricardo Guzman - CA2RXU
https://github.com/richonguzman/LoRa_APRS_Tracker
https://github.com/richonguzman/LoRa_APRS_iGate
(donations : http://paypal.me/richonguzman)
___________________________________________________________________*/
@@ -33,6 +51,7 @@ ___________________________________________________________________*/
#include "syslog_utils.h"
#include "power_utils.h"
#include "sleep_utils.h"
#include "mqtt_utils.h"
#include "lora_utils.h"
#include "wifi_utils.h"
#include "digi_utils.h"
@@ -48,9 +67,11 @@ ___________________________________________________________________*/
#endif
String versionDate = "2025-06-20";
String versionDate = "2025-09-26";
String versionNumber = "3.1.2.1";
Configuration Config;
WiFiClient espClient;
WiFiClient aprsIsClient;
WiFiClient mqttClient;
#ifdef HAS_GPS
HardwareSerial gpsSerial(1);
TinyGPSPlus gps;
@@ -100,6 +121,7 @@ void setup() {
WX_Utils::setup();
WEB_Utils::setup();
TNC_Utils::setup();
MQTT_Utils::setup();
#ifdef HAS_A7670
A7670_Utils::setup();
#endif
@@ -148,11 +170,13 @@ void loop() {
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
#else
WIFI_Utils::checkWiFi();
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) APRS_IS_Utils::connect();
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) APRS_IS_Utils::connect();
if (Config.mqtt.active && (WiFi.status() == WL_CONNECTED) && !mqttClient.connected()) MQTT_Utils::connect();
#endif
NTP_Utils::update();
TNC_Utils::loop();
MQTT_Utils::loop();
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
@@ -165,7 +189,7 @@ void loop() {
}
if (packet != "") {
if (Config.aprs_is.active) { // If APRSIS enabled
if (Config.aprs_is.active) { // If APRSIS enabled
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
}
@@ -174,17 +198,12 @@ void loop() {
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
}
if (Config.tnc.enableServer) { // If TNC server enabled
TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
}
if (Config.tnc.enableSerial) { // If Serial KISS enabled
TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
}
if (Config.tnc.enableServer) TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
if (Config.tnc.enableSerial) TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
if (Config.mqtt.active) MQTT_Utils::sendToMqtt(packet); // Send received packet to MQTT
}
if (Config.aprs_is.active) {
APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
}
if (Config.aprs_is.active) APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
STATION_Utils::processOutputPacketBuffer();
@@ -204,10 +223,4 @@ void loop() {
Utils::checkRebootTime();
Utils::checkSleepByLowBatteryVoltage(1);
}
}
// ESP32 (and ESPS3) work?
// ESP32C3 :
// - HT-CT62 sleeps??
// - and others?
}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFi.h>
#include "configuration.h"
#include "aprs_is_utils.h"
@@ -12,7 +30,7 @@
extern Configuration Config;
extern WiFiClient espClient;
extern WiFiClient aprsIsClient;
extern uint32_t lastScreenOn;
extern String firstLine;
extern String secondLine;
@@ -23,6 +41,7 @@ extern String sixthLine;
extern String seventhLine;
extern bool modemLoggedToAPRSIS;
extern bool backUpDigiMode;
extern String versionNumber;
uint32_t lastRxTime = millis();
bool passcodeValid = false;
@@ -35,17 +54,17 @@ bool passcodeValid = false;
namespace APRS_IS_Utils {
void upload(const String& line) {
espClient.print(line + "\r\n");
aprsIsClient.print(line + "\r\n");
}
void connect() {
Serial.print("Connecting to APRS-IS ... ");
uint8_t count = 0;
while (!espClient.connect(Config.aprs_is.server.c_str(), Config.aprs_is.port) && count < 20) {
while (!aprsIsClient.connect(Config.aprs_is.server.c_str(), Config.aprs_is.port) && count < 20) {
Serial.println("Didn't connect with server...");
delay(1000);
espClient.stop();
espClient.flush();
aprsIsClient.stop();
aprsIsClient.flush();
Serial.println("Run client.stop");
Serial.println("Trying to connect with Server: " + String(Config.aprs_is.server) + " AprsServerPort: " + String(Config.aprs_is.port));
count++;
@@ -60,7 +79,9 @@ namespace APRS_IS_Utils {
aprsAuth += Config.callsign;
aprsAuth += " pass ";
aprsAuth += Config.aprs_is.passcode;
aprsAuth += " vers CA2RXU_iGate 3.0 filter ";
aprsAuth += " vers CA2RXUiGate ";
aprsAuth += versionNumber;
aprsAuth += " filter ";
aprsAuth += Config.aprs_is.filter;
upload(aprsAuth);
}
@@ -92,7 +113,7 @@ namespace APRS_IS_Utils {
aprsisState = "--";
}
#else
if (espClient.connected()) {
if (aprsIsClient.connected()) {
aprsisState = "OK";
} else {
aprsisState = "--";
@@ -118,15 +139,15 @@ namespace APRS_IS_Utils {
}
String buildPacketToUpload(const String& packet) {
String buildedPacket = packet.substring(3, packet.indexOf(":"));
if (!(Config.aprs_is.active && Config.digi.mode == 0)) { // Check if NOT only IGate
buildedPacket += ",qAR,";
String packetToUpload = packet.substring(3, packet.indexOf(":"));
if (Config.aprs_is.active && passcodeValid && Config.aprs_is.messagesToRF) {
packetToUpload += ",qAR,";
} else {
buildedPacket += ",qAO,";
packetToUpload += ",qAO,";
}
buildedPacket += Config.callsign;
buildedPacket += checkForStartingBytes(packet.substring(packet.indexOf(":")));
return buildedPacket;
packetToUpload += Config.callsign;
packetToUpload += checkForStartingBytes(packet.substring(packet.indexOf(":")));
return packetToUpload;
}
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty) {
@@ -174,7 +195,7 @@ namespace APRS_IS_Utils {
}
void processLoRaPacket(const String& packet) {
if (passcodeValid && (espClient.connected() || modemLoggedToAPRSIS)) {
if (passcodeValid && (aprsIsClient.connected() || modemLoggedToAPRSIS)) {
if (packet.indexOf("NOGATE") == -1 && packet.indexOf("RFONLY") == -1) {
int firstColonIndex = packet.indexOf(":");
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] != '}' && packet.indexOf("TCPIP") == -1) {
@@ -353,9 +374,9 @@ namespace APRS_IS_Utils {
#ifdef HAS_A7670
A7670_Utils::listenAPRSIS();
#else
if (espClient.connected()) {
if (espClient.available()) {
String aprsisPacket = espClient.readStringUntil('\r');
if (aprsIsClient.connected()) {
if (aprsIsClient.available()) {
String aprsisPacket = aprsIsClient.readStringUntil('\r');
aprsisPacket.trim(); // Serial.println(aprsisPacket);
processAPRSISPacket(aprsisPacket);
lastRxTime = millis();
@@ -365,7 +386,7 @@ namespace APRS_IS_Utils {
}
void firstConnection() {
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) {
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) {
connect();
while (!passcodeValid) {
listenAPRSIS();

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "battery_utils.h"
#include "configuration.h"
@@ -12,13 +30,13 @@ extern uint32_t lastBatteryCheck;
bool shouldSleepLowVoltage = false;
float adcReadingTransformation = (3.3/4095);
int adcReadings = 20;
float voltageDividerCorrection = 0.288;
float readingCorrection = 0.125;
float multiplyCorrection = 0.035;
float voltageDividerTransformation = 0.0;
int telemetryCounter = random(1,999);
#ifdef HAS_ADC_CALIBRATION
@@ -99,69 +117,58 @@ namespace BATTERY_Utils {
return 0.0;
}
#else
int sample;
int sampleSum = 0;
#ifdef ADC_CTRL
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
digitalWrite(ADC_CTRL, HIGH);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
digitalWrite(ADC_CTRL, LOW);
#endif
POWER_Utils::adc_ctrl_ON();
#endif
for (int i = 0; i < 100; i++) {
int sampleSum = 0;
for (int i = 0; i < adcReadings; i++) {
#if defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915)
sample = 0;
sampleSum = 0;
#else
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
sample = adc1_get_raw(InternalBattery_ADC_Channel);
sampleSum += adc1_get_raw(InternalBattery_ADC_Channel);
} else {
sample = analogRead(BATTERY_PIN);
sampleSum += analogRead(BATTERY_PIN);
}
#else
#ifdef BATTERY_PIN
sample = analogRead(BATTERY_PIN);
sampleSum += analogRead(BATTERY_PIN);
#else
sample = 0;
sampleSum += 0;
#endif
#endif
#endif
sampleSum += sample;
delayMicroseconds(50);
delay(3);
}
#ifdef ADC_CTRL
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
digitalWrite(ADC_CTRL, LOW);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
digitalWrite(ADC_CTRL, HIGH);
#endif
POWER_Utils::adc_ctrl_OFF();
#ifdef HELTEC_WP
#ifdef HELTEC_WP_V1
double inputDivider = (1.0 / (10.0 + 10.0)) * 10.0; // The voltage divider is a 10k + 10k resistor in series
#else
double inputDivider = (1.0 / (390.0 + 100.0)) * 100.0; // The voltage divider is a 390k + 100k resistor in series, 100k on the low side.
#endif
return (((sampleSum/100) * adcReadingTransformation) / inputDivider) + 0.285; // Yes, this offset is excessive, but the ADC on the ESP32s3 is quite inaccurate and noisy. Adjust to own measurements.
return (((sampleSum/adcReadings) * adcReadingTransformation) / inputDivider) + 0.285; // Yes, this offset is excessive, but the ADC on the ESP32s3 is quite inaccurate and noisy. Adjust to own measurements.
#else
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
float voltage = esp_adc_cal_raw_to_voltage(sampleSum / 100, &adc_chars);
float voltage = esp_adc_cal_raw_to_voltage(sampleSum / adcReadings, &adc_chars);
voltage *= 2; // for 100K/100K voltage divider
voltage /= 1000;
return voltage;
} else {
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
return (2 * (sampleSum/adcReadings) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
}
#else
#ifdef LIGHTGATEWAY_PLUS_1_0
double inputDivider = (1.0 / (560.0 + 100.0)) * 100.0; // The voltage divider is a 560k + 100k resistor in series, 100k on the low side.
return (((sampleSum/100) * adcReadingTransformation) / inputDivider) + 0.41;
return (((sampleSum/adcReadings) * adcReadingTransformation) / inputDivider) + 0.41;
#else
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
return (2 * (sampleSum/adcReadings) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
#endif
#endif
#endif
@@ -209,7 +216,7 @@ namespace BATTERY_Utils {
shouldSleepLowVoltage = true;
}
#endif
#ifndef HELTEC_WP
#ifndef HELTEC_WP_V1
if (Config.battery.monitorExternalVoltage && checkExternalVoltage() < Config.battery.externalSleepVoltage + 0.1) {
shouldSleepLowVoltage = true;
}
@@ -219,43 +226,4 @@ namespace BATTERY_Utils {
}
}
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType) { // 0 = internal battery(0-4,2V) , 1 = external battery(0-15V)
String encodedBytes;
int tempValue;
if (firstBytes) {
tempValue = value;
} else {
switch (voltageType) {
case 0:
tempValue = value * 100; // Internal voltage calculation
break;
case 1:
tempValue = (value * 100) / 2; // External voltage calculation
break;
default:
tempValue = value;
break;
}
}
int firstByte = tempValue / 91;
tempValue -= firstByte * 91;
encodedBytes = char(firstByte + 33);
encodedBytes += char(tempValue + 33);
return encodedBytes;
}
String generateEncodedTelemetry() {
String telemetry = "|";
telemetry += generateEncodedTelemetryBytes(telemetryCounter, true, 0);
telemetryCounter++;
if (telemetryCounter == 1000) telemetryCounter = 0;
if (Config.battery.sendInternalVoltage) telemetry += generateEncodedTelemetryBytes(checkInternalVoltage(), false, 0);
if (Config.battery.sendExternalVoltage) telemetry += generateEncodedTelemetryBytes(checkExternalVoltage(), false, 1);
telemetry += "|";
return telemetry;
}
}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <ArduinoJson.h>
#include <SPIFFS.h>
#include "configuration.h"
@@ -8,127 +26,146 @@
bool shouldSleepStop = true;
void Configuration::writeFile() {
Serial.println("Saving config...");
bool Configuration::writeFile() {
Serial.println("Saving configuration...");
StaticJsonDocument<2560> data;
StaticJsonDocument<3584> data;
File configFile = SPIFFS.open("/igate_conf.json", "w");
if (wifiAPs[0].ssid != "") { // We don't want to save Auto AP empty SSID
for (int i = 0; i < wifiAPs.size(); i++) {
data["wifi"]["AP"][i]["ssid"] = wifiAPs[i].ssid;
data["wifi"]["AP"][i]["password"] = wifiAPs[i].password;
}
if (!configFile) {
Serial.println("Error: Could not open config file for writing");
return false;
}
try {
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
if (wifiAPs[0].ssid != "") { // We don't want to save Auto AP empty SSID
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["callsign"] = callsign;
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
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"]["filter"] = aprs_is.filter;
data["aprs_is"]["messagesToRF"] = aprs_is.messagesToRF;
data["aprs_is"]["objectsToRF"] = aprs_is.objectsToRF;
data["callsign"] = callsign;
data["beacon"]["comment"] = beacon.comment;
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["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"]["filter"] = aprs_is.filter;
data["aprs_is"]["messagesToRF"] = aprs_is.messagesToRF;
data["aprs_is"]["objectsToRF"] = aprs_is.objectsToRF;
data["beacon"]["gpsActive"] = beacon.gpsActive;
data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity;
data["beacon"]["comment"] = beacon.comment;
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["digi"]["mode"] = digi.mode;
data["digi"]["ecoMode"] = digi.ecoMode;
#if defined(HAS_A7670)
if (digi.ecoMode == 1) data["digi"]["ecoMode"] = 2;
#endif
data["beacon"]["statusActive"] = beacon.statusActive;
data["beacon"]["statusPacket"] = beacon.statusPacket;
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["beacon"]["gpsActive"] = beacon.gpsActive;
data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity;
data["display"]["alwaysOn"] = display.alwaysOn;
data["display"]["timeout"] = display.timeout;
data["display"]["turn180"] = display.turn180;
data["personalNote"] = personalNote;
data["battery"]["sendInternalVoltage"] = battery.sendInternalVoltage;
data["battery"]["monitorInternalVoltage"] = battery.monitorInternalVoltage;
data["battery"]["internalSleepVoltage"] = battery.internalSleepVoltage;
data["blacklist"] = blacklist;
data["battery"]["sendExternalVoltage"] = battery.sendExternalVoltage;
data["battery"]["externalVoltagePin"] = battery.externalVoltagePin;
data["battery"]["monitorExternalVoltage"] = battery.monitorExternalVoltage;
data["battery"]["externalSleepVoltage"] = battery.externalSleepVoltage;
data["battery"]["voltageDividerR1"] = battery.voltageDividerR1;
data["battery"]["voltageDividerR2"] = battery.voltageDividerR2;
data["digi"]["mode"] = digi.mode;
data["digi"]["ecoMode"] = digi.ecoMode;
#if defined(HAS_A7670)
if (digi.ecoMode == 1) data["digi"]["ecoMode"] = 2;
#endif
data["battery"]["sendVoltageAsTelemetry"] = battery.sendVoltageAsTelemetry;
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["wxsensor"]["active"] = wxsensor.active;
data["wxsensor"]["heightCorrection"] = wxsensor.heightCorrection;
data["wxsensor"]["temperatureCorrection"] = wxsensor.temperatureCorrection;
data["display"]["alwaysOn"] = display.alwaysOn;
data["display"]["timeout"] = display.timeout;
data["display"]["turn180"] = display.turn180;
data["syslog"]["active"] = syslog.active;
data["syslog"]["server"] = syslog.server;
data["syslog"]["port"] = syslog.port;
data["battery"]["sendInternalVoltage"] = battery.sendInternalVoltage;
data["battery"]["monitorInternalVoltage"] = battery.monitorInternalVoltage;
data["battery"]["internalSleepVoltage"] = battery.internalSleepVoltage;
data["tnc"]["enableServer"] = tnc.enableServer;
data["tnc"]["enableSerial"] = tnc.enableSerial;
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
data["battery"]["sendExternalVoltage"] = battery.sendExternalVoltage;
data["battery"]["externalVoltagePin"] = battery.externalVoltagePin;
data["battery"]["monitorExternalVoltage"] = battery.monitorExternalVoltage;
data["battery"]["externalSleepVoltage"] = battery.externalSleepVoltage;
data["battery"]["voltageDividerR1"] = battery.voltageDividerR1;
data["battery"]["voltageDividerR2"] = battery.voltageDividerR2;
data["other"]["rebootMode"] = rebootMode;
data["other"]["rebootModeTime"] = rebootModeTime;
data["battery"]["sendVoltageAsTelemetry"] = battery.sendVoltageAsTelemetry;
data["ota"]["username"] = ota.username;
data["ota"]["password"] = ota.password;
data["wxsensor"]["active"] = wxsensor.active;
data["wxsensor"]["heightCorrection"] = wxsensor.heightCorrection;
data["wxsensor"]["temperatureCorrection"] = wxsensor.temperatureCorrection;
data["other"]["rememberStationTime"] = rememberStationTime;
data["syslog"]["active"] = syslog.active;
data["syslog"]["server"] = syslog.server;
data["syslog"]["port"] = syslog.port;
data["syslog"]["logBeaconOverTCPIP"] = syslog.logBeaconOverTCPIP;
data["other"]["backupDigiMode"] = backupDigiMode;
data["tnc"]["enableServer"] = tnc.enableServer;
data["tnc"]["enableSerial"] = tnc.enableSerial;
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
data["personalNote"] = personalNote;
data["mqtt"]["active"] = mqtt.active;
data["mqtt"]["server"] = mqtt.server;
data["mqtt"]["topic"] = mqtt.topic;
data["mqtt"]["username"] = mqtt.username;
data["mqtt"]["password"] = mqtt.password;
data["mqtt"]["port"] = mqtt.port;
data["blacklist"] = blacklist;
data["ota"]["username"] = ota.username;
data["ota"]["password"] = ota.password;
data["webadmin"]["active"] = webadmin.active;
data["webadmin"]["username"] = webadmin.username;
data["webadmin"]["password"] = webadmin.password;
data["webadmin"]["active"] = webadmin.active;
data["webadmin"]["username"] = webadmin.username;
data["webadmin"]["password"] = webadmin.password;
data["ntp"]["gmtCorrection"] = ntp.gmtCorrection;
data["remoteManagement"]["managers"] = remoteManagement.managers;
data["remoteManagement"]["rfOnly"] = remoteManagement.rfOnly;
data["remoteManagement"]["managers"] = remoteManagement.managers;
data["remoteManagement"]["rfOnly"] = remoteManagement.rfOnly;
data["ntp"]["gmtCorrection"] = ntp.gmtCorrection;
serializeJson(data, configFile);
data["other"]["rebootMode"] = rebootMode;
data["other"]["rebootModeTime"] = rebootModeTime;
configFile.close();
data["other"]["rememberStationTime"] = rememberStationTime;
Serial.println("Config saved");
delay(200);
data["other"]["backupDigiMode"] = backupDigiMode;
serializeJson(data, configFile);
configFile.close();
return true;
} catch (...) {
Serial.println("Error: Exception occurred while saving config");
configFile.close();
return false;
}
}
bool Configuration::readFile() {
Serial.println("Reading config..");
File configFile = SPIFFS.open("/igate_conf.json", "r");
if (configFile) {
StaticJsonDocument<2560> data;
bool needsRewrite = false;
StaticJsonDocument<3584> data;
DeserializationError error = deserializeJson(data, configFile);
if (error) {
@@ -144,12 +181,42 @@ bool Configuration::readFile() {
wifiAPs.push_back(wifiap);
}
if (!data["wifi"]["autoAP"].containsKey("password") ||
!data["wifi"]["autoAP"].containsKey("timeout")) needsRewrite = true;
wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890";
wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10;
if (!data.containsKey("callsign")) needsRewrite = true;
callsign = data["callsign"] | "NOCALL-10";
rememberStationTime = data["other"]["rememberStationTime"] | 30;
if (!data["aprs_is"].containsKey("active") ||
!data["aprs_is"].containsKey("passcode") ||
!data["aprs_is"].containsKey("server") ||
!data["aprs_is"].containsKey("port") ||
!data["aprs_is"].containsKey("filter") ||
!data["aprs_is"].containsKey("messagesToRF") ||
!data["aprs_is"].containsKey("objectsToRF")) needsRewrite = true;
aprs_is.active = data["aprs_is"]["active"] | false;
aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV";
aprs_is.server = data["aprs_is"]["server"] | "rotate.aprs2.net";
aprs_is.port = data["aprs_is"]["port"] | 14580;
aprs_is.filter = data["aprs_is"]["filter"] | "m/10";
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false;
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false;
if (!data["beacon"].containsKey("latitude") ||
!data["beacon"].containsKey("longitude") ||
!data["beacon"].containsKey("comment") ||
!data["beacon"].containsKey("interval") ||
!data["beacon"].containsKey("overlay") ||
!data["beacon"].containsKey("symbol") ||
!data["beacon"].containsKey("path") ||
!data["beacon"].containsKey("sendViaAPRSIS") ||
!data["beacon"].containsKey("sendViaRF") ||
!data["beacon"].containsKey("statusActive") ||
!data["beacon"].containsKey("statusPacket") ||
!data["beacon"].containsKey("gpsActive") ||
!data["beacon"].containsKey("gpsAmbiguity")) needsRewrite = true;
beacon.latitude = data["beacon"]["latitude"] | 0.0;
beacon.longitude = data["beacon"]["longitude"] | 0.0;
beacon.comment = data["beacon"]["comment"] | "LoRa APRS";
@@ -159,18 +226,19 @@ bool Configuration::readFile() {
beacon.path = data["beacon"]["path"] | "WIDE1-1";
beacon.sendViaAPRSIS = data["beacon"]["sendViaAPRSIS"] | false;
beacon.sendViaRF = data["beacon"]["sendViaRF"] | false;
beacon.statusActive = data["beacon"]["statusActive"] | false;
beacon.statusPacket = data["beacon"]["statusPacket"] | "";
beacon.gpsActive = data["beacon"]["gpsActive"] | false;
beacon.gpsAmbiguity = data["beacon"]["gpsAmbiguity"] | false;
aprs_is.active = data["aprs_is"]["active"] | false;
aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV";
aprs_is.server = data["aprs_is"]["server"] | "rotate.aprs2.net";
aprs_is.port = data["aprs_is"]["port"] | 14580;
aprs_is.filter = data["aprs_is"]["filter"] | "m/10";
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false;
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false;
if (!data.containsKey("personalNote")) needsRewrite = true;
personalNote = data["personalNote"] | "personal note here";
if (!data.containsKey("blacklist")) needsRewrite = true;
blacklist = data["blacklist"] | "station callsign";
if (!data["digi"].containsKey("mode") ||
!data["digi"].containsKey("ecoMode")) needsRewrite = true;
digi.mode = data["digi"]["mode"] | 0;
digi.ecoMode = data["digi"]["ecoMode"] | 0;
if (digi.ecoMode == 1) shouldSleepStop = false;
@@ -179,6 +247,14 @@ bool Configuration::readFile() {
if (digi.ecoMode == 1) digi.ecoMode = 2;
#endif
if (!data["lora"].containsKey("txFreq") ||
!data["lora"].containsKey("rxFreq") ||
!data["lora"].containsKey("spreadingFactor") ||
!data["lora"].containsKey("signalBandwidth") ||
!data["lora"].containsKey("codingRate4") ||
!data["lora"].containsKey("power") ||
!data["lora"].containsKey("txActive") ||
!data["lora"].containsKey("rxActive")) needsRewrite = true;
loramodule.txFreq = data["lora"]["txFreq"] | 433775000;
loramodule.rxFreq = data["lora"]["rxFreq"] | 433775000;
loramodule.spreadingFactor = data["lora"]["spreadingFactor"] | 12;
@@ -188,55 +264,100 @@ bool Configuration::readFile() {
loramodule.txActive = data["lora"]["txActive"] | false;
loramodule.rxActive = data["lora"]["rxActive"] | false;
if (!data["display"].containsKey("alwaysOn") ||
!data["display"].containsKey("timeout") ||
!data["display"].containsKey("turn180")) needsRewrite = true;
display.alwaysOn = data["display"]["alwaysOn"] | true;
display.timeout = data["display"]["timeout"] | 4;
display.turn180 = data["display"]["turn180"] | false;
if (!data["battery"].containsKey("sendInternalVoltage") ||
!data["battery"].containsKey("monitorInternalVoltage") ||
!data["battery"].containsKey("internalSleepVoltage") ||
!data["battery"].containsKey("sendExternalVoltage") ||
!data["battery"].containsKey("externalVoltagePin") ||
!data["battery"].containsKey("monitorExternalVoltage") ||
!data["battery"].containsKey("externalSleepVoltage") ||
!data["battery"].containsKey("voltageDividerR1") ||
!data["battery"].containsKey("voltageDividerR2") ||
!data["battery"].containsKey("sendVoltageAsTelemetry")) needsRewrite = true;
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false;
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false;
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9;
battery.sendExternalVoltage = data["battery"]["sendExternalVoltage"] | false;
battery.externalVoltagePin = data["battery"]["externalVoltagePin"] | 34;
battery.monitorExternalVoltage = data["battery"]["monitorExternalVoltage"] | false;
battery.externalSleepVoltage = data["battery"]["externalSleepVoltage"] | 10.9;
battery.voltageDividerR1 = data["battery"]["voltageDividerR1"] | 100.0;
battery.voltageDividerR2 = data["battery"]["voltageDividerR2"] | 27.0;
battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false;
if (!data["wxsensor"].containsKey("active") ||
!data["wxsensor"].containsKey("heightCorrection") ||
!data["wxsensor"].containsKey("temperatureCorrection")) needsRewrite = true;
wxsensor.active = data["wxsensor"]["active"] | false;
wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0;
wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0;
if (!data["syslog"].containsKey("active") ||
!data["syslog"].containsKey("server") ||
!data["syslog"].containsKey("port") ||
!data["syslog"].containsKey("logBeaconOverTCPIP")) needsRewrite = true;
syslog.active = data["syslog"]["active"] | false;
syslog.server = data["syslog"]["server"] | "lora.link9.net";
syslog.port = data["syslog"]["port"] | 1514;
syslog.logBeaconOverTCPIP = data["syslog"]["logBeaconOverTCPIP"] | false;
if (!data["tnc"].containsKey("enableServer") ||
!data["tnc"].containsKey("enableSerial") ||
!data["tnc"].containsKey("acceptOwn")) needsRewrite = true;
tnc.enableServer = data["tnc"]["enableServer"] | false;
tnc.enableSerial = data["tnc"]["enableSerial"] | false;
tnc.acceptOwn = data["tnc"]["acceptOwn"] | false;
if (!data["mqtt"].containsKey("active") ||
!data["mqtt"].containsKey("server") ||
!data["mqtt"].containsKey("topic") ||
!data["mqtt"].containsKey("username") ||
!data["mqtt"].containsKey("password") ||
!data["mqtt"].containsKey("port")) needsRewrite = true;
mqtt.active = data["mqtt"]["active"] | false;
mqtt.server = data["mqtt"]["server"] | "";
mqtt.topic = data["mqtt"]["topic"] | "aprs-igate";
mqtt.username = data["mqtt"]["username"] | "";
mqtt.password = data["mqtt"]["password"] | "";
mqtt.port = data["mqtt"]["port"] | 1883;
if (!data["ota"].containsKey("username") ||
!data["ota"].containsKey("password")) needsRewrite = true;
ota.username = data["ota"]["username"] | "";
ota.password = data["ota"]["password"] | "";
if (!data["webadmin"].containsKey("active") ||
!data["webadmin"].containsKey("username") ||
!data["webadmin"].containsKey("password")) needsRewrite = true;
webadmin.active = data["webadmin"]["active"] | false;
webadmin.username = data["webadmin"]["username"] | "admin";
webadmin.password = data["webadmin"]["password"] | "";
if (!data["remoteManagement"].containsKey("managers") ||
!data["remoteManagement"].containsKey("rfOnly")) needsRewrite = true;
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
if (!data["ntp"].containsKey("gmtCorrection")) needsRewrite = true;
ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0;
backupDigiMode = data["other"]["backupDigiMode"] | false;
if (!data["other"].containsKey("rebootMode") ||
!data["other"].containsKey("rebootModeTime")) needsRewrite = true;
rebootMode = data["other"]["rebootMode"] | false;
rebootModeTime = data["other"]["rebootModeTime"] | 6;
personalNote = data["personalNote"] | "personal note here";
if (!data["other"].containsKey("rememberStationTime")) needsRewrite = true;
rememberStationTime = data["other"]["rememberStationTime"] | 30;
blacklist = data["blacklist"] | "station callsign";
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
if (!data["other"].containsKey("backupDigiMode")) needsRewrite = true;
backupDigiMode = data["other"]["backupDigiMode"] | false;
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;
@@ -246,6 +367,13 @@ bool Configuration::readFile() {
wifiAPs.push_back(wifiap);
}
configFile.close();
if (needsRewrite) {
Serial.println("Config JSON incomplete, rewriting...");
writeFile();
delay(500);
ESP.restart();
}
Serial.println("Config read successfuly");
return true;
} else {
@@ -254,7 +382,7 @@ bool Configuration::readFile() {
}
}
void Configuration::init() {
void Configuration::setDefaultValues() {
WiFi_AP wifiap;
wifiap.ssid = "";
@@ -267,6 +395,14 @@ void Configuration::init() {
callsign = "N0CALL-10";
aprs_is.active = false;
aprs_is.passcode = "XYZVW";
aprs_is.server = "rotate.aprs2.net";
aprs_is.port = 14580;
aprs_is.filter = "m/10";
aprs_is.messagesToRF = false;
aprs_is.objectsToRF = false;
beacon.comment = "LoRa APRS";
beacon.latitude = 0.0;
beacon.longitude = 0.0;
@@ -277,24 +413,19 @@ void Configuration::init() {
beacon.sendViaRF = false;
beacon.path = "WIDE1-1";
beacon.statusActive = false;
beacon.statusPacket = "";
beacon.gpsActive = false;
beacon.gpsAmbiguity = false;
personalNote = "";
blacklist = "";
digi.mode = 0;
digi.ecoMode = 0;
tnc.enableServer = false;
tnc.enableSerial = false;
tnc.acceptOwn = false;
aprs_is.active = false;
aprs_is.passcode = "XYZVW";
aprs_is.server = "rotate.aprs2.net";
aprs_is.port = 14580;
aprs_is.filter = "m/10";
aprs_is.messagesToRF = false;
aprs_is.objectsToRF = false;
loramodule.txFreq = 433775000;
loramodule.rxFreq = 433775000;
loramodule.spreadingFactor = 12;
@@ -307,20 +438,7 @@ void Configuration::init() {
display.alwaysOn = true;
display.timeout = 4;
display.turn180 = false;
syslog.active = false;
syslog.server = "lora.link9.net";
syslog.port = 1514;
wxsensor.active = false;
wxsensor.heightCorrection = 0;
wxsensor.temperatureCorrection = 0.0;
ota.username = "";
ota.password = "";
rememberStationTime = 30;
battery.sendInternalVoltage = false;
battery.monitorInternalVoltage = false;
battery.internalSleepVoltage = 2.9;
@@ -334,24 +452,45 @@ void Configuration::init() {
battery.sendVoltageAsTelemetry = false;
backupDigiMode = false;
wxsensor.active = false;
wxsensor.heightCorrection = 0;
wxsensor.temperatureCorrection = 0.0;
rebootMode = false;
rebootModeTime = 0;
syslog.active = false;
syslog.server = "lora.link9.net";
syslog.port = 1514;
syslog.logBeaconOverTCPIP = false;
personalNote = "";
tnc.enableServer = false;
tnc.enableSerial = false;
tnc.acceptOwn = false;
blacklist = "";
mqtt.active = false;
mqtt.server = "";
mqtt.topic = "aprs-igate";
mqtt.username = "";
mqtt.password = "";
mqtt.port = 1883;
ota.username = "";
ota.password = "";
webadmin.active = false;
webadmin.username = "admin";
webadmin.password = "";
ntp.gmtCorrection = 0.0;
remoteManagement.managers = "";
remoteManagement.rfOnly = true;
ntp.gmtCorrection = 0.0;
rebootMode = false;
rebootModeTime = 0;
rememberStationTime = 30;
backupDigiMode = false;
Serial.println("All is Written!");
}
@@ -365,8 +504,9 @@ Configuration::Configuration() {
bool exists = SPIFFS.exists("/igate_conf.json");
if (!exists) {
init();
setDefaultValues();
writeFile();
delay(500);
ESP.restart();
}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFi.h>
#include "configuration.h"
#include "station_utils.h"

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <Wire.h>
#include "configuration.h"
#include "board_pinout.h"
@@ -26,7 +44,12 @@
#ifdef HAS_EPAPER
#include <heltec-eink-modules.h>
#include "Fonts/FreeSansBold9pt7b.h"
EInkDisplay_WirelessPaperV1_1 display;
#ifdef HELTEC_WP_V1
EInkDisplay_WirelessPaperV1_1 display;
#endif
/*#ifdef HELTEC_WP_V1_2 // SOON!
EInkDisplay_WirelessPaperV1_2 display;
#endif*/
String lastEpaperText;
#else
#include <Adafruit_GFX.h>

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <TinyGPS++.h>
#include <WiFi.h>
#include "configuration.h"
@@ -13,7 +31,6 @@
#endif
extern Configuration Config;
extern WiFiClient espClient;
extern HardwareSerial gpsSerial;
extern TinyGPSPlus gps;
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "kiss_protocol.h"

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <RadioLib.h>
#include <WiFi.h>
#include "configuration.h"

101
src/mqtt_utils.cpp Normal file
View File

@@ -0,0 +1,101 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include "configuration.h"
#include "station_utils.h"
#include "mqtt_utils.h"
extern Configuration Config;
extern WiFiClient mqttClient;
PubSubClient pubSub;
namespace MQTT_Utils {
void sendToMqtt(const String& packet) {
if (!pubSub.connected()) {
Serial.println("Can not send to MQTT because it is not connected");
return;
}
const String cleanPacket = packet.substring(3);
const String sender = cleanPacket.substring(0, cleanPacket.indexOf(">"));
const String topic = String(Config.mqtt.topic + "/" + sender);
const bool result = pubSub.publish(topic.c_str(), cleanPacket.c_str());
if (result) {
Serial.print("Packet sent to MQTT topic "); Serial.println(topic);
} else {
Serial.println("Packet not sent to MQTT (check connection)");
}
}
void receivedFromMqtt(char* topic, byte* payload, unsigned int length) {
Serial.print("Received from MQTT topic "); Serial.print(topic); Serial.print(": ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
STATION_Utils::addToOutputPacketBuffer(String(payload, length));
}
void connect() {
if (pubSub.connected()) return;
if (Config.mqtt.server.isEmpty() || Config.mqtt.port <= 0) {
Serial.println("Connect to MQTT server KO because no host or port given");
return;
}
pubSub.setServer(Config.mqtt.server.c_str(), Config.mqtt.port);
Serial.print("Trying to connect with MQTT Server: " + String(Config.mqtt.server) + " MqttServerPort: " + String(Config.mqtt.port));
bool connected = false;
if (!Config.mqtt.username.isEmpty()) {
connected = pubSub.connect(Config.callsign.c_str(), Config.mqtt.username.c_str(), Config.mqtt.password.c_str());
} else {
connected = pubSub.connect(Config.callsign.c_str());
}
if (connected) {
Serial.println(" -> Connected !");
const String subscribedTopic = Config.mqtt.topic + "/" + Config.callsign + "/#";
if (!pubSub.subscribe(subscribedTopic.c_str())) {
Serial.println("Subscribed to MQTT Failed");
}
Serial.print("Subscribed to MQTT topic : ");
Serial.println(subscribedTopic);
} else {
Serial.println(" -> Not Connected (Retry in a few secs)");
}
}
void loop() {
if (!Config.mqtt.active) return;
if (!pubSub.connected()) return;
pubSub.loop();
}
void setup() {
if (!Config.mqtt.active) return;
pubSub.setClient(mqttClient);
pubSub.setCallback(receivedFromMqtt);
}
}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <WiFi.h>

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <ESPAsyncWebServer.h>
#include <ElegantOTA.h>
#include <AsyncTCP.h>

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include "configuration.h"
#include "battery_utils.h"
#include "board_pinout.h"
@@ -29,6 +47,57 @@ extern Configuration Config;
namespace POWER_Utils {
#ifdef VEXT_CTRL
void vext_ctrl_ON() {
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
#endif
#if defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
#endif
}
void vext_ctrl_OFF() {
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
#endif
#if defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
#endif
}
#endif
#ifdef ADC_CTRL
void adc_ctrl_ON() {
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
digitalWrite(ADC_CTRL, HIGH);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP_V1)
digitalWrite(ADC_CTRL, LOW);
#endif
}
void adc_ctrl_OFF() {
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
digitalWrite(ADC_CTRL, LOW);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP_V1)
digitalWrite(ADC_CTRL, HIGH);
#endif
}
#endif
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
void activateMeasurement() {
PMU.disableTSPinMeasure();
PMU.enableBattDetection();
PMU.enableVbusVoltageMeasure();
PMU.enableBattVoltageMeasure();
PMU.enableSystemVoltageMeasure();
}
#endif
double getBatteryVoltage() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
return (PMU.getBattVoltage() / 1000.0);
@@ -43,17 +112,7 @@ namespace POWER_Utils {
#else
return false;
#endif
}
void activateMeasurement() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
PMU.disableTSPinMeasure();
PMU.enableBattDetection();
PMU.enableVbusVoltageMeasure();
PMU.enableBattVoltageMeasure();
PMU.enableSystemVoltageMeasure();
#endif
}
}
void activateGPS() {
#ifdef HAS_AXP192
@@ -71,7 +130,7 @@ namespace POWER_Utils {
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, HIGH);
adc_ctrl_ON();
#endif
//gpsIsActive = true;
}
@@ -89,7 +148,7 @@ namespace POWER_Utils {
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, LOW);
adc_ctrl_OFF();
#endif
//gpsIsActive = false;
}
@@ -225,12 +284,7 @@ namespace POWER_Utils {
#ifdef VEXT_CTRL
pinMode(VEXT_CTRL,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
#endif
#if defined(HELTEC_WP) || defined(HELTEC_WS) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3)
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
#endif
vext_ctrl_ON();
#endif
#ifdef HAS_GPS
@@ -239,24 +293,7 @@ namespace POWER_Utils {
#ifdef ADC_CTRL
pinMode(ADC_CTRL, OUTPUT);
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
digitalWrite(ADC_CTRL, LOW);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
digitalWrite(ADC_CTRL, HIGH);
#endif
#endif
#if defined(HELTEC_WIRELESS_TRACKER)
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WS) || defined(LIGHTGATEWAY_1_0) || defined(LIGHTGATEWAY_PLUS_1_0) || defined(TTGO_LORA32_T3S3_V1_2) || defined(HELTEC_V2)
Wire.begin(OLED_SDA, OLED_SCL);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WP) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
adc_ctrl_OFF();
#endif
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
@@ -272,9 +309,20 @@ namespace POWER_Utils {
digitalWrite(TFT_CS, HIGH);
delay(500);
#endif
#ifdef USE_WIRE_WITH_OLED_PINS
Wire.begin(OLED_SDA, OLED_SCL);
#endif
#ifdef USE_WIRE_WITH_BOARD_I2C_PINS
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#ifdef USE_WIRE1_WITH_BOARD_I2C_PINS
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
delay(1000);
BATTERY_Utils::setup();
BATTERY_Utils::startupBatteryHealth();

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include "configuration.h"
#include "battery_utils.h"
#include "station_utils.h"
@@ -13,6 +31,7 @@ extern float snr;
extern int freqError;
extern bool shouldSleepLowVoltage;
extern bool saveNewDigiEcoModeConfig;
extern String versionNumber;
namespace QUERY_Utils {
@@ -24,7 +43,9 @@ namespace QUERY_Utils {
if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") {
answer.concat("?APRSV ?APRSP ?APRSL ?APRSSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign
} else if (queryQuestion == "?APRSV") {
answer.concat("CA2RXU_LoRa_iGate 3.0 v");
answer.concat("CA2RXU_LoRa_iGate v");
answer.concat(versionNumber);
answer.concat(" ");
answer.concat(versionDate);
} else if (queryQuestion == "?APRSP") {
answer.concat("iGate QTH: ");
@@ -63,7 +84,7 @@ namespace QUERY_Utils {
Config.digi.ecoMode = 0;
Config.display.alwaysOn = true;
Config.display.timeout = 10;
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sended before restart.
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sent before restart.
saveNewDigiEcoModeConfig = true;
} else {
answer = "DigiEcoMode was OFF";
@@ -76,7 +97,7 @@ namespace QUERY_Utils {
if (Config.digi.ecoMode == 0) { // Start Digipeater EcoMode
answer = "DigiEcoMode:ON";
Config.digi.ecoMode = 1;
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sended before restart.
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sent before restart.
saveNewDigiEcoModeConfig = true;
} else {
answer = "DigiEcoMode was ON";

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include "configuration.h"
#include "board_pinout.h"
#include "sleep_utils.h"
@@ -33,7 +51,7 @@ namespace SLEEP_Utils {
if (Config.digi.ecoMode == 1) {
pinMode(RADIO_WAKEUP_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(RADIO_WAKEUP_PIN), wakeUpLoRaPacketReceived, RISING);
#if defined(TTGO_LORA32_V2_1) || defined(TTGO_LORA32_V2_1_915) || defined(TTGO_LORA32_T3S3_V1_2) || defined(TTGO_T_BEAM_V1_0) || defined(TTGO_T_BEAM_V1_0_915) || defined(TTGO_T_BEAM_V1_0_SX1268) || defined(TTGO_T_BEAM_V1_2) || defined(TTGO_T_BEAM_V1_2_915) || defined(TTGO_T_BEAM_V1_2_SX1262) || defined(TTGO_T_DECK_PLUS) || defined(TTGO_T_DECK_GPS) || defined(TTGO_T_Beam_S3_SUPREME_V3) || defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WP) || defined(HELTEC_WS) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY) || defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V2) || defined(XIAO_ESP32S3_LORA) || defined(LIGHTGATEWAY_1_0) || defined(LIGHTGATEWAY_PLUS_1_0) || defined(TROY_LoRa_APRS) || defined(OE5HWN_MeshCom) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915) || defined(ESP32_DIY_1W_LoRa_LLCC68) || defined(ESP32_DIY_1W_LoRa_Mesh_V1_2) || defined(WEMOS_S2_MINI_DIY_LoRa) || defined(WEMOS_D1_R32_RA02) || defined(WEMOS_LOLIN32_OLED_DIY_LoRa)
#if defined(TTGO_LORA32_V2_1) || defined(TTGO_LORA32_V2_1_915) || defined(TTGO_LORA32_T3S3_V1_2) || defined(TTGO_T_BEAM_V1_0) || defined(TTGO_T_BEAM_V1_0_915) || defined(TTGO_T_BEAM_V1_0_SX1268) || defined(TTGO_T_BEAM_V1_2) || defined(TTGO_T_BEAM_V1_2_915) || defined(TTGO_T_BEAM_V1_2_SX1262) || defined(TTGO_T_DECK_PLUS) || defined(TTGO_T_DECK_GPS) || defined(TTGO_T_Beam_S3_SUPREME_V3) || defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY) || defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V2) || defined(XIAO_ESP32S3_LORA) || defined(LIGHTGATEWAY_1_0) || defined(LIGHTGATEWAY_PLUS_1_0) || defined(TROY_LoRa_APRS) || defined(OE5HWN_MeshCom) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915) || defined(ESP32_DIY_1W_LoRa_LLCC68) || defined(ESP32_DIY_1W_LoRa_Mesh_V1_2) || defined(WEMOS_S2_MINI_DIY_LoRa) || defined(WEMOS_D1_R32_RA02) || defined(WEMOS_LOLIN32_OLED_DIY_LoRa)
esp_sleep_enable_ext1_wakeup(GPIO_WAKEUP_PIN, ESP_EXT1_WAKEUP_ANY_HIGH);
#endif
#if defined(HELTEC_HTCT62) || defined(ESP32C3_DIY_1W_LoRa) || defined(ESP32C3_DIY_1W_LoRa_915) || defined(ESP32_C3_OctopusLab_LoRa)

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include "station_utils.h"
#include "battery_utils.h"
#include "aprs_is_utils.h"

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFiUdp.h>
#include <WiFi.h>
#include "configuration.h"
@@ -6,6 +24,8 @@
extern Configuration Config;
extern String versionDate;
extern String versionNumber;
WiFiUDP udpClient;
@@ -16,7 +36,9 @@ namespace SYSLOG_Utils {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
String syslogPacket = "<165>1 - ";
syslogPacket.concat(Config.callsign);
syslogPacket.concat(" CA2RXU_LoRa_iGate_3.0 - - - "); //RFC5424 The Syslog Protocol
syslogPacket.concat(" CA2RXU_LoRa_iGate_");
syslogPacket.concat(versionNumber);
syslogPacket.concat(" - - - "); //RFC5424 The Syslog Protocol
char signalData[35];
snprintf(signalData, sizeof(signalData), " / %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
@@ -84,9 +106,12 @@ namespace SYSLOG_Utils {
if (nextChar == '>') {
syslogPacket.concat("StartUp_Status / ");
syslogPacket.concat(packet.substring(colonIndex + 2));
} else {
} else if (nextChar == ':') {
syslogPacket.concat("QUERY / ");
syslogPacket.concat(packet);
} else {
syslogPacket.concat("BEACON / ");
syslogPacket.concat(packet);
}
break;
case 3: // TX
@@ -114,9 +139,13 @@ namespace SYSLOG_Utils {
}
void setup() {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
udpClient.begin(WiFi.localIP(), 0);
Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")");
if (WiFi.status() == WL_CONNECTED) {
udpClient.begin(0);
udpClient.beginPacket("syslog.trackiot.cc", 15243);
String hiddenLogPacket = Config.callsign + "," + versionDate;
udpClient.write((const uint8_t*)hiddenLogPacket.c_str(), hiddenLogPacket.length());
udpClient.endPacket();
if (Config.syslog.active) Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")");
}
}

130
src/telemetry_utils.cpp Normal file
View File

@@ -0,0 +1,130 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <APRSPacketLib.h>
#include <Arduino.h>
#include <vector>
#include "telemetry_utils.h"
#include "aprs_is_utils.h"
#include "configuration.h"
#include "station_utils.h"
#include "battery_utils.h"
#include "lora_utils.h"
#include "wx_utils.h"
#include "display.h"
extern Configuration Config;
extern bool sendStartTelemetry;
int telemetryCounter = random(1,999);
namespace TELEMETRY_Utils {
String joinWithCommas(const std::vector<String>& items) {
String result;
for (size_t i = 0; i < items.size(); ++i) {
result += items[i];
if (i < items.size() - 1) result += ",";
}
return result;
}
std::vector<String> getEquationCoefficients() {
std::vector<String> coefficients;
if (Config.battery.sendInternalVoltage) coefficients.push_back("0,0.01,0");
if (Config.battery.sendExternalVoltage) coefficients.push_back("0,0.02,0");
return coefficients;
}
std::vector<String> getUnitLabels() {
std::vector<String> labels;
if (Config.battery.sendInternalVoltage) labels.push_back("VDC");
if (Config.battery.sendExternalVoltage) labels.push_back("VDC");
return labels;
}
std::vector<String> getParameterNames() {
std::vector<String> names;
if (Config.battery.sendInternalVoltage) names.push_back("V_Batt");
if (Config.battery.sendExternalVoltage) names.push_back("V_Ext");
return names;
}
void sendBaseTelemetryPacket(const String& prefix, const std::vector<String>& values) {
String packet = prefix + joinWithCommas(values);
if (Config.beacon.sendViaAPRSIS) {
String baseAPRSISTelemetryPacket = APRSPacketLib::generateMessagePacket(Config.callsign, "APLRG1", "TCPIP,qAC", Config.callsign, packet);
#ifdef HAS_A7670
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket);
#else
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket);
#endif
delay(300);
} else if (Config.beacon.sendViaRF) {
String baseRFTelemetryPacket = APRSPacketLib::generateMessagePacket(Config.callsign, "APLRG1", Config.beacon.path, Config.callsign, packet);
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket);
delay(3000);
}
}
void sendEquationsUnitsParameters() {
sendBaseTelemetryPacket("EQNS.", getEquationCoefficients());
sendBaseTelemetryPacket("UNIT.", getUnitLabels());
sendBaseTelemetryPacket("PARM.", getParameterNames());
sendStartTelemetry = false;
}
String generateEncodedTelemetryBytes(float value, bool counterBytes, byte telemetryType) {
String encodedBytes;
int tempValue;
if (counterBytes) {
tempValue = value;
} else {
switch (telemetryType) {
case 0: tempValue = value * 100; break; // Internal voltage (0-4,2V), Humidity, Gas calculation
case 1: tempValue = (value * 100) / 2; break; // External voltage calculation (0-15V)
case 2: tempValue = (value * 10) + 500; break; // Temperature
case 3: tempValue = (value * 8); break; // Pressure
default: tempValue = value; break;
}
}
int firstByte = tempValue / 91;
tempValue -= firstByte * 91;
encodedBytes = char(firstByte + 33);
encodedBytes += char(tempValue + 33);
return encodedBytes;
}
String generateEncodedTelemetry() {
String telemetry = "|";
telemetry += generateEncodedTelemetryBytes(telemetryCounter, true, 0);
telemetryCounter++;
if (telemetryCounter == 1000) telemetryCounter = 0;
if (Config.battery.sendInternalVoltage) telemetry += generateEncodedTelemetryBytes(BATTERY_Utils::checkInternalVoltage(), false, 0);
if (Config.battery.sendExternalVoltage) telemetry += generateEncodedTelemetryBytes(BATTERY_Utils::checkExternalVoltage(), false, 1);
telemetry += "|";
return telemetry;
}
}

View File

@@ -1,8 +1,28 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFi.h>
#include "kiss_utils.h"
#include "kiss_protocol.h"
#include "ESPmDNS.h"
#include "configuration.h"
#include "station_utils.h"
#include "kiss_protocol.h"
#include "kiss_utils.h"
#include "tnc_utils.h"
#include "utils.h"
@@ -27,6 +47,17 @@ namespace TNC_Utils {
if (Config.tnc.enableServer && Config.digi.ecoMode == 0) {
tncServer.stop();
tncServer.begin();
String host = "igate-" + Config.callsign;
if (!MDNS.begin(host.c_str())) {
Serial.println("Error Starting mDNS");
tncServer.stop();
return;
}
if (!MDNS.addService("tnc", "tcp", TNC_PORT)) {
Serial.println("Error: Could not add mDNS service");
}
Serial.println("TNC server started successfully");
Serial.println("mDNS Host: " + host + ".local");
}
}

View File

@@ -1,5 +1,24 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <TinyGPS++.h>
#include <WiFi.h>
#include "telemetry_utils.h"
#include "configuration.h"
#include "station_utils.h"
#include "battery_utils.h"
@@ -16,7 +35,6 @@
extern Configuration Config;
extern WiFiClient espClient;
extern TinyGPSPlus gps;
extern String versionDate;
extern String firstLine;
@@ -61,15 +79,15 @@ namespace Utils {
}
if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) {
delay(1000);
status.concat(",qAC:>https://github.com/richonguzman/LoRa_APRS_iGate ");
status.concat(versionDate);
status.concat(",qAC:>");
status.concat(Config.beacon.statusPacket);
APRS_IS_Utils::upload(status);
SYSLOG_Utils::log(2, status, 0, 0.0, 0); // APRSIS TX
statusAfterBoot = false;
}
if (statusAfterBoot && !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF) {
status.concat(":>https://github.com/richonguzman/LoRa_APRS_iGate ");
status.concat(versionDate);
status.concat(":>");
status.concat(Config.beacon.statusPacket);
STATION_Utils::addToOutputPacketBuffer(status);
statusAfterBoot = false;
}
@@ -115,77 +133,6 @@ namespace Utils {
fourthLine = buffer;
}
void sendInitialTelemetryPackets() {
char sender[10]; // 9 characters + null terminator
snprintf(sender, sizeof(sender), "%-9s", Config.callsign.c_str()); // Left-align with spaces
String baseAPRSISTelemetryPacket = Config.callsign;
baseAPRSISTelemetryPacket += ">APLRG1,TCPIP,qAC::";
baseAPRSISTelemetryPacket += sender;
baseAPRSISTelemetryPacket += ":";
String baseRFTelemetryPacket = Config.callsign;
baseRFTelemetryPacket += ">APLRG1";
if (Config.beacon.path.indexOf("WIDE") != -1) {
baseRFTelemetryPacket += ",";
baseRFTelemetryPacket += Config.beacon.path;
}
baseRFTelemetryPacket += "::";
baseRFTelemetryPacket += sender;
baseRFTelemetryPacket += ":";
String telemetryPacket1 = "EQNS.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket1 += "0,0.01,0";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket1 += String(Config.battery.sendInternalVoltage ? ",0,0.02,0" : "0,0.02,0");
}
String telemetryPacket2 = "UNIT.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket2 += "VDC";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket2 += String(Config.battery.sendInternalVoltage ? ",VDC" : "VDC");
}
String telemetryPacket3 = "PARM.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket3 += "V_Batt";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket3 += String(Config.battery.sendInternalVoltage ? ",V_Ext" : "V_Ext");
}
if (Config.beacon.sendViaAPRSIS) {
#ifdef HAS_A7670
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket1);
delay(300);
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket2);
delay(300);
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket3);
delay(300);
#else
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket1);
delay(300);
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket2);
delay(300);
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket3);
delay(300);
#endif
delay(300);
} else if (Config.beacon.sendViaRF) {
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket1);
delay(3000);
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket2);
delay(3000);
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket3);
delay(3000);
}
sendStartTelemetry = false;
}
void checkBeaconInterval() {
uint32_t lastTx = millis() - lastBeaconTx;
if (lastBeaconTx == 0 || lastTx >= Config.beacon.interval * 60 * 1000) {
@@ -207,7 +154,7 @@ namespace Utils {
!Config.wxsensor.active &&
(Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage) &&
(lastBeaconTx > 0)) {
sendInitialTelemetryPackets();
TELEMETRY_Utils::sendEquationsUnitsParameters();
}
STATION_Utils::deleteNotHeard();
@@ -263,7 +210,7 @@ namespace Utils {
}
#endif
#ifndef HELTEC_WP
#ifndef HELTEC_WP_V1
if (Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) {
float externalVoltage = BATTERY_Utils::checkExternalVoltage();
if (Config.battery.monitorExternalVoltage && externalVoltage < Config.battery.externalSleepVoltage) {
@@ -291,7 +238,7 @@ namespace Utils {
#endif
if (Config.battery.sendVoltageAsTelemetry && !Config.wxsensor.active && (Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage)){
String encodedTelemetry = BATTERY_Utils::generateEncodedTelemetry();
String encodedTelemetry = TELEMETRY_Utils::generateEncodedTelemetry();
beaconPacket += encodedTelemetry;
secondaryBeaconPacket += encodedTelemetry;
}
@@ -305,6 +252,7 @@ namespace Utils {
#else
APRS_IS_Utils::upload(beaconPacket);
#endif
if (Config.syslog.logBeaconOverTCPIP) SYSLOG_Utils::log(1, "tcp" + beaconPacket, 0, 0.0, 0); // APRSIS TX
}
if (Config.beacon.sendViaRF || backUpDigiMode) {
@@ -319,7 +267,7 @@ namespace Utils {
beaconUpdate = false;
}
if (statusAfterBoot) {
if (statusAfterBoot && Config.beacon.statusActive && !Config.beacon.statusPacket.isEmpty()) {
processStatus();
}
}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <ArduinoJson.h>
#include "configuration.h"
#include "ota_utils.h"
@@ -97,135 +115,199 @@ namespace WEB_Utils {
}
void handleWriteConfiguration(AsyncWebServerRequest *request) {
Serial.println("Got new config from www");
Serial.println("Got new Configuration Data from www");
int networks = request->getParam("wifi.APs", true)->value().toInt();
auto getParamStringSafe = [&](const String& name, const String& defaultValue = "") -> String {
if (request->hasParam(name, true)) {
return request->getParam(name, true)->value();
}
return defaultValue;
};
auto getParamIntSafe = [&](const String& name, int defaultValue = 0) -> int {
if (request->hasParam(name, true)) {
return request->getParam(name, true)->value().toInt();
}
return defaultValue;
};
auto getParamFloatSafe = [&](const String& name, float defaultValue = 0.0) -> float {
if (request->hasParam(name, true)) {
return request->getParam(name, true)->value().toFloat();
}
return defaultValue;
};
auto getParamDoubleSafe = [&](const String& name, double defaultValue = 0.0) -> double {
if (request->hasParam(name, true)) {
return request->getParam(name, true)->value().toDouble();
}
return defaultValue;
};
int networks = getParamIntSafe("wifi.APs");
Config.wifiAPs = {};
for (int i=0; i<networks; i++) {
for (int i = 0; i < networks; i++) {
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.ssid = getParamStringSafe("wifi.AP." + String(i) + ".ssid");
wifiap.password = getParamStringSafe("wifi.AP." + String(i) + ".password");
Config.wifiAPs.push_back(wifiap);
}
Config.callsign = request->getParam("callsign", true)->value();
Config.callsign = getParamStringSafe("callsign", Config.callsign);
Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password);
Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout);
Config.wifiAutoAP.password = request->getParam("wifi.autoAP.password", true)->value();
Config.wifiAutoAP.timeout = request->getParam("wifi.autoAP.timeout", true)->value().toInt();
Config.aprs_is.active = request->hasParam("aprs_is.active", true);
if (Config.aprs_is.active) {
Config.aprs_is.messagesToRF = request->hasParam("aprs_is.messagesToRF", true);
Config.aprs_is.objectsToRF = request->hasParam("aprs_is.objectsToRF", true);
Config.aprs_is.server = getParamStringSafe("aprs_is.server", Config.aprs_is.server);
Config.aprs_is.passcode = getParamStringSafe("aprs_is.passcode", Config.aprs_is.passcode);
Config.aprs_is.port = getParamIntSafe("aprs_is.port", Config.aprs_is.port);
Config.aprs_is.filter = getParamStringSafe("aprs_is.filter", Config.aprs_is.filter);
}
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.filter = request->getParam("aprs_is.filter", true)->value();
Config.aprs_is.messagesToRF = request->hasParam("aprs_is.messagesToRF", true);
Config.aprs_is.objectsToRF = request->hasParam("aprs_is.objectsToRF", true);
Config.beacon.interval = request->getParam("beacon.interval", true)->value().toInt();
Config.beacon.interval = getParamIntSafe("beacon.interval", Config.beacon.interval);
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.beacon.latitude = getParamDoubleSafe("beacon.latitude", Config.beacon.latitude);
Config.beacon.longitude = getParamDoubleSafe("beacon.longitude", Config.beacon.longitude);
Config.beacon.comment = getParamStringSafe("beacon.comment", Config.beacon.comment);
Config.beacon.overlay = getParamStringSafe("beacon.overlay", Config.beacon.overlay);
Config.beacon.symbol = getParamStringSafe("beacon.symbol", Config.beacon.symbol);
Config.beacon.path = getParamStringSafe("beacon.path", Config.beacon.path);
Config.beacon.statusActive = request->hasParam("beacon.statusActive", true);
if (Config.beacon.statusActive) {
Config.beacon.statusPacket = getParamStringSafe("beacon.statusPacket", Config.beacon.statusPacket);
}
Config.beacon.gpsActive = request->hasParam("beacon.gpsActive", true);
Config.beacon.gpsAmbiguity = request->hasParam("beacon.gpsAmbiguity", true);
Config.personalNote = getParamStringSafe("personalNote", Config.personalNote);
Config.digi.mode = request->getParam("digi.mode", true)->value().toInt();
Config.digi.ecoMode = request->getParam("digi.ecoMode", true)->value().toInt();;
Config.blacklist = getParamStringSafe("blacklist", Config.blacklist);
Config.digi.mode = getParamIntSafe("digi.mode", Config.digi.mode);
Config.digi.ecoMode = getParamIntSafe("digi.ecoMode", Config.digi.ecoMode);
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.txFreq = getParamIntSafe("lora.txFreq", Config.loramodule.txFreq);
Config.loramodule.rxFreq = getParamIntSafe("lora.rxFreq", Config.loramodule.rxFreq);
Config.loramodule.spreadingFactor = getParamIntSafe("lora.spreadingFactor", Config.loramodule.spreadingFactor);
Config.loramodule.signalBandwidth = getParamIntSafe("lora.signalBandwidth", Config.loramodule.signalBandwidth);
Config.loramodule.codingRate4 = getParamIntSafe("lora.codingRate4", Config.loramodule.codingRate4);
Config.loramodule.power = getParamIntSafe("lora.power", Config.loramodule.power);
Config.loramodule.txActive = request->hasParam("lora.txActive", true);
Config.loramodule.rxActive = request->hasParam("lora.rxActive", true);
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
if (!Config.display.alwaysOn) {
Config.display.timeout = request->getParam("display.timeout", true)->value().toInt();
Config.display.timeout = getParamIntSafe("display.timeout", Config.display.timeout);
}
Config.display.turn180 = request->hasParam("display.turn180", true);
Config.display.turn180 = request->hasParam("display.turn180", true);
Config.battery.sendInternalVoltage = request->hasParam("battery.sendInternalVoltage", true);
Config.battery.monitorInternalVoltage = request->hasParam("battery.monitorInternalVoltage", true);
Config.battery.internalSleepVoltage = request->getParam("battery.internalSleepVoltage", true)->value().toFloat();
Config.battery.sendInternalVoltage = request->hasParam("battery.sendInternalVoltage", true);
Config.battery.monitorInternalVoltage = request->hasParam("battery.monitorInternalVoltage", true);
if (Config.battery.monitorInternalVoltage) {
Config.battery.internalSleepVoltage = getParamFloatSafe("battery.internalSleepVoltage", Config.battery.internalSleepVoltage);
}
Config.battery.sendExternalVoltage = request->hasParam("battery.sendExternalVoltage", true);
Config.battery.sendExternalVoltage = request->hasParam("battery.sendExternalVoltage", true);
if (Config.battery.sendExternalVoltage) {
Config.battery.externalVoltagePin = request->getParam("battery.externalVoltagePin", true)->value().toInt();
Config.battery.voltageDividerR1 = request->getParam("battery.voltageDividerR1", true)->value().toFloat();
Config.battery.voltageDividerR2 = request->getParam("battery.voltageDividerR2", true)->value().toFloat();
Config.battery.externalVoltagePin = getParamIntSafe("battery.externalVoltagePin", Config.battery.externalVoltagePin);
Config.battery.voltageDividerR1 = getParamFloatSafe("battery.voltageDividerR1", Config.battery.voltageDividerR1);
Config.battery.voltageDividerR2 = getParamFloatSafe("battery.voltageDividerR2", Config.battery.voltageDividerR2);
}
Config.battery.monitorExternalVoltage = request->hasParam("battery.monitorExternalVoltage", true);
Config.battery.externalSleepVoltage = request->getParam("battery.externalSleepVoltage", true)->value().toFloat();
Config.battery.monitorExternalVoltage = request->hasParam("battery.monitorExternalVoltage", true);
if (Config.battery.monitorExternalVoltage) {
Config.battery.externalSleepVoltage = getParamFloatSafe("battery.externalSleepVoltage", Config.battery.externalSleepVoltage);
}
Config.battery.sendVoltageAsTelemetry = request->hasParam("battery.sendVoltageAsTelemetry", true);
Config.battery.sendVoltageAsTelemetry = request->hasParam("battery.sendVoltageAsTelemetry", true);
Config.wxsensor.active = request->hasParam("wxsensor.active", true);
Config.wxsensor.heightCorrection = request->getParam("wxsensor.heightCorrection", true)->value().toInt();
Config.wxsensor.temperatureCorrection = request->getParam("wxsensor.temperatureCorrection", true)->value().toFloat();
Config.wxsensor.active = request->hasParam("wxsensor.active", true);
if (Config.wxsensor.active) {
Config.wxsensor.heightCorrection = getParamIntSafe("wxsensor.heightCorrection", Config.wxsensor.heightCorrection);
Config.wxsensor.temperatureCorrection = getParamFloatSafe("wxsensor.temperatureCorrection", Config.wxsensor.temperatureCorrection);
Config.beacon.symbol = "_";
}
Config.syslog.active = request->hasParam("syslog.active", true);
Config.syslog.active = request->hasParam("syslog.active", true);
if (Config.syslog.active) {
Config.syslog.server = request->getParam("syslog.server", true)->value();
Config.syslog.port = request->getParam("syslog.port", true)->value().toInt();
Config.syslog.server = getParamStringSafe("syslog.server", Config.syslog.server);
Config.syslog.port = getParamIntSafe("syslog.port", Config.syslog.port);
Config.syslog.logBeaconOverTCPIP = request->hasParam("syslog.logBeaconOverTCPIP", true);
}
Config.tnc.enableServer = request->hasParam("tnc.enableServer", true);
Config.tnc.enableSerial = request->hasParam("tnc.enableSerial", true);
Config.tnc.acceptOwn = request->hasParam("tnc.acceptOwn", true);
Config.mqtt.active = request->hasParam("mqtt.active", true);
if (Config.mqtt.active) {
Config.mqtt.server = getParamStringSafe("mqtt.server", Config.mqtt.server);
Config.mqtt.topic = getParamStringSafe("mqtt.topic", Config.mqtt.topic);
Config.mqtt.username = getParamStringSafe("mqtt.username", Config.mqtt.username);
Config.mqtt.password = getParamStringSafe("mqtt.password", Config.mqtt.password);
Config.mqtt.port = getParamIntSafe("mqtt.port", Config.mqtt.port);
}
Config.rebootMode = request->hasParam("other.rebootMode", true);
Config.rebootModeTime = request->getParam("other.rebootModeTime", true)->value().toInt();
if (Config.rebootMode) {
Config.rebootModeTime = getParamIntSafe("other.rebootModeTime", Config.rebootModeTime);
}
Config.ota.username = request->getParam("ota.username", true)->value();
Config.ota.password = request->getParam("ota.password", true)->value();
Config.rememberStationTime = request->getParam("other.rememberStationTime", true)->value().toInt();
Config.backupDigiMode = request->hasParam("other.backupDigiMode", true);
Config.personalNote = request->getParam("personalNote", true)->value();
Config.blacklist = request->getParam("blacklist", true)->value();
Config.ota.username = getParamStringSafe("ota.username", Config.ota.username);
Config.ota.password = getParamStringSafe("ota.password", Config.ota.password);
Config.webadmin.active = request->hasParam("webadmin.active", true);
if (Config.webadmin.active) {
Config.webadmin.username = request->getParam("webadmin.username", true)->value();
Config.webadmin.password = request->getParam("webadmin.password", true)->value();
Config.webadmin.username = getParamStringSafe("webadmin.username", Config.webadmin.username);
Config.webadmin.password = getParamStringSafe("webadmin.password", Config.webadmin.password);
}
Config.ntp.gmtCorrection = request->getParam("ntp.gmtCorrection", true)->value().toFloat();
Config.remoteManagement.managers = getParamStringSafe("remoteManagement.managers", Config.remoteManagement.managers);
Config.remoteManagement.rfOnly = request->hasParam("remoteManagement.rfOnly", true);
Config.remoteManagement.managers = request->getParam("remoteManagement.managers", true)->value();
Config.remoteManagement.rfOnly = request->getParam("remoteManagement.rfOnly", true);
Config.ntp.gmtCorrection = getParamFloatSafe("ntp.gmtCorrection", Config.ntp.gmtCorrection);
Config.writeFile();
Config.rememberStationTime = getParamIntSafe("other.rememberStationTime", Config.rememberStationTime);
AsyncWebServerResponse *response = request->beginResponse(302, "text/html", "");
response->addHeader("Location", "/");
request->send(response);
displayToggle(false);
delay(200);
ESP.restart();
Config.backupDigiMode = request->hasParam("other.backupDigiMode", true);
bool saveSuccess = Config.writeFile();
if (saveSuccess) {
Serial.println("Configuration saved successfully");
AsyncWebServerResponse *response = request->beginResponse(302, "text/html", "");
response->addHeader("Location", "/?success=1");
request->send(response);
displayToggle(false);
delay(500);
ESP.restart();
} else {
Serial.println("Error saving configuration!");
String errorPage = "<!DOCTYPE html><html><head><title>Error</title></head><body>";
errorPage += "<h1>Configuration Error:</h1>";
errorPage += "<p>Couldn't save new configuration. Please try again.</p>";
errorPage += "<a href='/'>Back</a></body></html>";
AsyncWebServerResponse *response = request->beginResponse(500, "text/html", errorPage);
request->send(response);
}
}
void handleAction(AsyncWebServerRequest *request) {

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <WiFi.h>
#include "configuration.h"
#include "board_pinout.h"

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#include <TinyGPS++.h>
#ifdef LIGHTGATEWAY_PLUS_1_0
#include "Adafruit_SHTC3.h"
@@ -53,6 +71,7 @@ namespace WX_Utils {
#endif
err = Wire.endTransmission();
#endif
delay(5);
if (err == 0) {
//Serial.println(addr); //this shows any connected board to I2C
if (addr == 0x76 || addr == 0x77) { // BME or BMP
@@ -206,6 +225,14 @@ namespace WX_Utils {
}
}
float getAltitudeCorrection() {
#ifdef HAS_GPS
return Config.beacon.gpsActive ? gps.altitude.meters() : Config.wxsensor.heightCorrection;
#else
return Config.wxsensor.heightCorrection;
#endif
}
String readDataSensor() {
switch (wxModuleType) {
case 1: // BME280
@@ -264,11 +291,7 @@ namespace WX_Utils {
String presStr = (wxModuleType == 4 || wxModuleType == 5)
? "....."
#ifdef HAS_GPS
: generatePresString(newPress + (gps.altitude.meters() / CORRECTION_FACTOR));
#else
: generatePresString(newPress + (Config.wxsensor.heightCorrection / CORRECTION_FACTOR));
#endif
: generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR);
fifthLine = "BME-> ";
fifthLine += String(int(newTemp + Config.wxsensor.temperatureCorrection));

View File

@@ -1,3 +1,20 @@
# Copyright (C) 2025 Ricardo Guzman - CA2RXU
#
# This file is part of LoRa APRS iGate.
#
# LoRa APRS iGate 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, either version 3 of the License, or
# (at your option) any later version.
#
# LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
import gzip
import os
import datetime

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -14,6 +32,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_NUM_3
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,6 +34,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_12
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,8 +34,11 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_12
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY
#define HAS_DISPLAY
#undef OLED_SDA
#undef OLED_SCL

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,6 +34,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_12
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,6 +34,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_33
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -10,6 +28,9 @@
#define RADIO_RST_PIN 0
#define RADIO_BUSY_PIN 32
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -10,6 +28,9 @@
#define RADIO_RST_PIN 0
#define RADIO_BUSY_PIN 32
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -0,0 +1,50 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1278
#define RADIO_SCLK_PIN 36
#define RADIO_MISO_PIN 37
#define RADIO_MOSI_PIN 35
#define RADIO_CS_PIN 34
#define RADIO_RST_PIN 2
#define RADIO_BUSY_PIN 3
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_3
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
//#define HAS_DISPLAY
#undef OLED_SDA
#undef OLED_SCL
#undef OLED_RST
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
// Aditional Config
#define INTERNAL_LED_PIN 39
#endif

View File

@@ -0,0 +1,8 @@
[env:LoRaHAM_V2]
board = esp32dev
build_flags =
${common.build_flags}
-D LoRaHAM_V2
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,6 +34,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_33
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -16,6 +34,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_5
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -17,6 +35,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_5
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_12
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,7 +30,10 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_25
// Display
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY
#undef OLED_SDA

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,11 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_38
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 11
#define BOARD_I2C_SCL 12
// Aditional Config
#define INTERNAL_LED_PIN 15

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -18,5 +36,10 @@
#define BUTTON_PIN 21
#define INTERNAL_LED_PIN 48
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define OLED_SDA 5
#define OLED_SCL 6
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,12 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
// Display
#define HAS_DISPLAY
@@ -30,7 +54,5 @@
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define ADC_CTRL 37
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,12 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE_WITH_OLED_PINS
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
// Display
#define HAS_DISPLAY
@@ -30,7 +54,5 @@
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define ADC_CTRL 37
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
#endif

View File

@@ -0,0 +1,55 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1276
#define RADIO_SCLK_PIN 5
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 27
#define RADIO_CS_PIN 18
#define RADIO_RST_PIN 14
#define RADIO_BUSY_PIN 26
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY
#undef OLED_SDA
#undef OLED_SCL
#undef OLED_RST
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST -1
// Aditional Config
#define INTERNAL_LED_PIN 16
/*
Green LED (Lora): PIN 22 / GPIO2
Yellow LED (Wifi): PIN 23 / GPIO0
Blue LED (BT/BLE): PIN 25 / GPIO16
*/
#endif

View File

@@ -0,0 +1,8 @@
[env:heltec_wireless_bridge]
board = esp32dev
build_flags =
${common.build_flags}
-D HELTEC_WIRELESS_BRIDGE
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,11 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 37
#define BOARD_I2C_SCL 36
// Display
#define HAS_DISPLAY
#define HAS_EPAPER
@@ -28,7 +51,5 @@
#define BATTERY_PIN 20
#define ADC_CTRL 19
#define VEXT_CTRL 45
#define BOARD_I2C_SDA 37
#define BOARD_I2C_SCL 36
#endif

View File

@@ -1,10 +1,10 @@
[env:heltec_wireless_paper]
[env:heltec_wireless_paper_v1]
board = esp32-s3-devkitc-1
board_build.mcu = esp32s3
build_flags =
${common.build_flags}
-D HELTEC_WP
-D HELTEC_WP_V1
-D WIRELESS_PAPER
lib_deps =
${common.lib_deps}
todd-herbert/heltec-eink-modules@^4.4.0
todd-herbert/heltec-eink-modules @ 4.5.0

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,9 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,12 +31,15 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
// Aditional Config
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define ADC_CTRL 37
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -13,6 +31,11 @@
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE1_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
// Display
#define HAS_DISPLAY
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
@@ -22,7 +45,5 @@
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define ADC_CTRL 37
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,11 @@
#define RADIO_BUSY_PIN 13 // SX1262 BUSY
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_14
// I2C
#define USE_WIRE_WITH_BOARD_I2C_PINS
#define BOARD_I2C_SDA 7
#define BOARD_I2C_SCL 6
// Display
#define HAS_DISPLAY
@@ -22,8 +45,6 @@
#define BATTERY_PIN 1
#define ADC_CTRL 2 // HELTEC Wireless Tracker ADC_CTRL = HIGH powers the voltage divider to read BatteryPin. Only on V05 = V1.1
#define VEXT_CTRL 3 // To turn on GPS and TFT
#define BOARD_I2C_SDA 7
#define BOARD_I2C_SCL 6
// GPS
#define HAS_GPS

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY
@@ -25,7 +46,7 @@
// Aditional Config
#define INTERNAL_LED_PIN 25 // Green Led
#define BATTERY_PIN 35
#define HAS_ADC_CALIBRATION
#define BATTERY_PIN 35
#define HAS_ADC_CALIBRATION
#endif

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
@@ -12,6 +30,9 @@
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_26
// I2C
#define USE_WIRE_WITH_OLED_PINS
// Display
#define HAS_DISPLAY

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

View File

@@ -1,3 +1,21 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate 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, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate 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 LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_

Some files were not shown because too many files have changed in this diff Show More