From c438928465ac93432555f819c01c44f952666e4f Mon Sep 17 00:00:00 2001 From: richonguzman Date: Tue, 17 Sep 2024 22:24:48 -0300 Subject: [PATCH] encoded Telemetry added --- README.md | 1 + data/tracker_config.json | 6 ++- src/LoRa_APRS_Tracker.cpp | 4 +- src/battery_utils.cpp | 50 +++++++++++++++++ src/battery_utils.h | 13 +++++ src/configuration.cpp | 109 ++++++++++++++++++++------------------ src/configuration.h | 9 +++- src/power_utils.cpp | 2 +- src/station_utils.cpp | 86 +++++++++++++++++++++--------- 9 files changed, 197 insertions(+), 83 deletions(-) create mode 100644 src/battery_utils.cpp create mode 100644 src/battery_utils.h diff --git a/README.md b/README.md index c67707c..195b628 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ ____________________________________________________ ____________________________________________________ ## Timeline (Versions): +- 2024.09.17 Battery Info now as Encoded Telemetry in GPS Beacon. - 2024.08.26 New reformating of code ahead of WebInstaller: SmartBeacon change. - 2024.08.16 BLE support for Android devices (not APRSDroid yet). - 2024.08.12 Added support for EByte E220 400M30S 1Watt LoRa module for DIY ESP32 Tracker (LLCC68 supports spreading factor only in range of 5 - 11!) diff --git a/data/tracker_config.json b/data/tracker_config.json index e30ca22..95f70ff 100644 --- a/data/tracker_config.json +++ b/data/tracker_config.json @@ -37,6 +37,11 @@ "timeout": 4, "turn180" : false }, + "battery": { + "sendVoltage": true, + "voltageAsTelemetry": true, + "sendVoltageAlways": true + }, "other": { "simplifiedTrackerMode": false, "sendCommentAfterXBeacons": 10, @@ -46,7 +51,6 @@ "maxDistanceToTracker": 30, "standingUpdateTime": 15, "sendAltitude": true, - "sendBatteryInfo": false, "bluetoothType": 0, "bluetoothActive": true, "disableGPS": false diff --git a/src/LoRa_APRS_Tracker.cpp b/src/LoRa_APRS_Tracker.cpp index 4a06e89..043fb71 100644 --- a/src/LoRa_APRS_Tracker.cpp +++ b/src/LoRa_APRS_Tracker.cpp @@ -41,13 +41,13 @@ Configuration Config; HardwareSerial neo6m_gps(1); TinyGPSPlus gps; #ifdef HAS_BT_CLASSIC - BluetoothSerial SerialBT; + BluetoothSerial SerialBT; #endif #ifdef BUTTON_PIN OneButton userButton = OneButton(BUTTON_PIN, true, true); #endif -String versionDate = "2024.09.10"; +String versionDate = "2024.09.17"; uint8_t myBeaconsIndex = 0; int myBeaconsSize = Config.beacons.size(); diff --git a/src/battery_utils.cpp b/src/battery_utils.cpp new file mode 100644 index 0000000..07caff8 --- /dev/null +++ b/src/battery_utils.cpp @@ -0,0 +1,50 @@ +#include +#include "battery_utils.h" + + +int telemetryCounter = random(1,999); + + +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(float voltage) { + String telemetry = "|"; + telemetry += generateEncodedTelemetryBytes(telemetryCounter, true, 0); + telemetryCounter++; + if (telemetryCounter == 1000) { + telemetryCounter = 0; + } + telemetry += generateEncodedTelemetryBytes(voltage, false, 0); + telemetry += "|"; + return telemetry; + } + +} \ No newline at end of file diff --git a/src/battery_utils.h b/src/battery_utils.h new file mode 100644 index 0000000..da3448d --- /dev/null +++ b/src/battery_utils.h @@ -0,0 +1,13 @@ +#ifndef BATTERY_UTILS_H_ +#define BATTERY_UTILS_H_ + +#include + + +namespace BATTERY_Utils { + + String generateEncodedTelemetry(float voltage); + +} + +#endif \ No newline at end of file diff --git a/src/configuration.cpp b/src/configuration.cpp index 6c401f9..93da72e 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -27,76 +27,79 @@ void Configuration::readFile(fs::FS &fs, const char *fileName) { for (int i = 0; i < BeaconsArray.size(); i++) { Beacon bcn; - bcn.callsign = BeaconsArray[i]["callsign"] | "NOCALL-7"; + bcn.callsign = BeaconsArray[i]["callsign"] | "NOCALL-7"; bcn.callsign.toUpperCase(); - bcn.symbol = BeaconsArray[i]["symbol"] | ">"; - bcn.overlay = BeaconsArray[i]["overlay"] | "/"; - bcn.comment = BeaconsArray[i]["comment"] | ""; - bcn.smartBeaconActive = BeaconsArray[i]["smartBeaconActive"] | true; - bcn.smartBeaconSetting = BeaconsArray[i]["smartBeaconSetting"] | 0; - bcn.micE = BeaconsArray[i]["micE"] | ""; - bcn.gpsEcoMode = BeaconsArray[i]["gpsEcoMode"] | false; + bcn.symbol = BeaconsArray[i]["symbol"] | ">"; + bcn.overlay = BeaconsArray[i]["overlay"] | "/"; + bcn.comment = BeaconsArray[i]["comment"] | ""; + bcn.smartBeaconActive = BeaconsArray[i]["smartBeaconActive"] | true; + bcn.smartBeaconSetting = BeaconsArray[i]["smartBeaconSetting"] | 0; + bcn.micE = BeaconsArray[i]["micE"] | ""; + bcn.gpsEcoMode = BeaconsArray[i]["gpsEcoMode"] | false; beacons.push_back(bcn); } - display.showSymbol = data["display"]["showSymbol"] | true; - display.ecoMode = data["display"]["ecoMode"] | false; - display.timeout = data["display"]["timeout"] | 4; - display.turn180 = data["display"]["turn180"] | false; + display.showSymbol = data["display"]["showSymbol"] | true; + display.ecoMode = data["display"]["ecoMode"] | false; + display.timeout = data["display"]["timeout"] | 4; + display.turn180 = data["display"]["turn180"] | false; - winlink.password = data["winlink"]["password"] | "NOPASS"; + battery.sendVoltage = data["battery"]["sendVoltage"] | false; + battery.voltageAsTelemetry = data["battery"]["voltageAsTelemetry"] | false; + battery.sendVoltageAlways = data["battery"]["sendVoltageAlways"] | false; - bme.active = data["bme"]["active"] | false; - bme.temperatureCorrection = data["bme"]["temperatureCorrection"] | 0.0; - bme.sendTelemetry = data["bme"]["sendTelemetry"] | false; + winlink.password = data["winlink"]["password"] | "NOPASS"; - notification.ledTx = data["notification"]["ledTx"] | false; - notification.ledTxPin = data["notification"]["ledTxPin"]| 13; - notification.ledMessage = data["notification"]["ledMessage"] | false; - notification.ledMessagePin = data["notification"]["ledMessagePin"] | 2; - notification.ledFlashlight = data["notification"]["ledFlashlight"] | false; - notification.ledFlashlightPin = data["notification"]["ledFlashlightPin"] | 14; - notification.buzzerActive = data["notification"]["buzzerActive"] | false; - notification.buzzerPinTone = data["notification"]["buzzerPinTone"] | 33; - notification.buzzerPinVcc = data["notification"]["buzzerPinVcc"] | 25; - notification.bootUpBeep = data["notification"]["bootUpBeep"] | false; - notification.txBeep = data["notification"]["txBeep"] | false; - notification.messageRxBeep = data["notification"]["messageRxBeep"] | false; - notification.stationBeep = data["notification"]["stationBeep"] | false; - notification.lowBatteryBeep = data["notification"]["lowBatteryBeep"] | false; - notification.shutDownBeep = data["notification"]["shutDownBeep"] | false; + bme.active = data["bme"]["active"] | false; + bme.temperatureCorrection = data["bme"]["temperatureCorrection"] | 0.0; + bme.sendTelemetry = data["bme"]["sendTelemetry"] | false; + + notification.ledTx = data["notification"]["ledTx"] | false; + notification.ledTxPin = data["notification"]["ledTxPin"]| 13; + notification.ledMessage = data["notification"]["ledMessage"] | false; + notification.ledMessagePin = data["notification"]["ledMessagePin"] | 2; + notification.ledFlashlight = data["notification"]["ledFlashlight"] | false; + notification.ledFlashlightPin = data["notification"]["ledFlashlightPin"] | 14; + notification.buzzerActive = data["notification"]["buzzerActive"] | false; + notification.buzzerPinTone = data["notification"]["buzzerPinTone"] | 33; + notification.buzzerPinVcc = data["notification"]["buzzerPinVcc"] | 25; + notification.bootUpBeep = data["notification"]["bootUpBeep"] | false; + notification.txBeep = data["notification"]["txBeep"] | false; + notification.messageRxBeep = data["notification"]["messageRxBeep"] | false; + notification.stationBeep = data["notification"]["stationBeep"] | false; + notification.lowBatteryBeep = data["notification"]["lowBatteryBeep"] | false; + notification.shutDownBeep = data["notification"]["shutDownBeep"] | false; JsonArray LoraTypesArray = data["lora"]; for (int j = 0; j < LoraTypesArray.size(); j++) { LoraType loraType; - loraType.frequency = LoraTypesArray[j]["frequency"] | 433775000; - loraType.spreadingFactor = LoraTypesArray[j]["spreadingFactor"] | 12; - loraType.signalBandwidth = LoraTypesArray[j]["signalBandwidth"] | 125000; - loraType.codingRate4 = LoraTypesArray[j]["codingRate4"] | 5; - loraType.power = LoraTypesArray[j]["power"] | 20; + loraType.frequency = LoraTypesArray[j]["frequency"] | 433775000; + loraType.spreadingFactor = LoraTypesArray[j]["spreadingFactor"] | 12; + loraType.signalBandwidth = LoraTypesArray[j]["signalBandwidth"] | 125000; + loraType.codingRate4 = LoraTypesArray[j]["codingRate4"] | 5; + loraType.power = LoraTypesArray[j]["power"] | 20; loraTypes.push_back(loraType); } - ptt.active = data["pttTrigger"]["active"] | false; - ptt.io_pin = data["pttTrigger"]["io_pin"] | 4; - ptt.preDelay = data["pttTrigger"]["preDelay"] | 0; - ptt.postDelay = data["pttTrigger"]["postDelay"] | 0; - ptt.reverse = data["pttTrigger"]["reverse"] | false; + ptt.active = data["pttTrigger"]["active"] | false; + ptt.io_pin = data["pttTrigger"]["io_pin"] | 4; + ptt.preDelay = data["pttTrigger"]["preDelay"] | 0; + ptt.postDelay = data["pttTrigger"]["postDelay"] | 0; + ptt.reverse = data["pttTrigger"]["reverse"] | false; - simplifiedTrackerMode = data["other"]["simplifiedTrackerMode"] | false; - sendCommentAfterXBeacons = data["other"]["sendCommentAfterXBeacons"] | 10; - path = data["other"]["path"] | "WIDE1-1"; - nonSmartBeaconRate = data["other"]["nonSmartBeaconRate"] | 15; - rememberStationTime = data["other"]["rememberStationTime"] | 30; - maxDistanceToTracker = data["other"]["maxDistanceToTracker"] | 30; - standingUpdateTime = data["other"]["standingUpdateTime"] | 15; - sendAltitude = data["other"]["sendAltitude"] | true; - sendBatteryInfo = data["other"]["sendBatteryInfo"] | false; - bluetoothType = data["other"]["bluetoothType"] | 1; - bluetoothActive = data["other"]["bluetoothActive"] | true; - disableGPS = data["other"]["disableGPS"] | false; + simplifiedTrackerMode = data["other"]["simplifiedTrackerMode"] | false; + sendCommentAfterXBeacons = data["other"]["sendCommentAfterXBeacons"] | 10; + path = data["other"]["path"] | "WIDE1-1"; + nonSmartBeaconRate = data["other"]["nonSmartBeaconRate"] | 15; + rememberStationTime = data["other"]["rememberStationTime"] | 30; + maxDistanceToTracker = data["other"]["maxDistanceToTracker"] | 30; + standingUpdateTime = data["other"]["standingUpdateTime"] | 15; + sendAltitude = data["other"]["sendAltitude"] | true; + bluetoothType = data["other"]["bluetoothType"] | 1; + bluetoothActive = data["other"]["bluetoothActive"] | true; + disableGPS = data["other"]["disableGPS"] | false; configFile.close(); } diff --git a/src/configuration.h b/src/configuration.h index 974e518..5d282a0 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -25,6 +25,13 @@ public: bool turn180; }; +class Battery { +public: + bool sendVoltage; + bool voltageAsTelemetry; + bool sendVoltageAlways; +}; + class Winlink { public: String password; @@ -79,6 +86,7 @@ public: std::vector beacons; Display display; + Battery battery; Winlink winlink; BME bme; Notification notification; @@ -93,7 +101,6 @@ public: int maxDistanceToTracker; int standingUpdateTime; bool sendAltitude; - bool sendBatteryInfo; int bluetoothType; bool bluetoothActive; bool disableGPS; diff --git a/src/power_utils.cpp b/src/power_utils.cpp index 37d68cd..e1275b3 100644 --- a/src/power_utils.cpp +++ b/src/power_utils.cpp @@ -164,7 +164,7 @@ namespace POWER_Utils { BatteryIsConnected = isBatteryConnected(); if (BatteryIsConnected) { #ifdef HAS_AXP2101 - batteryVoltage = String(PMU.getBattVoltage()); + batteryVoltage = String(PMU.getBattVoltage()/1000); #else batteryVoltage = String(getBatteryVoltage(), 2); #endif diff --git a/src/station_utils.cpp b/src/station_utils.cpp index 99b9c4d..9bc42e7 100644 --- a/src/station_utils.cpp +++ b/src/station_utils.cpp @@ -2,6 +2,7 @@ #include #include "APRSPacketLib.h" #include "station_utils.h" +#include "battery_utils.h" #include "configuration.h" #include "boards_pinout.h" #include "power_utils.h" @@ -43,7 +44,7 @@ bool sendStandingUpdate = false; uint8_t updateCounter = Config.sendCommentAfterXBeacons; - +bool sendStartTelemetry = true; uint32_t lastTelemetryTx = 0; uint32_t telemetryTx = millis(); @@ -176,6 +177,38 @@ namespace STATION_Utils { } void sendBeacon(uint8_t type) { + if (sendStartTelemetry && Config.battery.voltageAsTelemetry) { + String sender = currentBeacon->callsign; + for (int i = sender.length(); i < 9; i++) { + sender += ' '; + } + String basePacket = currentBeacon->callsign; + basePacket += ">APLRT1"; + if (Config.path != "") { + basePacket += ","; + basePacket += Config.path; + } + basePacket += "::"; + basePacket += sender; + basePacket += ":"; + + String tempPacket = basePacket; + tempPacket += "EQNS.0,0.01,0"; + LoRa_Utils::sendNewPacket(tempPacket); + delay(3000); + + tempPacket = basePacket; + tempPacket += "UNIT.VDC"; + LoRa_Utils::sendNewPacket(tempPacket); + delay(3000); + + tempPacket = basePacket; + tempPacket += "PARM.V_Batt"; + LoRa_Utils::sendNewPacket(tempPacket); + delay(3000); + sendStartTelemetry = false; + } + String packet; if (Config.bme.sendTelemetry && type == 1) { // WX packet = APRSPacketLib::generateGPSBeaconPacket(currentBeacon->callsign, "APLRT1", Config.path, "/", APRSPacketLib::encodeGPS(gps.location.lat(),gps.location.lng(), gps.course.deg(), 0.0, currentBeacon->symbol, Config.sendAltitude, gps.altitude.feet(), sendStandingUpdate, "Wx")); @@ -197,36 +230,39 @@ namespace STATION_Utils { } String comment; int sendCommentAfterXBeacons; - if (winlinkCommentState) { - comment = " winlink"; + if (winlinkCommentState || Config.battery.sendVoltageAlways) { + if (winlinkCommentState) comment = " winlink"; sendCommentAfterXBeacons = 1; } else { comment = currentBeacon->comment; sendCommentAfterXBeacons = Config.sendCommentAfterXBeacons; } String batteryVoltage = POWER_Utils::getBatteryInfoVoltage(); - if (Config.sendBatteryInfo) { - //String batteryVoltage = POWER_Utils::getBatteryInfoVoltage(); - String batteryChargeCurrent = POWER_Utils::getBatteryInfoCurrent(); - #ifdef HAS_AXP192 - comment += " Bat="; - comment += batteryVoltage; - comment += "V ("; - comment += batteryChargeCurrent; - comment += "mA)"; - #endif - #ifdef HAS_AXP2101 - comment += " Bat="; - comment += String(batteryVoltage.toFloat()/1000,2); - comment += "V ("; - comment += batteryChargeCurrent; - comment += "%)"; - #endif - #if defined(HELTEC_V3_GPS) || defined(HELTEC_WIRELESS_TRACKER) || defined(TTGO_T_DECK_GPS) - comment += " Bat="; - comment += String(batteryVoltage.toFloat(),2); - comment += "V"; - #endif + if (Config.battery.sendVoltage) { + if (Config.battery.voltageAsTelemetry) { + comment += BATTERY_Utils::generateEncodedTelemetry(batteryVoltage.toFloat()); + } else { + String batteryChargeCurrent = POWER_Utils::getBatteryInfoCurrent(); + #ifdef HAS_AXP192 + comment += " Bat="; + comment += batteryVoltage; + comment += "V ("; + comment += batteryChargeCurrent; + comment += "mA)"; + #endif + #ifdef HAS_AXP2101 + comment += " Bat="; + comment += String(batteryVoltage.toFloat(),2); + comment += "V ("; + comment += batteryChargeCurrent; + comment += "%)"; + #endif + #if defined(HELTEC_V3_GPS) || defined(HELTEC_WIRELESS_TRACKER) || defined(TTGO_T_DECK_GPS) + comment += " Bat="; + comment += String(batteryVoltage.toFloat(),2); + comment += "V"; + #endif + } } if (comment != "") { updateCounter++;