diff --git a/tinyGS/src/ConfigManager/ConfigManager.cpp b/tinyGS/src/ConfigManager/ConfigManager.cpp
index abf799fa..c4e5cf75 100644
--- a/tinyGS/src/ConfigManager/ConfigManager.cpp
+++ b/tinyGS/src/ConfigManager/ConfigManager.cpp
@@ -23,6 +23,7 @@
#include "../Radio/Radio.h"
#include "../Display/graphics.h"
#include "../Mqtt/MQTT_credentials.h"
+#include "../Power/Battery.h"
#include "ArduinoJson.h"
#if ARDUINOJSON_USE_LONG_LONG == 0 && !PLATFORMIO
#error "Using Arduino IDE is not recommended, please follow this guide https://github.com/G4lile0/tinyGS/wiki/Arduino-IDE or edit /ArduinoJson/src/ArduinoJson/Configuration.hpp and amend to #define ARDUINOJSON_USE_LONG_LONG 1 around line 68"
@@ -50,39 +51,39 @@ na SX1281 2.4–2.5Ghz 130 5.5 2000 0.476-202
ConfigManager::ConfigManager()
: IotWebConf2(thingName, &dnsServer, &server, initialApPassword, configVersion), server(80), gsConfigHtmlFormatProvider(*this), boards{
- //OLED_add, OLED_SDA, OLED_SCL, OLED_RST, PROG_BUTTON, BOARD_LED, L_SX127X?, L_NSS, L_DI00, L_DI01, L_BUSSY, L_RST, L_MISO, L_MOSI, L_SCK, L_TCXO_V, RX_EN, TX_EN, BOARD
+ //OLED_add, OLED_SDA, OLED_SCL, OLED_RST, PROG_BUTTON, BOARD_LED, L_SX127X?, L_NSS, L_DI00, L_DI01, L_BUSSY, L_RST, L_MISO, L_MOSI, L_SCK, L_TCXO_V, RX_EN, TX_EN, ADC_CTL, BAT_AIN, VBAT_SCALE, BOARD
#if CONFIG_IDF_TARGET_ESP32S3
- { 0x3c, 17, 18, 21, 0, 35, RADIO_SX1262, 8, UNUSED, 14, 13, 12, 11, 10, 9, 1.6f, UNUSED, UNUSED, "150–960Mhz - HELTEC LORA32 V3 SX1262" }, // SX1262
- { 0x3c, 17, 18, UNUSED, 0, 35, RADIO_SX1278, 8, 6, 14, UNUSED, 12, 11, 10, 9, 0.0f, UNUSED, UNUSED, "Custom ESP32-S3 433MHz SX1278" }, // SX1278 @g4lile0
- { 0x3c, 17, 18, UNUSED, 0, 3, RADIO_SX1262, 10, UNUSED, 1, 4, 5, 13, 11, 12, 1.6f, UNUSED, UNUSED, "433 Mhz TTGO T-Beam Sup SX1262 V1.0" }, // SX1268 @ Stephen
- { 0x3c, 17, 18, UNUSED, 0, 37, RADIO_SX1280, 7, UNUSED, 9, UNUSED, 8, 3, 6, 5, 0.0f, 21, 10, "2.4Ghz LILYGO SX1280" }, // SX1280 @ K4KDR
+ { 0x3c, 17, 18, 21, 0, 35, RADIO_SX1262, 8, UNUSED, 14, 13, 12, 11, 10, 9, 1.6f, UNUSED, UNUSED, 37, 1, 5.1205f, "150–960Mhz - HELTEC LORA32 V3 SX1262" }, // SX1262
+ { 0x3c, 17, 18, UNUSED, 0, 35, RADIO_SX1278, 8, 6, 14, UNUSED, 12, 11, 10, 9, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "Custom ESP32-S3 433MHz SX1278" }, // SX1278 @g4lile0
+ { 0x3c, 17, 18, UNUSED, 0, 3, RADIO_SX1262, 10, UNUSED, 1, 4, 5, 13, 11, 12, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433 Mhz TTGO T-Beam Sup SX1262 V1.0" }, // SX1268 @ Stephen
+ { 0x3c, 17, 18, UNUSED, 0, 37, RADIO_SX1280, 7, UNUSED, 9, UNUSED, 8, 3, 6, 5, 0.0f, 21, 10, UNUSED, UNUSED, UNUSED, "2.4Ghz LILYGO SX1280" }, // SX1280 @ K4KDR
#elif CONFIG_IDF_TARGET_ESP32C3
- { 0x3c, 0, 1, UNUSED, 20, 21, RADIO_SX1262, 8, UNUSED, 3, 4, 5, 6, 7, 10, 1.6f, UNUSED, UNUSED, "433MHz HELTEC LORA32 HT-CT62 SX1262" }, // SX1262 @gargomoma
- { 0x3c, 0, 1, UNUSED, 20, 21, RADIO_SX1278, 8, 4, UNUSED, UNUSED, 5, 6, 7, 10, 0.0f, UNUSED, UNUSED, "Custom ESP32-C3 433MHz SX1278" }, // SX1278 @gargomoma
+ { 0x3c, 0, 1, UNUSED, 20, 21, RADIO_SX1262, 8, UNUSED, 3, 4, 5, 6, 7, 10, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz HELTEC LORA32 HT-CT62 SX1262" }, // SX1262 @gargomoma
+ { 0x3c, 0, 1, UNUSED, 20, 21, RADIO_SX1278, 8, 4, UNUSED, UNUSED, 5, 6, 7, 10, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "Custom ESP32-C3 433MHz SX1278" }, // SX1278 @gargomoma
#else
- { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1278, 18, 26, 12, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz HELTEC WiFi LoRA 32 V1" }, // SX1278 @4m1g0
- { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1276, 18, 26, 12, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "863-928MHz HELTEC WiFi LoRA 32 V1" }, // SX1276
- { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1278, 18, 26, 35, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz HELTEC WiFi LoRA 32 V2" }, // SX1278 @4m1g0
- { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1276, 18, 26, 35, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "863-928MHz HELTEC WiFi LoRA 32 V2" }, // SX1276
- { 0x3c, 4, 15, 16, 0, 2, RADIO_SX1278, 18, 26, UNUSED, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433Mhz TTGO LoRa 32 v1" }, // SX1278 @g4lile0
- { 0x3c, 4, 15, 16, 0, 2, RADIO_SX1276, 18, 26, UNUSED, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz TTGO LoRa 32 v1" }, // SX1276
- { 0x3c, 21, 22, UNUSED, 0, 22, RADIO_SX1278, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz TTGO LoRA 32 v2" }, // SX1278 @TCRobotics
- { 0x3c, 21, 22, 16, 0, 22, RADIO_SX1276, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz TTGO LoRA 32 v2" }, // SX1276
- { 0x3c, 21, 22, 16, 39, 22, RADIO_SX1278, 18, 26, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz T-BEAM + OLED" }, // SX1278
- { 0x3c, 21, 22, 16, 39, 22, RADIO_SX1276, 18, 26, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz T-BEAM + OLED" }, // SX1276
- { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 27, 26, 14, 19, 23, 18, 0.0f, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x (Crystal)" }, // SX1268 @4m1g0, @lillefyr
- { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1268, 18, UNUSED, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "TTGO LoRa 32 V2 Modified with module SX126x (crystal)" }, // SX1268 @TCRobotics
- { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 2, 13, 26, 19, 23, 18, 1.6f, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x DRF1268T (TCX0) (5, 2, 26, 13)" }, // SX1268 @sdey76
- { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 26, 12, 14, 19, 23, 18, 1.6f, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x DRF1268T (TCX0) (5, 26, 14, 12)" }, // SX1268 @imants
- { 0x3c, 21, 22, UNUSED, 38, 22, RADIO_SX1278, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz T-BEAM V1.0 + OLED" }, // SX1278 @fafu
- { 0x3c, 21, 22, 16, 0, 2, RADIO_SX1268, 5, UNUSED, 34, 32, 14, 19, 27, 18, 1.6f, UNUSED, UNUSED, "433MHz FOSSA 1W Ground Station" }, // SX1268 @jgromes
- { 0x3c, 21, 22, 16, 0, 2, RADIO_SX1276, 5, UNUSED, 34, 32, 14, 19, 27, 18, 1.6f, UNUSED, UNUSED, "868-915MHz FOSSA 1W Ground Station" }, //SX1276 @jgromes
- { 0x3c, 21, 22, UNUSED, 0, 22, RADIO_SX1280, 5, 26, 34, 32, 14, 19, 27, 18, 0.0f, UNUSED, UNUSED, "2.4GHz ESP32 + SX1280" }, //SX1280 @g4lile0
- { 0x3c, 21, 22, UNUSED, 38, 22, RADIO_SX1276, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz T-BEAM V1.0 + OLED" }, // SX1276 @fafu
- { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1278, 18, 26, 33, UNUSED, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, "433MHz LILYGO T3_V1.6.1" }, // SX1278
- { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1276, 18, 26, 33, UNUSED, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz LILYGO T3_V1.6.1" }, // SX1276
- { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1276, 18, 26, UNUSED, 32, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, "868-915MHz LILYGO T3_V1.6.1 TCXO" }, // SX1276
- { 0x3c, 21, 22, UNUSED, 38, 4, RADIO_SX1268, 18, 26, 33, 32, 23, 19, 27, 5, 1.6f, UNUSED, UNUSED, "433 Mhz T-Beam SX1268 V1.0" }, // SX1268 @ Antonio
+ { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1278, 18, 26, 12, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz HELTEC WiFi LoRA 32 V1" }, // SX1278 @4m1g0
+ { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1276, 18, 26, 12, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "863-928MHz HELTEC WiFi LoRA 32 V1" }, // SX1276
+ { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1278, 18, 26, 35, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, 21, 37, 0.00283f, "433MHz HELTEC WiFi LoRA 32 V2" }, // SX1278 @4m1g0
+ { 0x3c, 4, 15, 16, 0, 25, RADIO_SX1276, 18, 26, 35, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, 21, 37, 0.00283f, "863-928MHz HELTEC WiFi LoRA 32 V2" }, // SX1276
+ { 0x3c, 4, 15, 16, 0, 2, RADIO_SX1278, 18, 26, UNUSED, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433Mhz TTGO LoRa 32 v1" }, // SX1278 @g4lile0
+ { 0x3c, 4, 15, 16, 0, 2, RADIO_SX1276, 18, 26, UNUSED, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz TTGO LoRa 32 v1" }, // SX1276
+ { 0x3c, 21, 22, UNUSED, 0, 22, RADIO_SX1278, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz TTGO LoRA 32 v2" }, // SX1278 @TCRobotics
+ { 0x3c, 21, 22, 16, 0, 22, RADIO_SX1276, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz TTGO LoRA 32 v2" }, // SX1276
+ { 0x3c, 21, 22, 16, 39, 22, RADIO_SX1278, 18, 26, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz T-BEAM + OLED" }, // SX1278
+ { 0x3c, 21, 22, 16, 39, 22, RADIO_SX1276, 18, 26, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz T-BEAM + OLED" }, // SX1276
+ { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 27, 26, 14, 19, 23, 18, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x (Crystal)" }, // SX1268 @4m1g0, @lillefyr
+ { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1268, 18, UNUSED, 33, 32, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "TTGO LoRa 32 V2 Modified with module SX126x (crystal)" }, // SX1268 @TCRobotics
+ { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 2, 13, 26, 19, 23, 18, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x DRF1268T (TCX0) (5, 2, 26, 13)" }, // SX1268 @sdey76
+ { 0x3c, 21, 22, 16, 0, 25, RADIO_SX1268, 5, UNUSED, 26, 12, 14, 19, 23, 18, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "Custom ESP32 Wroom + SX126x DRF1268T (TCX0) (5, 26, 14, 12)" }, // SX1268 @imants
+ { 0x3c, 21, 22, UNUSED, 38, 22, RADIO_SX1278, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz T-BEAM V1.0 + OLED" }, // SX1278 @fafu
+ { 0x3c, 21, 22, 16, 0, 2, RADIO_SX1268, 5, UNUSED, 34, 32, 14, 19, 27, 18, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz FOSSA 1W Ground Station" }, // SX1268 @jgromes
+ { 0x3c, 21, 22, 16, 0, 2, RADIO_SX1276, 5, UNUSED, 34, 32, 14, 19, 27, 18, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz FOSSA 1W Ground Station" }, //SX1276 @jgromes
+ { 0x3c, 21, 22, UNUSED, 0, 22, RADIO_SX1280, 5, 26, 34, 32, 14, 19, 27, 18, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "2.4GHz ESP32 + SX1280" }, //SX1280 @g4lile0
+ { 0x3c, 21, 22, UNUSED, 38, 22, RADIO_SX1276, 18, 26, 33, UNUSED, 14, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz T-BEAM V1.0 + OLED" }, // SX1276 @fafu
+ { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1278, 18, 26, 33, UNUSED, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433MHz LILYGO T3_V1.6.1" }, // SX1278
+ { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1276, 18, 26, 33, UNUSED, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz LILYGO T3_V1.6.1" }, // SX1276
+ { 0x3c, 21, 22, UNUSED, 0, 25, RADIO_SX1276, 18, 26, UNUSED, 32, 23, 19, 27, 5, 0.0f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "868-915MHz LILYGO T3_V1.6.1 TCXO" }, // SX1276
+ { 0x3c, 21, 22, UNUSED, 38, 4, RADIO_SX1268, 18, 26, 33, 32, 23, 19, 27, 5, 1.6f, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, "433 Mhz T-Beam SX1268 V1.0" }, // SX1268 @ Antonio
#endif
@@ -260,7 +261,17 @@ void ConfigManager::handleDashboard()
s += "
| MQTT Server | " + String(status.mqtt_connected ? "CONNECTED" : "NOT CONNECTED") + " |
";
s += "| WiFi RSSI | " + String(WiFi.isConnected() ? "CONNECTED" : "NOT CONNECTED") + " |
";
s += "| Radio | " + String(Radio::getInstance().isReady() ? "READY" : "NOT READY") + " |
";
- s += "| Noise floor | " + String(status.modeminfo.currentRssi) + " |
";
+ s += "| Noise floor | " + String(status.modeminfo.currentRssi) + " |
";
+ if (status.vbat > 0) {
+ if(getBatteryPercentage() > 100.0f) { // Charging
+ s += "| Power | USB " + String(status.vbat) + "V |
";
+ } else {
+ s += "| Power | Bat " + String(getBatteryPercentage(), 0) + "%" + String(status.vbat) + "V |
";
+ }
+ } else {
+ // Empty if battery monitoring not enabled
+ s += " | |
";
+ }
s += F("");
@@ -507,6 +518,16 @@ void ConfigManager::handleRefreshWorldmap()
if (status.radio_ready)
radio.currentRssi ();
data_string += String(status.modeminfo.currentRssi) + ",";
+ if (status.vbat > 0) {
+ if(getBatteryPercentage() > 100.0f) { // Charging
+ data_string += "USB " + String(status.vbat) + "V,";
+ } else {
+ data_string += "Bat " + String(getBatteryPercentage(), 0) + "% " + String(status.vbat) + "V,";
+ }
+ } else {
+ // if battery monitoring not enabled
+ data_string += ",";
+ }
// sat_info
@@ -547,9 +568,8 @@ else {
else {
timeStr[0] = '\0';
}
- data_string += String(timeStr) + "," ;
+ data_string += String(timeStr) + "," ;
-
// last packet received data (for lastpacket id table data)
data_string += String(status.lastPacketInfo.time) + ",";
data_string += String(status.lastPacketInfo.rssi) + ",";
@@ -753,8 +773,8 @@ void ConfigManager::printConfig()
Log::debug(PSTR("tz: %s\nOLED Bright: %u\nTX %s"), getTZ(), getOledBright(), getAllowTx() ? "Enable" : "Disable");
if (getBoardTemplate()[0] != '\0')
Log::debug(PSTR("board_template: %s"),getBoardTemplate());
- else
- Log::debug(PSTR("board: %u --> %s\n:"),getBoard(), boards[getBoard()].BOARD.c_str());
+ else
+ Log::debug(PSTR("board_template: %s"), boardTemplateToJSON(boards[getBoard()]).c_str() );
}
// void ConfigManager::setMqttServer(const char *server)
@@ -1022,6 +1042,51 @@ bool ConfigManager::parseBoardTemplate(board_t &board)
board.TX_EN = doc["TXEN"];
else
board.TX_EN = UNUSED;
+ if (doc.containsKey("ADC_CTL"))
+ board.ADC_CTL = doc["ADC_CTL"];
+ else
+ board.ADC_CTL = UNUSED;
+ if (doc.containsKey("VBAT"))
+ board.VBAT_AIN = doc["VBAT"];
+ else
+ board.VBAT_AIN = UNUSED;
+ if (doc.containsKey("VBAT_SCALE"))
+ board.VBAT_SCALE = doc["VBAT_SCALE"];
+ else
+ board.VBAT_SCALE = UNUSED;
return true;
}
+
+String ConfigManager::boardTemplateToJSON(board_t &board)
+{
+ size_t size = JSON_OBJECT_SIZE(22) + 256;
+ DynamicJsonDocument doc(size);
+ String output;
+
+ doc["aADDR"] = board.OLED__address;
+ doc["oSDA"] = board.OLED__SDA;
+ doc["oSCL"] = board.OLED__SCL;
+ doc["oRST"] = board.OLED__RST;
+ doc["pBut"] = board.PROG__BUTTON;
+ doc["led"] = board.BOARD_LED;
+ doc["radio"] = board.L_radio;
+ doc["lNSS"] = board.L_NSS;
+ doc["lDIO0"] = board.L_DI00;
+ doc["lDIO1"] = board.L_DI01;
+ doc["lBUSSY"] = board.L_BUSSY;
+ doc["lRST"] = board.L_RST;
+ doc["lMISO"] = board.L_MISO;
+ doc["lMOSI"] = board.L_MOSI;
+ doc["lSCK"] = board.L_SCK;
+ doc["lTCXOV"] = board.L_TCXO_V;
+ doc["RXEN"] = board.RX_EN;
+ doc["TXEN"] = board.TX_EN;
+ doc["ADC_CTL"] = board.ADC_CTL;
+ doc["VBAT"] = board.VBAT_AIN;
+ doc["VBAT_SCALE"] = board.VBAT_SCALE;
+ doc["name"] = board.BOARD;
+
+ serializeJson(doc, output);
+ return output;
+}
diff --git a/tinyGS/src/ConfigManager/ConfigManager.h b/tinyGS/src/ConfigManager/ConfigManager.h
index b56dfb1a..3c6f7781 100644
--- a/tinyGS/src/ConfigManager/ConfigManager.h
+++ b/tinyGS/src/ConfigManager/ConfigManager.h
@@ -126,18 +126,21 @@ struct board_t
uint8_t L_MISO;
uint8_t L_MOSI;
uint8_t L_SCK;
- float L_TCXO_V;
+ float L_TCXO_V;
uint8_t RX_EN;
uint8_t TX_EN;
- String BOARD;
+ uint8_t ADC_CTL; // GPIO pin to enable ADC reading
+ uint8_t VBAT_AIN; // GPIO pin for VBAT monitoring
+ float VBAT_SCALE; // potential divider between battery and GPIO pin
+ String BOARD;
board_t() = default;
board_t(uint8_t oled_addr, uint8_t oled_sda, uint8_t oled_scl, uint8_t oled_rst, uint8_t prog_btn, uint8_t board_led,
uint8_t l_radio, uint8_t l_nss, uint8_t l_di00, uint8_t l_di01, uint8_t l_bussy, uint8_t l_rst, uint8_t l_miso, uint8_t l_mosi, uint8_t l_sck,
- float l_tcxo_v, uint8_t rx_en, uint8_t tx_en, String board_name)
+ float l_tcxo_v, uint8_t rx_en, uint8_t tx_en, uint8_t adc_ctl, uint8_t vbat_ain, float vbat_scale, String board_name)
: OLED__address(oled_addr), OLED__SDA(oled_sda), OLED__SCL(oled_scl), OLED__RST(oled_rst), PROG__BUTTON(prog_btn), BOARD_LED(board_led),
L_radio(l_radio), L_NSS(l_nss), L_DI00(l_di00), L_DI01(l_di01), L_BUSSY(l_bussy), L_RST(l_rst), L_MISO(l_miso), L_MOSI(l_mosi), L_SCK(l_sck),
- L_TCXO_V(l_tcxo_v), RX_EN(rx_en), TX_EN(tx_en), BOARD(board_name) {}
+ L_TCXO_V(l_tcxo_v), RX_EN(rx_en), TX_EN(tx_en), ADC_CTL(adc_ctl), VBAT_AIN(vbat_ain), VBAT_SCALE(vbat_scale), BOARD(board_name) {}
};
const uint8_t UNUSED = -1;
@@ -306,6 +309,7 @@ class ConfigManager : public IotWebConf2
void parseAdvancedConf();
void parseModemStartup();
bool parseBoardTemplate(board_t &);
+ String boardTemplateToJSON(board_t &board);
std::function formValidatorStd;
DNSServer dnsServer;
diff --git a/tinyGS/src/ConfigManager/html.h b/tinyGS/src/ConfigManager/html.h
index 560b08c5..c5eb1408 100644
--- a/tinyGS/src/ConfigManager/html.h
+++ b/tinyGS/src/ConfigManager/html.h
@@ -71,7 +71,7 @@ const char BOARD_VALUES[][BOARD_LENGTH] PROGMEM = {"0", "1" };
const char BOARD_VALUES[][BOARD_LENGTH] PROGMEM = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" , "21", "22"};
#endif
-const char IOTWEBCONF_DASHBOARD_STYLE_INNER[] PROGMEM = "table{margin:20px auto;}h3{text-align:center;}.card{height:12em;margin:10px;text-align:left;font-family:Arial;border:3px groove;border-radius:0.3rem;display:inline-block;padding:10px;min-width:260px;}td{padding:0 10px;}textarea{resize:vertical;width:100%;margin:0;height:318px;padding:5px;overflow:auto;}#c1{width:98%;padding:5px;}#t1{width:98%}.console{display:inline-block;text-align:center;margin:10px 0;width:98%;max-width:1080px;}.G{color:green;}.R{color:red}";
+const char IOTWEBCONF_DASHBOARD_STYLE_INNER[] PROGMEM = "table{margin:20px auto;}h3{text-align:center;}.card{height:13em;margin:10px;text-align:left;font-family:Arial;border:3px groove;border-radius:0.3rem;display:inline-block;padding:10px;min-width:260px;}td{padding:0 10px;}textarea{resize:vertical;width:100%;margin:0;height:318px;padding:5px;overflow:auto;}#c1{width:98%;padding:5px;}#t1{width:98%}.console{display:inline-block;text-align:center;margin:10px 0;width:98%;max-width:1080px;}.G{color:green;}.R{color:red}";
const char IOTWEBCONF_DASHBOARD_BODY_INNER[] PROGMEM = "\n";
const char IOTWEBCONF_CONSOLE_BODY_INNER[] PROGMEM = "
\n";
const char IOTWEBCONF_CONSOLE_SCRIPT[] PROGMEM = "var x=null,lt,to,tp,pc='';var sn=0,id=0;function f(p){var c,o='',t;clearTimeout(lt);t = document.getElementById('t1');if (p==1) {c =document.getElementById('c1');o='&c1='+encodeURIComponent(c.value);c.value='';t.scrollTop=99999;sn=t.scrollTop;}if (t.scrollTop >= sn){if (x!=null){x.abort();}x=new XMLHttpRequest();x.onreadystatechange=function() {if(x.readyState==4&&x.status==200){var z,d;var a=x.responseText;console.log(a);id=a.substr(0,a.indexOf('\\n'));z=a.substr(a.indexOf('\\n')+1);if(z.length>0){t.value+=z;}t.scrollTop=99999;sn=t.scrollTop;}};x.open('GET','cs?c2='+id+o,true);x.send();}lt=setTimeout(f,2345);return false;}window.addEventListener('load', f);";
@@ -82,5 +82,5 @@ const char ADVANCED_CONFIG_SCRIPT[] PROGMEM =
"function tableDoneHandler(btn){var tbd=document.getElementById('current-table'); var ds=tableDictString(tbd); current_ctrl.value=ds; document.getElementById('dt-' + current_id).remove(); current_ctrl=null; current_id=null; }"
"function editElementDict(ed){if (current_ctrl===null){var ph=ed.getAttribute('placeholder'); var dstring = ed.value!='' ? ed.value : ph; if(dstring !== ''){ current_id=ed.id; var dict = JSON.parse(dstring); var tblhtml = '
' + dictTable(dict) + '
'; ed.insertAdjacentHTML('afterend', tblhtml); current_ctrl=ed; } } }"
"var current_id, current_ctrl=null; window.addEventListener('load', function() {setup_click('board_template'); setup_click('modem_startup');});";
-const char IOTWEBCONF_WORLDMAP_SCRIPT[] PROGMEM ="var wmx=null,wmt;function wmf(p){var sp,mc,gs,lp;clearTimeout(wmt);wmx=new XMLHttpRequest();wmx.onreadystatechange=function() {if(wmx.readyState==4&&x.status==200){var wma=wmx.responseText;var wmp = wma.split(',');sp=document.getElementById('wmsatpos');sp.setAttribute('cx', wmp[0]);sp.setAttribute('cy', wmp[1]);mc=document.getElementById('modemconfig');for(let r=0;r<6;r++){mc.rows[r].cells[1].innerHTML=wmp[r+2]};if(wmp[2]=='LoRa'){mc.rows[3].cells[0].innerHTML='Spreading Factor ';mc.rows[4].cells[0].innerHTML='Coding Rate ';}else{mc.rows[3].cells[0].innerHTML='Bitrate ';mc.rows[4].cells[0].innerHTML='Frequency dev ';};gs=document.getElementById('gsstatus');for(let r=0;r<6;r++){gs.rows[r].cells[1].innerHTML=wmp[r+8];};sd=document.getElementById('satdata');for(let r=0;r<6;r++){sd.rows[r].cells[1].innerHTML=wmp[r+14];};lp=document.getElementById('lastpacket');for(let r=0;r<4;r++){lp.rows[r].cells[1].innerHTML=wmp[r+20];};lp.rows[4].cells[0].innerHTML=wmp[24];}};wmx.open('GET','wm',true);wmx.send();wmt=setTimeout(wmf,5000);return false;}window.addEventListener('load', wmf);";
-const char IOTWEBCONF_CONFIG_STYLE_INNER[] PROGMEM = " fieldset[id='Board config'] div:nth-of-type(3) ~ div { display:none}";
\ No newline at end of file
+const char IOTWEBCONF_WORLDMAP_SCRIPT[] PROGMEM ="var wmx=null,wmt;function wmf(p){var sp,mc,gs,lp;clearTimeout(wmt);wmx=new XMLHttpRequest();wmx.onreadystatechange=function() {if(wmx.readyState==4&&x.status==200){var wma=wmx.responseText;var wmp = wma.split(',');sp=document.getElementById('wmsatpos');sp.setAttribute('cx', wmp[0]);sp.setAttribute('cy', wmp[1]);mc=document.getElementById('modemconfig');for(let r=0;r<6;r++){mc.rows[r].cells[1].innerHTML=wmp[r+2]};if(wmp[2]=='LoRa'){mc.rows[3].cells[0].innerHTML='Spreading Factor ';mc.rows[4].cells[0].innerHTML='Coding Rate ';}else{mc.rows[3].cells[0].innerHTML='Bitrate ';mc.rows[4].cells[0].innerHTML='Frequency dev ';};gs=document.getElementById('gsstatus');for(let r=0;r<7;r++){gs.rows[r].cells[1].innerHTML=wmp[r+8];};sd=document.getElementById('satdata');for(let r=0;r<6;r++){sd.rows[r].cells[1].innerHTML=wmp[r+15];};lp=document.getElementById('lastpacket');for(let r=0;r<4;r++){lp.rows[r].cells[1].innerHTML=wmp[r+21];};lp.rows[4].cells[0].innerHTML=wmp[25];}};wmx.open('GET','wm',true);wmx.send();wmt=setTimeout(wmf,5000);return false;}window.addEventListener('load', wmf);";
+const char IOTWEBCONF_CONFIG_STYLE_INNER[] PROGMEM = " fieldset[id='Board config'] div:nth-of-type(3) ~ div { display:none}";
diff --git a/tinyGS/src/Display/Display.cpp b/tinyGS/src/Display/Display.cpp
index c4ffbedb..ee9a79dc 100644
--- a/tinyGS/src/Display/Display.cpp
+++ b/tinyGS/src/Display/Display.cpp
@@ -22,6 +22,7 @@
#include "../ConfigManager/ConfigManager.h"
#include "../Mqtt/MQTT_credentials.h"
#include "../Logger/Logger.h"
+#include "../Power/Battery.h"
SSD1306* display;
OLEDDisplayUi* ui = NULL;
@@ -232,6 +233,15 @@ void drawFrame3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int1
snprintf(displayBuffer, sizeof(displayBuffer), "%.1fkbps", status.modeminfo.bitrate);
display->drawString(128 + x, 34 + y, displayBuffer);
}
+ if (status.vbat != 0.0)
+ {
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+ if(getBatteryPercentage() > 100.0f) {
+ display->drawString(x, 45 + y, "Pow: USB " + String(status.vbat) + "V");
+ } else {
+ display->drawString(x, 45 + y, "Pow: Bat " + String(getBatteryPercentage(), 0) + "% " + String(status.vbat) + "V");
+ }
+ }
}
void drawFrame4(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y)
diff --git a/tinyGS/src/Mqtt/MQTT_Client.cpp b/tinyGS/src/Mqtt/MQTT_Client.cpp
index f1c587a6..a5d898bf 100644
--- a/tinyGS/src/Mqtt/MQTT_Client.cpp
+++ b/tinyGS/src/Mqtt/MQTT_Client.cpp
@@ -108,7 +108,7 @@ void MQTT_Client::loop()
else
{
StaticJsonDocument<192> doc;
- doc["Vbat"] = voltage();
+ doc["Vbat"] = status.vbat;
doc["Mem"] = ESP.getFreeHeap();
doc["MinMem"] = ESP.getMinFreeHeap(); // Mínimo histórico
doc["MaxBlk"] = ESP.getMaxAllocHeap(); // Bloque más grande disponible
@@ -249,7 +249,7 @@ void MQTT_Client::sendWelcome()
doc["board"] = configManager.getBoard();
doc["mac"] = clientId;
doc["seconds"] = millis()/1000;
- doc["Vbat"] = voltage();
+ doc["Vbat"] = status.vbat;
doc["chip"] = ESP.getChipModel();
doc["slot"] = esp_ota_get_running_partition ()->label;
doc["pSize"] = esp_ota_get_running_partition ()->size;
@@ -1170,37 +1170,3 @@ void MQTT_Client::begin()
setServer(configManager.getMqttServer(), configManager.getMqttPort());
setCallback(manageMQTTDataCallback);
}
-
-
-
-int MQTT_Client::voltage() {
- int medianVoltage;
- int length = 21;
- int voltages[22];
-
- for (int i = 0; i < 21; i++)
- {
- voltages[i] = analogRead(36);
- }
-
- // BubbleSortAsc from https://www.luisllamas.es/arduino-bubble-sort/
- int i, j, flag = 1;
- int temp;
- for (i = 1; (i <= length) && flag; i++)
- {
- flag = 0;
- for (j = 0; j < (length - 1); j++)
- {
- if (voltages[j + 1] < voltages[j])
- {
- temp = voltages[j];
- voltages[j] = voltages[j + 1];
- voltages[j + 1] = temp;
- flag = 1;
- }
- }
- }
- medianVoltage = voltages[10];
- return medianVoltage;
-}
-
diff --git a/tinyGS/src/Power/Battery.cpp b/tinyGS/src/Power/Battery.cpp
new file mode 100644
index 00000000..86b5331c
--- /dev/null
+++ b/tinyGS/src/Power/Battery.cpp
@@ -0,0 +1,126 @@
+// Battery.cpp
+// Battery monitoring helpers for tinyGS
+
+#include
+#include "Battery.h"
+#include "../ConfigManager/ConfigManager.h"
+#include "../Logger/Logger.h"
+#include
+#include
+
+adc_cali_handle_t cali_handle = NULL;
+#define DEFAULT_VREF 1100
+
+
+// Arduino Framework Battery Writeup
+// https://digitalconcepts.net.au/arduino/index.php?op=Battery
+
+// Initialize ADC pins and ADC configuration for the board's VBAT input.
+// If the board provides an `ADC_CTL` pin (to enable/disable the voltage
+// divider), that pin is configured as an output. If the `VBAT_AIN` analog
+// input is available, attach it to the ADC and set resolution/attenuation
+// appropriate for battery voltage measurement.
+void initBatteryMonitoring(void)
+{
+ board_t board;
+ if (ConfigManager::getInstance().getBoardConfig(board)) {
+ // If ADC_CTL is defined, set it up as the enable pin for ADC reading
+ if (board.ADC_CTL != UNUSED) {
+ pinMode(board.ADC_CTL, OUTPUT); // control pin for ADC/voltage divider
+ }
+ if (board.VBAT_AIN != UNUSED) {
+ // Configure the analog input used for VBAT monitoring
+ pinMode(board.VBAT_AIN, INPUT);
+ // Use 12-bit resolution and 11dB attenuation for ~0-3.6V range
+ analogReadResolution(12);
+ analogSetAttenuation(ADC_11db);
+ // Characterize ADC for voltage conversion
+ adc_cali_curve_fitting_config_t cali_config = {
+ .unit_id = ADC_UNIT_1,
+ .atten = ADC_ATTEN_DB_12,
+ .bitwidth = ADC_BITWIDTH_DEFAULT,
+ };
+
+ adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle);
+ }
+ checkBattery(); // Initial read to seed status.vbat
+ }
+}
+
+// Drive the ADC control pin to the enabled state (if present) and wait
+// briefly for voltages to stabilize before taking a reading.
+inline void enableADCReading(board_t board)
+{
+ if (board.ADC_CTL != UNUSED) {
+ digitalWrite(board.ADC_CTL, ADC_READ_ENABLE);
+ delay(50); // Allow voltage to stabilize before sampling
+ }
+}
+
+// Disable the ADC control pin to remove standby current from the
+// voltage divider (if the board uses one). No delay is necessary here.
+inline void disableADCReading(board_t board)
+{
+ if (board.ADC_CTL != UNUSED) {
+ digitalWrite(board.ADC_CTL, ADC_READ_DISABLE);
+ }
+}
+
+// Periodically read the VBAT analog input and update the global
+// `status.vbat` value. Reads are throttled by `BATTERY_CHECK_INTERVAL`.
+// The raw ADC value is scaled by `board.VBAT_SCALE` (provided by the
+// board configuration) to convert it into volts.
+void checkBattery(void)
+{
+ static unsigned long lastReadTime = 0;
+ board_t board;
+
+ // Throttle the battery check interval
+ if (millis() - lastReadTime > BATTERY_CHECK_INTERVAL) {
+ lastReadTime = millis();
+ if (ConfigManager::getInstance().getBoardConfig(board)) {
+ if (board.VBAT_AIN != UNUSED && board.VBAT_SCALE != UNUSED) {
+ int voltage = 0;
+
+ enableADCReading(board);
+
+ // Read raw ADC
+ int raw = analogRead(board.VBAT_AIN);
+
+ disableADCReading(board);
+
+ //Convert adc_reading to voltage in mV
+ adc_cali_raw_to_voltage(cali_handle, raw, &voltage);
+
+ // Convert and smooth: seed or simple average with previous value
+ float measured = (board.VBAT_SCALE * voltage) / 1000.0f; // convert mV to V
+ Log::debug(PSTR("adc raw: %d, voltage: %f V"), raw, measured);
+ if (status.vbat == 0.0) {
+ status.vbat = measured; // initial seed
+ } else {
+ status.vbat = (status.vbat + measured) / 2.0f; // simple smoothing
+ }
+ }
+ }
+ }
+}
+
+// Convert the current battery voltage status.vbat to a percentage.
+// Assumes a linear discharge curve between 3.0V (0%) and 4.15V (100%).
+// Returns 999.0f if the voltage is above 4.2V, indicating charging state.
+float getBatteryPercentage(void)
+{
+ const float poweredVoltage = 4.23f; // Voltage above 100%
+ const float maxVoltage = 4.15f; // Voltage at 100%
+ const float minVoltage = 3.5f; // Voltage at 0%
+ float voltage = status.vbat;
+ if (voltage >= poweredVoltage) {
+ return 999.0f; // Plugged in / charging
+ } else if (voltage >= maxVoltage) {
+ return 100.0f;
+ } else if (voltage <= minVoltage) {
+ return 0.0f;
+ } else {
+ return ((voltage - minVoltage) / (maxVoltage - minVoltage)) * 100.0f;
+ }
+}
\ No newline at end of file
diff --git a/tinyGS/src/Power/Battery.h b/tinyGS/src/Power/Battery.h
new file mode 100644
index 00000000..bb0b549d
--- /dev/null
+++ b/tinyGS/src/Power/Battery.h
@@ -0,0 +1,31 @@
+#ifndef BATTERY_H
+#define BATTERY_H
+#include "Arduino.h"
+#include
+#include "../Status.h"
+#include "../ConfigManager/ConfigManager.h"
+
+// Throttle reads of battery voltage (in ms)
+#define BATTERY_CHECK_INTERVAL 10000
+
+// ADC control pin polarity differs between some boards (ESP32-S3 vs
+// others). `ADC_READ_ENABLE` drives the board-specific pin value that
+// enables the voltage divider or ADC front-end; `ADC_READ_DISABLE`
+// disables it. These are used by enableADCReading()/disableADCReading().
+#if CONFIG_IDF_TARGET_ESP32S3
+ #define ADC_READ_ENABLE HIGH
+ #define ADC_READ_DISABLE LOW
+#else
+ #define ADC_READ_ENABLE LOW
+ #define ADC_READ_DISABLE HIGH
+#endif
+
+// Global device status structure defined elsewhere; `status.vbat` is
+// used/updated by the battery monitoring code in Battery.cpp.
+extern Status status;
+
+void initBatteryMonitoring(void);
+void checkBattery(void);
+float getBatteryPercentage(void);
+
+#endif
\ No newline at end of file
diff --git a/tinyGS/src/Status.h b/tinyGS/src/Status.h
index eaf424c2..6a9eac50 100644
--- a/tinyGS/src/Status.h
+++ b/tinyGS/src/Status.h
@@ -100,6 +100,7 @@ struct Status {
bool mqtt_connected = false;
bool radio_ready = false;
int16_t radio_error = 0;
+ float vbat = 0.0;
PacketInfo lastPacketInfo;
ModemInfo modeminfo;
ModemInfo modeminfolastpckt;
diff --git a/tinyGS/tinyGS.ino b/tinyGS/tinyGS.ino
index 8b78dff4..5df77071 100644
--- a/tinyGS/tinyGS.ino
+++ b/tinyGS/tinyGS.ino
@@ -80,6 +80,7 @@
#include "time.h"
#include "src/Mqtt/MQTT_credentials.h"
#include "src/Improv/tinygs_improv.h"
+#include "src/Power/Battery.h"
#if RADIOLIB_VERSION_MAJOR != (0x07) || RADIOLIB_VERSION_MINOR != (0x05) || RADIOLIB_VERSION_PATCH != (0x00) || RADIOLIB_VERSION_EXTRA != (0x00)
@@ -166,8 +167,10 @@ void setup()
// make sure to call doLoop at least once before starting to use the configManager
configManager.doLoop();
board_t board;
- if(configManager.getBoardConfig(board))
+ if(configManager.getBoardConfig(board)) {
pinMode (board.PROG__BUTTON, INPUT_PULLUP);
+ initBatteryMonitoring();
+ }
displayInit();
displayShowInitialCredits();
configManager.delay(1000);
@@ -321,6 +324,8 @@ void loop() {
return;
}
+ checkBattery();
+
// connected
mqtt.loop();