mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-07-12 12:51:03 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb795816e1 | |||
| a046791722 | |||
| 88eda7b3fd | |||
| 03991e245d | |||
| 8a02e953c3 | |||
| 4651938cb1 |
+3
-1
@@ -33,9 +33,11 @@ lib_deps =
|
|||||||
ayushsharma82/ElegantOTA @ 3.1.5
|
ayushsharma82/ElegantOTA @ 3.1.5
|
||||||
bblanchon/ArduinoJson @ 6.21.3
|
bblanchon/ArduinoJson @ 6.21.3
|
||||||
jgromes/RadioLib @ 7.1.0
|
jgromes/RadioLib @ 7.1.0
|
||||||
|
knolleary/PubSubClient @ 2.8
|
||||||
mathieucarbou/AsyncTCP @ 3.2.5
|
mathieucarbou/AsyncTCP @ 3.2.5
|
||||||
mathieucarbou/ESPAsyncWebServer @ 3.2.3
|
mathieucarbou/ESPAsyncWebServer @ 3.2.3
|
||||||
mikalhart/TinyGPSPlus @ 1.0.3
|
mikalhart/TinyGPSPlus @ 1.0.3
|
||||||
|
richonguzman/APRSPacketLib @1.0.0
|
||||||
display_libs =
|
display_libs =
|
||||||
adafruit/Adafruit GFX Library @ 1.11.9
|
adafruit/Adafruit GFX Library @ 1.11.9
|
||||||
adafruit/Adafruit SSD1306 @ 2.5.10
|
adafruit/Adafruit SSD1306 @ 2.5.10
|
||||||
|
|||||||
@@ -90,7 +90,15 @@
|
|||||||
"remoteManagement": {
|
"remoteManagement": {
|
||||||
"managers": "",
|
"managers": "",
|
||||||
"rfOnly": true
|
"rfOnly": true
|
||||||
},
|
},
|
||||||
|
"mqtt": {
|
||||||
|
"active": false,
|
||||||
|
"server": "",
|
||||||
|
"topic": "",
|
||||||
|
"username": "",
|
||||||
|
"password": "",
|
||||||
|
"port": 1883
|
||||||
|
},
|
||||||
"other": {
|
"other": {
|
||||||
"rememberStationTime": 30,
|
"rememberStationTime": 30,
|
||||||
"backupDigiMode": false,
|
"backupDigiMode": false,
|
||||||
|
|||||||
@@ -1502,6 +1502,142 @@
|
|||||||
</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="row my-5 d-flex align-items-top">
|
||||||
<div class="col-lg-3 col-sm-12">
|
<div class="col-lg-3 col-sm-12">
|
||||||
<h5>
|
<h5>
|
||||||
|
|||||||
@@ -224,6 +224,14 @@ function loadSettings(settings) {
|
|||||||
// NTP
|
// NTP
|
||||||
document.getElementById("ntp.gmtCorrection").value = settings.ntp.gmtCorrection;
|
document.getElementById("ntp.gmtCorrection").value = settings.ntp.gmtCorrection;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
// Experimental
|
// Experimental
|
||||||
document.getElementById("other.backupDigiMode").checked = settings.other.backupDigiMode;
|
document.getElementById("other.backupDigiMode").checked = settings.other.backupDigiMode;
|
||||||
|
|
||||||
@@ -351,6 +359,32 @@ WebadminCheckbox.addEventListener("change", function () {
|
|||||||
WebadminPassword.disabled = !this.checked;
|
WebadminPassword.disabled = !this.checked;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelector(".new button").addEventListener("click", function () {
|
document.querySelector(".new button").addEventListener("click", function () {
|
||||||
const networksContainer = document.querySelector(".list-networks");
|
const networksContainer = document.querySelector(".list-networks");
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ namespace BATTERY_Utils {
|
|||||||
float checkExternalVoltage();
|
float checkExternalVoltage();
|
||||||
void startupBatteryHealth();
|
void startupBatteryHealth();
|
||||||
|
|
||||||
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType);
|
|
||||||
String generateEncodedTelemetry();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -149,6 +149,16 @@ public:
|
|||||||
bool rfOnly;
|
bool rfOnly;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MQTT {
|
||||||
|
public:
|
||||||
|
bool active;
|
||||||
|
String server;
|
||||||
|
String topic;
|
||||||
|
String username;
|
||||||
|
String password;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
class Configuration {
|
class Configuration {
|
||||||
public:
|
public:
|
||||||
String callsign;
|
String callsign;
|
||||||
@@ -173,6 +183,7 @@ public:
|
|||||||
WEBADMIN webadmin;
|
WEBADMIN webadmin;
|
||||||
NTP ntp;
|
NTP ntp;
|
||||||
REMOTE_MANAGEMENT remoteManagement;
|
REMOTE_MANAGEMENT remoteManagement;
|
||||||
|
MQTT mqtt;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void writeFile();
|
void writeFile();
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -41,7 +41,6 @@ namespace POWER_Utils {
|
|||||||
|
|
||||||
double getBatteryVoltage();
|
double getBatteryVoltage();
|
||||||
bool isBatteryConnected();
|
bool isBatteryConnected();
|
||||||
void activateMeasurement();
|
|
||||||
void activateGPS();
|
void activateGPS();
|
||||||
void deactivateGPS();
|
void deactivateGPS();
|
||||||
void activateLoRa();
|
void activateLoRa();
|
||||||
|
|||||||
@@ -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
|
||||||
+13
-13
@@ -51,6 +51,7 @@ ___________________________________________________________________*/
|
|||||||
#include "syslog_utils.h"
|
#include "syslog_utils.h"
|
||||||
#include "power_utils.h"
|
#include "power_utils.h"
|
||||||
#include "sleep_utils.h"
|
#include "sleep_utils.h"
|
||||||
|
#include "mqtt_utils.h"
|
||||||
#include "lora_utils.h"
|
#include "lora_utils.h"
|
||||||
#include "wifi_utils.h"
|
#include "wifi_utils.h"
|
||||||
#include "digi_utils.h"
|
#include "digi_utils.h"
|
||||||
@@ -66,9 +67,10 @@ ___________________________________________________________________*/
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
String versionDate = "2025-08-20";
|
String versionDate = "2025-08-27";
|
||||||
Configuration Config;
|
Configuration Config;
|
||||||
WiFiClient espClient;
|
WiFiClient aprsIsClient;
|
||||||
|
WiFiClient mqttClient;
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
HardwareSerial gpsSerial(1);
|
HardwareSerial gpsSerial(1);
|
||||||
TinyGPSPlus gps;
|
TinyGPSPlus gps;
|
||||||
@@ -118,6 +120,7 @@ void setup() {
|
|||||||
WX_Utils::setup();
|
WX_Utils::setup();
|
||||||
WEB_Utils::setup();
|
WEB_Utils::setup();
|
||||||
TNC_Utils::setup();
|
TNC_Utils::setup();
|
||||||
|
MQTT_Utils::setup();
|
||||||
#ifdef HAS_A7670
|
#ifdef HAS_A7670
|
||||||
A7670_Utils::setup();
|
A7670_Utils::setup();
|
||||||
#endif
|
#endif
|
||||||
@@ -166,11 +169,13 @@ void loop() {
|
|||||||
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
|
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
|
||||||
#else
|
#else
|
||||||
WIFI_Utils::checkWiFi();
|
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
|
#endif
|
||||||
|
|
||||||
NTP_Utils::update();
|
NTP_Utils::update();
|
||||||
TNC_Utils::loop();
|
TNC_Utils::loop();
|
||||||
|
MQTT_Utils::loop();
|
||||||
|
|
||||||
Utils::checkDisplayInterval();
|
Utils::checkDisplayInterval();
|
||||||
Utils::checkBeaconInterval();
|
Utils::checkBeaconInterval();
|
||||||
@@ -183,7 +188,7 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (packet != "") {
|
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
|
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,17 +197,12 @@ void loop() {
|
|||||||
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
|
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.tnc.enableServer) { // If TNC server enabled
|
if (Config.tnc.enableServer) TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
|
||||||
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.tnc.enableSerial) { // If Serial KISS enabled
|
|
||||||
TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.aprs_is.active) {
|
if (Config.aprs_is.active) APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
|
||||||
APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
|
|
||||||
}
|
|
||||||
|
|
||||||
STATION_Utils::processOutputPacketBuffer();
|
STATION_Utils::processOutputPacketBuffer();
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern WiFiClient espClient;
|
extern WiFiClient aprsIsClient;
|
||||||
extern uint32_t lastScreenOn;
|
extern uint32_t lastScreenOn;
|
||||||
extern String firstLine;
|
extern String firstLine;
|
||||||
extern String secondLine;
|
extern String secondLine;
|
||||||
@@ -53,17 +53,17 @@ bool passcodeValid = false;
|
|||||||
namespace APRS_IS_Utils {
|
namespace APRS_IS_Utils {
|
||||||
|
|
||||||
void upload(const String& line) {
|
void upload(const String& line) {
|
||||||
espClient.print(line + "\r\n");
|
aprsIsClient.print(line + "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect() {
|
void connect() {
|
||||||
Serial.print("Connecting to APRS-IS ... ");
|
Serial.print("Connecting to APRS-IS ... ");
|
||||||
uint8_t count = 0;
|
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...");
|
Serial.println("Didn't connect with server...");
|
||||||
delay(1000);
|
delay(1000);
|
||||||
espClient.stop();
|
aprsIsClient.stop();
|
||||||
espClient.flush();
|
aprsIsClient.flush();
|
||||||
Serial.println("Run client.stop");
|
Serial.println("Run client.stop");
|
||||||
Serial.println("Trying to connect with Server: " + String(Config.aprs_is.server) + " AprsServerPort: " + String(Config.aprs_is.port));
|
Serial.println("Trying to connect with Server: " + String(Config.aprs_is.server) + " AprsServerPort: " + String(Config.aprs_is.port));
|
||||||
count++;
|
count++;
|
||||||
@@ -110,7 +110,7 @@ namespace APRS_IS_Utils {
|
|||||||
aprsisState = "--";
|
aprsisState = "--";
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (espClient.connected()) {
|
if (aprsIsClient.connected()) {
|
||||||
aprsisState = "OK";
|
aprsisState = "OK";
|
||||||
} else {
|
} else {
|
||||||
aprsisState = "--";
|
aprsisState = "--";
|
||||||
@@ -192,7 +192,7 @@ namespace APRS_IS_Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void processLoRaPacket(const String& packet) {
|
void processLoRaPacket(const String& packet) {
|
||||||
if (passcodeValid && (espClient.connected() || modemLoggedToAPRSIS)) {
|
if (passcodeValid && (aprsIsClient.connected() || modemLoggedToAPRSIS)) {
|
||||||
if (packet.indexOf("NOGATE") == -1 && packet.indexOf("RFONLY") == -1) {
|
if (packet.indexOf("NOGATE") == -1 && packet.indexOf("RFONLY") == -1) {
|
||||||
int firstColonIndex = packet.indexOf(":");
|
int firstColonIndex = packet.indexOf(":");
|
||||||
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] != '}' && packet.indexOf("TCPIP") == -1) {
|
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] != '}' && packet.indexOf("TCPIP") == -1) {
|
||||||
@@ -371,9 +371,9 @@ namespace APRS_IS_Utils {
|
|||||||
#ifdef HAS_A7670
|
#ifdef HAS_A7670
|
||||||
A7670_Utils::listenAPRSIS();
|
A7670_Utils::listenAPRSIS();
|
||||||
#else
|
#else
|
||||||
if (espClient.connected()) {
|
if (aprsIsClient.connected()) {
|
||||||
if (espClient.available()) {
|
if (aprsIsClient.available()) {
|
||||||
String aprsisPacket = espClient.readStringUntil('\r');
|
String aprsisPacket = aprsIsClient.readStringUntil('\r');
|
||||||
aprsisPacket.trim(); // Serial.println(aprsisPacket);
|
aprsisPacket.trim(); // Serial.println(aprsisPacket);
|
||||||
processAPRSISPacket(aprsisPacket);
|
processAPRSISPacket(aprsisPacket);
|
||||||
lastRxTime = millis();
|
lastRxTime = millis();
|
||||||
@@ -383,7 +383,7 @@ namespace APRS_IS_Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void firstConnection() {
|
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();
|
connect();
|
||||||
while (!passcodeValid) {
|
while (!passcodeValid) {
|
||||||
listenAPRSIS();
|
listenAPRSIS();
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ float multiplyCorrection = 0.035;
|
|||||||
|
|
||||||
float voltageDividerTransformation = 0.0;
|
float voltageDividerTransformation = 0.0;
|
||||||
|
|
||||||
int telemetryCounter = random(1,999);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAS_ADC_CALIBRATION
|
#ifdef HAS_ADC_CALIBRATION
|
||||||
@@ -228,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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -136,6 +136,13 @@ void Configuration::writeFile() {
|
|||||||
data["remoteManagement"]["managers"] = remoteManagement.managers;
|
data["remoteManagement"]["managers"] = remoteManagement.managers;
|
||||||
data["remoteManagement"]["rfOnly"] = remoteManagement.rfOnly;
|
data["remoteManagement"]["rfOnly"] = remoteManagement.rfOnly;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
serializeJson(data, configFile);
|
serializeJson(data, configFile);
|
||||||
|
|
||||||
configFile.close();
|
configFile.close();
|
||||||
@@ -264,6 +271,13 @@ bool Configuration::readFile() {
|
|||||||
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
|
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
|
||||||
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
|
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | 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 (wifiAPs.size() == 0) { // If we don't have any WiFi's from config we need to add "empty" SSID for AUTO AP
|
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;
|
WiFi_AP wifiap;
|
||||||
wifiap.ssid = "";
|
wifiap.ssid = "";
|
||||||
@@ -382,6 +396,13 @@ void Configuration::init() {
|
|||||||
remoteManagement.managers = "";
|
remoteManagement.managers = "";
|
||||||
remoteManagement.rfOnly = true;
|
remoteManagement.rfOnly = true;
|
||||||
|
|
||||||
|
mqtt.active = false;
|
||||||
|
mqtt.server = "";
|
||||||
|
mqtt.topic = "aprs-igate";
|
||||||
|
mqtt.username = "";
|
||||||
|
mqtt.password = "";
|
||||||
|
mqtt.port = 1883;
|
||||||
|
|
||||||
Serial.println("All is Written!");
|
Serial.println("All is Written!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern WiFiClient espClient;
|
|
||||||
extern HardwareSerial gpsSerial;
|
extern HardwareSerial gpsSerial;
|
||||||
extern TinyGPSPlus gps;
|
extern TinyGPSPlus gps;
|
||||||
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/* 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));
|
||||||
|
if (pubSub.connect(Config.callsign.c_str(), Config.mqtt.username.c_str(), Config.mqtt.password.c_str())) {
|
||||||
|
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 10 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+11
-11
@@ -88,6 +88,16 @@ namespace POWER_Utils {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
|
void activateMeasurement() {
|
||||||
|
PMU.disableTSPinMeasure();
|
||||||
|
PMU.enableBattDetection();
|
||||||
|
PMU.enableVbusVoltageMeasure();
|
||||||
|
PMU.enableBattVoltageMeasure();
|
||||||
|
PMU.enableSystemVoltageMeasure();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
double getBatteryVoltage() {
|
double getBatteryVoltage() {
|
||||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
return (PMU.getBattVoltage() / 1000.0);
|
return (PMU.getBattVoltage() / 1000.0);
|
||||||
@@ -102,17 +112,7 @@ namespace POWER_Utils {
|
|||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void activateMeasurement() {
|
|
||||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
|
||||||
PMU.disableTSPinMeasure();
|
|
||||||
PMU.enableBattDetection();
|
|
||||||
PMU.enableVbusVoltageMeasure();
|
|
||||||
PMU.enableBattVoltageMeasure();
|
|
||||||
PMU.enableSystemVoltageMeasure();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void activateGPS() {
|
void activateGPS() {
|
||||||
#ifdef HAS_AXP192
|
#ifdef HAS_AXP192
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
-74
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <TinyGPS++.h>
|
#include <TinyGPS++.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include "telemetry_utils.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "station_utils.h"
|
#include "station_utils.h"
|
||||||
#include "battery_utils.h"
|
#include "battery_utils.h"
|
||||||
@@ -34,7 +35,6 @@
|
|||||||
|
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern WiFiClient espClient;
|
|
||||||
extern TinyGPSPlus gps;
|
extern TinyGPSPlus gps;
|
||||||
extern String versionDate;
|
extern String versionDate;
|
||||||
extern String firstLine;
|
extern String firstLine;
|
||||||
@@ -133,77 +133,6 @@ namespace Utils {
|
|||||||
fourthLine = buffer;
|
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() {
|
void checkBeaconInterval() {
|
||||||
uint32_t lastTx = millis() - lastBeaconTx;
|
uint32_t lastTx = millis() - lastBeaconTx;
|
||||||
if (lastBeaconTx == 0 || lastTx >= Config.beacon.interval * 60 * 1000) {
|
if (lastBeaconTx == 0 || lastTx >= Config.beacon.interval * 60 * 1000) {
|
||||||
@@ -225,7 +154,7 @@ namespace Utils {
|
|||||||
!Config.wxsensor.active &&
|
!Config.wxsensor.active &&
|
||||||
(Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage) &&
|
(Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage) &&
|
||||||
(lastBeaconTx > 0)) {
|
(lastBeaconTx > 0)) {
|
||||||
sendInitialTelemetryPackets();
|
TELEMETRY_Utils::sendEquationsUnitsParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
STATION_Utils::deleteNotHeard();
|
STATION_Utils::deleteNotHeard();
|
||||||
@@ -309,7 +238,7 @@ namespace Utils {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (Config.battery.sendVoltageAsTelemetry && !Config.wxsensor.active && (Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage)){
|
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;
|
beaconPacket += encodedTelemetry;
|
||||||
secondaryBeaconPacket += encodedTelemetry;
|
secondaryBeaconPacket += encodedTelemetry;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -238,7 +238,14 @@ namespace WEB_Utils {
|
|||||||
Config.ntp.gmtCorrection = request->getParam("ntp.gmtCorrection", true)->value().toFloat();
|
Config.ntp.gmtCorrection = request->getParam("ntp.gmtCorrection", true)->value().toFloat();
|
||||||
|
|
||||||
Config.remoteManagement.managers = request->getParam("remoteManagement.managers", true)->value();
|
Config.remoteManagement.managers = request->getParam("remoteManagement.managers", true)->value();
|
||||||
Config.remoteManagement.rfOnly = request->getParam("remoteManagement.rfOnly", true);
|
Config.remoteManagement.rfOnly = request->hasParam("remoteManagement.rfOnly", true);
|
||||||
|
|
||||||
|
Config.mqtt.active = request->hasParam("mqtt.active", true);
|
||||||
|
Config.mqtt.server = request->getParam("mqtt.server", true)->value();
|
||||||
|
Config.mqtt.topic = request->getParam("mqtt.topic", true)->value();
|
||||||
|
Config.mqtt.username = request->getParam("mqtt.username", true)->value();
|
||||||
|
Config.mqtt.password = request->getParam("mqtt.password", true)->value();
|
||||||
|
Config.mqtt.port = request->getParam("mqtt.port", true)->value().toInt();
|
||||||
|
|
||||||
Config.writeFile();
|
Config.writeFile();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user