From c235f6a71a0291faeae404d6e3c303727568fafa Mon Sep 17 00:00:00 2001 From: richonguzman Date: Sat, 28 Jan 2023 02:56:09 -0300 Subject: [PATCH] SPIFSS transformation --- README.md | 22 +++++-- data/tracker.json | 62 ++++++++++++++++++ platformio.ini | 1 + src/BeaconManager.cpp | 23 +++++++ src/BeaconManager.h | 20 ++++++ src/Lora_1W_APRS_Tracker.cpp | 62 ++++++++++++------ src/beacon_config.h | 9 --- src/configuration.cpp | 119 +++++++++++++++++++++++++++++++++++ src/configuration.h | 83 ++++++++++++++++++++++++ src/user_config.h | 9 --- 10 files changed, 369 insertions(+), 41 deletions(-) create mode 100644 data/tracker.json create mode 100644 src/BeaconManager.cpp create mode 100644 src/BeaconManager.h create mode 100644 src/configuration.cpp create mode 100644 src/configuration.h delete mode 100644 src/user_config.h diff --git a/README.md b/README.md index c8f9a21..c03d0b0 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,22 @@ This LORA APRS Tracker will work with very cheep hardware (amazon, ebay or aliex This project uses Enconded APRS GPS packet to extends range by saving bytes (increased battery life, higher chances of good packet reception (increased range), lower probability of packet collisions (more channel capacity) and 1 Watt LoRa Module (over the usual 0.1 Watt in commercial boards like the LILYGO T-Beam V.1). +Achievements: + +- configurations saved on ESP32 memory (SPIFFS). +- changing CALLSINGs with the "long" push of a button. +- custom smartbeacon values for each CALLSIGN +- force Tx with the "short" push of a button. +- send enconded GPS data for shorter and realiable comunication. + +To add (shortly) working on it +- turn_slope for course angle smartbeacon +- oled screen (allready bought ... and waiting.. ) +- SendAltitude: encoded instead of just "Course+Speed" without adding lenght to the APRS packet. +- SendComment: for a GPS position or distance to certain GPS point +- Send Status: for a GPS position or distance to certain GPS point +- Send Message to anothe APRS capable Radio/Handy/tracker/iGate or even Twitter ;) +- Battery Monitoring (voltage, consumption, low_battery warning, charging?) @@ -20,14 +36,10 @@ This Repository is based on lots of other Lora APRS Tracker ideas like: -things to do: +things to do (also): - add wiki -- add status update (on the works) -- add message to another APRS capable Radio (on the works) - add translation to Spanish (and German?) -- add OLED Screen (allready Bought) - add schematic for the wiring - add info of 5V DC stepup and charging battery -- add battery monitoring + charging - add photos of prototipe - add PCB (with eagle and gerber) diff --git a/data/tracker.json b/data/tracker.json new file mode 100644 index 0000000..7908760 --- /dev/null +++ b/data/tracker.json @@ -0,0 +1,62 @@ +{ + "beacons": [ + { + "callsign": "CD2RXU-7", + "path": "AP", + "symbol": "[", + "overlay": "/", + "smart_beacon": { + "turn_min": 8, + "turn_slope":60, + "slow_rate": 120, + "slow_speed": 3, + "fast_rate": 60, + "fast_speed": 20, + "min_tx_dist": 50, + "min_bcn": 20 + } + }, + { + "callsign": "CD2RXU-8", + "path": "AP", + "symbol": "b", + "overlay": "/", + "smart_beacon": { + "turn_min": 12, + "turn_slope":80, + "slow_rate": 180, + "slow_speed": 5, + "fast_rate": 60, + "fast_speed": 40, + "min_tx_dist": 70, + "min_bcn": 12 + } + }, + { + "callsign": "CD2RXU-9", + "path": "AP", + "symbol": ">", + "overlay": "/", + "smart_beacon": { + "active": true, + "turn_min": 15, + "turn_slope":80, + "slow_rate": 120, + "slow_speed": 10, + "fast_rate": 60, + "fast_speed": 70, + "min_tx_dist": 100, + "min_bcn": 10 + } + } + + ], + "lora": { + "frequency_rx": 433775000, + "frequency_tx": 433775000, + "power": 20, + "spreading_factor": 12, + "signal_bandwidth": 125000, + "coding_rate4": 5 + } +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 8501153..94797f0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,4 +17,5 @@ lib_deps = jgromes/RadioLib@^5.5.0 paulstoffregen/Time@^1.6.1 mathertel/OneButton@^2.0.3 + bblanchon/ArduinoJson@^6.20.0 monitor_speed = 115200 diff --git a/src/BeaconManager.cpp b/src/BeaconManager.cpp new file mode 100644 index 0000000..506cac0 --- /dev/null +++ b/src/BeaconManager.cpp @@ -0,0 +1,23 @@ +#include "BeaconManager.h" + +BeaconManager::BeaconManager() : _currentBeaconConfig(_beacon_config.end()) { +} + +// cppcheck-suppress unusedFunction +void BeaconManager::loadConfig(const std::list &beacon_config) { + _beacon_config = beacon_config; + _currentBeaconConfig = _beacon_config.begin(); +} + +// cppcheck-suppress unusedFunction +std::list::iterator BeaconManager::getCurrentBeaconConfig() const { + return _currentBeaconConfig; +} + +// cppcheck-suppress unusedFunction +void BeaconManager::loadNextBeacon() { + ++_currentBeaconConfig; + if (_currentBeaconConfig == _beacon_config.end()) { + _currentBeaconConfig = _beacon_config.begin(); + } +} \ No newline at end of file diff --git a/src/BeaconManager.h b/src/BeaconManager.h new file mode 100644 index 0000000..82af5c7 --- /dev/null +++ b/src/BeaconManager.h @@ -0,0 +1,20 @@ +#ifndef BEACON_MANAGER_H_ +#define BEACON_MANAGER_H_ + +#include "configuration.h" + +class BeaconManager { +public: + BeaconManager(); + + void loadConfig(const std::list &beacon_config); + + std::list::iterator getCurrentBeaconConfig() const; + void loadNextBeacon(); + +private: + std::list _beacon_config; + std::list::iterator _currentBeaconConfig; +}; + +#endif \ No newline at end of file diff --git a/src/Lora_1W_APRS_Tracker.cpp b/src/Lora_1W_APRS_Tracker.cpp index c061c87..9fcb6ce 100644 --- a/src/Lora_1W_APRS_Tracker.cpp +++ b/src/Lora_1W_APRS_Tracker.cpp @@ -14,20 +14,38 @@ https://github.com/sh123/esp32_loraprs #include #include #include -#include "user_config.h" +#include "BeaconManager.h" #include "pins.h" #include "lora_config.h" #include "beacon_config.h" +#include "configuration.h" -#define VERSION "2023.01.24" // BETA!!! +#define VERSION "2023.01.28" // BETA still!!! SX1268 radio = new Module(NSS, DIO1, NRST, BUSY); HardwareSerial neo6m_gps(1); TinyGPSPlus gps; OneButton UserButton1 = OneButton(BUTTON1_PIN, true, true); +Configuration Config; +BeaconManager BeaconMan; static bool send_update = true; +void load_config() { + ConfigurationManagement confmg("/tracker.json"); + Config = confmg.readConfiguration(); + BeaconMan.loadConfig(Config.beacons); + if (BeaconMan.getCurrentBeaconConfig()->callsign == "NOCALL-10") { + Serial.println("You have to change your settings in 'data/tracker.json' and " + "upload it via \"Upload File System image\"!"); + while (true) { + } + } else { + Serial.println("##### (Configuration Loaded) #####"); + } +} + + void setup_lora_module() { int state = radio.begin(LoraFreqTx, LoraBandWidth, LoraSpreadingFactor, LoraCodingRate, LoraSyncWord, LoraOutro, LoraPreampbleLenght); radio.setOutputPower(Lora_Power); @@ -49,18 +67,26 @@ static void ForcedBeaconTx() { send_update = true; } +static void HandleNextBeacon() { + BeaconMan.loadNextBeacon(); + Serial.print("Changing CALLSIGN --> "); + Serial.println(BeaconMan.getCurrentBeaconConfig()->callsign); +} + void setup() { Serial.begin(115200); - Serial.println(F("LoRa tracker " __DATE__ " " __TIME__ " / Callsign ------> " SRC_CALLSIGN)); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); + load_config(); + Serial.print("LoRa tracker " __DATE__ " " __TIME__ " / Callsign ------> "); + Serial.println(BeaconMan.getCurrentBeaconConfig()->callsign); setup_lora_module(); setup_gps_module(); UserButton1.attachClick(ForcedBeaconTx); + UserButton1.attachLongPressStart(HandleNextBeacon); WiFi.mode(WIFI_OFF); btStop(); - Serial.print("Version = "); - Serial.println(VERSION); + Serial.print("(Version = "); Serial.print(VERSION); Serial.println(")"); Serial.println("Transmission Start ---->"); } @@ -104,15 +130,15 @@ void loop() { currentHeading = gps.course.deg(); lastTxDistance = TinyGPSPlus::distanceBetween(gps.location.lat(), gps.location.lng(), lastTxLatitude, lastTxLongitude); if (lastTx >= txInterval) { - if (lastTxDistance > MinimumDistanceTx) { + if (lastTxDistance > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_tx_dist) { send_update = true; mensaje_test = "Dist: " + String(lastTxDistance) + " Int: " + String(txInterval); } } if (!send_update) { double headingDelta = abs(previousHeading - currentHeading); - if (lastTx > MinimumTimeDeltaBeacon * 1000) { - if (headingDelta > TurnDegrees && lastTxDistance > MinimumDistanceTx) { + if (lastTx > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_bcn * 1000) { + if (headingDelta > BeaconMan.getCurrentBeaconConfig()->smart_beacon.turn_min && lastTxDistance > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_tx_dist) { send_update = true; mensaje_test = "Delta: " + String(headingDelta) + " Dist: " + String(lastTxDistance) + " Int: " + String(txInterval); } @@ -142,7 +168,7 @@ void loop() { if(Tlon < 0) { Tlon= -Tlon; } String AprsPacketMsg = "!"; - AprsPacketMsg += "/"; + AprsPacketMsg += BeaconMan.getCurrentBeaconConfig()->overlay; char helper_base91[] = {"0000\0"}; int i; ax25_base91enc(helper_base91, 4, aprs_lat); @@ -154,7 +180,7 @@ void loop() { AprsPacketMsg += helper_base91[i]; } - AprsPacketMsg += SYMBOL; + AprsPacketMsg += BeaconMan.getCurrentBeaconConfig()->symbol; if (SendAltitude) { // Send Altitude or... (APRS calculates Speed also) int Alt1, Alt2; @@ -180,7 +206,7 @@ void loop() { } if (SendComment) { - //AprsPacketMsg += APRS_COMMENT; + //AprsPacketMsg += "Lora Tracker 1W"; AprsPacketMsg += mensaje_test; @@ -195,7 +221,7 @@ void loop() { memset(tx_buffer, 0x00, sizeof tx_buffer); uint16_t size = 0; - size = snprintf(reinterpret_cast(tx_buffer), sizeof tx_buffer, "\x3c\xff\x01%s>%s:%s", SRC_CALLSIGN, DST_CALLSIGN, AprsPacketMsg.c_str()); + size = snprintf(reinterpret_cast(tx_buffer), sizeof tx_buffer, "\x3c\xff\x01%s>%s:%s", BeaconMan.getCurrentBeaconConfig()->callsign, BeaconMan.getCurrentBeaconConfig()->path, AprsPacketMsg.c_str()); Serial.print(millis()); // Only for Serial Monitor Serial.print(F(" transmitting: ")); @@ -214,14 +240,14 @@ void loop() { send_update = false; } - if (gps_time_update) { // updating txInterval between Slow and FastRate or in between + if (gps_time_update) { // updating txInterval between Slow and FastRate or "in-between" int curr_speed = (int)gps.speed.kmph(); - if (curr_speed < SlowSpeed) { - txInterval = SlowRate * 1000; - } else if (curr_speed > FastSpeed) { - txInterval = FastRate * 1000; + if (curr_speed < BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_speed) { + txInterval = BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate * 1000; + } else if (curr_speed > BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed) { + txInterval = BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate * 1000; } else { - txInterval = min(SlowRate, (FastSpeed * FastRate / curr_speed)) * 1000; + txInterval = min(BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate, (BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed * BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate / curr_speed)) * 1000; } } } \ No newline at end of file diff --git a/src/beacon_config.h b/src/beacon_config.h index 1f95a5b..6032b6a 100644 --- a/src/beacon_config.h +++ b/src/beacon_config.h @@ -1,15 +1,6 @@ #ifndef BEACON_CONFIG_H_ #define BEACON_CONFIG_H_ -// Settings for Car Tracker (for now) -#define SlowRate 300 // Seg (300 = 5min) -#define SlowSpeed 10 // Km/h (3 Runner , 5 Bike, 10 Car) -#define FastRate 30 // Seg -#define FastSpeed 100 // Km/h (20 Runner y Bike, 100 Car) -#define TurnDegrees 20 // Degrees before Forced Beacon Tx (20 Car , 15 Bike/Runner) -#define MinimumDistanceTx 100 // Mts (20 Runner, 100 Car/Bike) -#define MinimumTimeDeltaBeacon 5 // Seg between Tx - #define SendAltitude true // "true" adds Altitude to the APRS packet/message, "false" add Course+Speed #define SendComment true // "true" adds comment to the APRS packet/message diff --git a/src/configuration.cpp b/src/configuration.cpp new file mode 100644 index 0000000..efd87b0 --- /dev/null +++ b/src/configuration.cpp @@ -0,0 +1,119 @@ +#include +#include +#include "configuration.h" + +ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(FilePath) { + if (!SPIFFS.begin(true)) { + Serial.println("Mounting SPIFFS was not possible. Trying to format SPIFFS..."); + SPIFFS.format(); + if (!SPIFFS.begin()) { + Serial.println("Formatting SPIFFS was not okay!"); + } + } +} + +Configuration ConfigurationManagement::readConfiguration() { + File file = SPIFFS.open(mFilePath); + if (!file) { + Serial.println("Failed to open file for reading..."); + return Configuration(); + } + DynamicJsonDocument data(2048); + DeserializationError error = deserializeJson(data, file); + + if (error) { + Serial.println("Failed to read file, using default configuration."); + } + file.close(); + + Configuration conf; + + conf.debug = data["debug"] | false; + + JsonArray beacons = data["beacons"].as(); + for (JsonVariant v : beacons) { + Configuration::Beacon beacon; + + if (v.containsKey("callsign")) + beacon.callsign = v["callsign"].as(); + beacon.path = v["path"].as(); + if (v.containsKey("message")) + beacon.message = v["message"].as(); + beacon.timeout = v["timeout"] | 1; + if (v.containsKey("symbol")) + beacon.symbol = v["symbol"].as(); + if (v.containsKey("overlay")) + beacon.overlay = v["overlay"].as(); + + beacon.smart_beacon.active = v["smart_beacon"]["active"] | false; + beacon.smart_beacon.turn_min = v["smart_beacon"]["turn_min"] | 25; + beacon.smart_beacon.slow_rate = v["smart_beacon"]["slow_rate"] | 300; + beacon.smart_beacon.slow_speed = v["smart_beacon"]["slow_speed"] | 10; + beacon.smart_beacon.fast_rate = v["smart_beacon"]["fast_rate"] | 60; + beacon.smart_beacon.fast_speed = v["smart_beacon"]["fast_speed"] | 100; + beacon.smart_beacon.min_tx_dist = v["smart_beacon"]["min_tx_dist"] | 100; + beacon.smart_beacon.min_bcn = v["smart_beacon"]["min_bcn"] | 5; + + beacon.enhance_precision = v["enhance_precision"] | false; + + conf.beacons.push_back(beacon); + } + + conf.button.tx = data["button"]["tx"] | false; + conf.button.alt_message = data["button"]["alt_message"] | false; + + conf.lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; + conf.lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; + conf.lora.power = data["lora"]["power"] | 20; + conf.lora.spreadingFactor = data["lora"]["spreading_factor"] | 12; + conf.lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000; + conf.lora.codingRate4 = data["lora"]["coding_rate4"] | 5; + + return conf; +} + +void ConfigurationManagement::writeConfiguration(Configuration conf) { + File file = SPIFFS.open(mFilePath, "w"); + if (!file) { + Serial.println("Failed to open file for writing..."); + return; + } + DynamicJsonDocument data(2048); + + JsonArray beacons = data.createNestedArray("beacons"); + for (Configuration::Beacon beacon : conf.beacons) { + JsonObject v = beacons.createNestedObject(); + v["callsign"] = beacon.callsign; + v["path"] = beacon.path; + v["message"] = beacon.message; + v["timeout"] = beacon.timeout; + v["symbol"] = beacon.symbol; + v["overlay"] = beacon.overlay; + + v["smart_beacon"]["active"] = beacon.smart_beacon.active; + v["smart_beacon"]["turn_min"] = beacon.smart_beacon.turn_min; + v["smart_beacon"]["slow_rate"] = beacon.smart_beacon.slow_rate; + v["smart_beacon"]["slow_speed"] = beacon.smart_beacon.slow_speed; + v["smart_beacon"]["fast_rate"] = beacon.smart_beacon.fast_rate; + v["smart_beacon"]["fast_speed"] = beacon.smart_beacon.fast_speed; + v["smart_beacon"]["min_tx_dist"] = beacon.smart_beacon.min_tx_dist; + v["smart_beacon"]["min_bcn"] = beacon.smart_beacon.min_bcn; + + v["enhance_precision"] = beacon.enhance_precision; + } + + data["debug"] = conf.debug; + + data["button"]["tx"] = conf.button.tx; + data["button"]["alt_message"] = conf.button.alt_message; + + data["lora"]["frequency_rx"] = conf.lora.frequencyRx; + data["lora"]["frequency_tx"] = conf.lora.frequencyTx; + data["lora"]["power"] = conf.lora.power; + data["lora"]["spreading_factor"] = conf.lora.spreadingFactor; + data["lora"]["signal_bandwidth"] = conf.lora.signalBandwidth; + data["lora"]["coding_rate4"] = conf.lora.codingRate4; + + serializeJson(data, file); + file.close(); +} \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..6cad17c --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,83 @@ +#ifndef CONFIGURATION_H_ +#define CONFIGURATION_H_ + +#include +#include + +#include + +class Configuration { +public: + class Beacon { + public: + class Smart_Beacon { + public: + Smart_Beacon() : active(false), turn_min(25), slow_rate(300), slow_speed(10), fast_rate(60), fast_speed(100), min_tx_dist(100), min_bcn(5) { + } + + bool active; + int turn_min; + int slow_rate; + int slow_speed; + int fast_rate; + int fast_speed; + int min_tx_dist; + int min_bcn; + }; + + Beacon() : callsign("NOCALL-10"), path("WIDE1-1"), message("LoRa Tracker"), timeout(1), symbol("["), overlay("/"), enhance_precision(true) { + } + + String callsign; + String path; + String message; + int timeout; + String symbol; + String overlay; + Smart_Beacon smart_beacon; + bool enhance_precision; + }; + + class LoRa { + public: + LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) { + } + + long frequencyRx; + long frequencyTx; + int power; + int spreadingFactor; + long signalBandwidth; + int codingRate4; + }; + + class Button { + public: + Button() : tx(false), alt_message(false) { + } + + bool tx; + int alt_message; + }; + + Configuration() : debug(false) { + } + + bool debug; + std::list beacons; + LoRa lora; + Button button; +}; + +class ConfigurationManagement { +public: + explicit ConfigurationManagement(String FilePath); + + Configuration readConfiguration(); + void writeConfiguration(Configuration conf); + +private: + const String mFilePath; +}; + +#endif \ No newline at end of file diff --git a/src/user_config.h b/src/user_config.h deleted file mode 100644 index 59b95c3..0000000 --- a/src/user_config.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef USER_CONFIG_H_ -#define USER_CONFIG_H_ - -#define SRC_CALLSIGN "CD2RXU-7" // Change "CD2RXU-7" to your CALLSIGN-SSID you would use in APRS -#define DST_CALLSIGN "AP" // APRS Destination (could be also "WIDE1-1") -#define SYMBOL "[" // APRS Symbol: "[" Runner, "b" Bike, ">" Auto/Car -#define APRS_COMMENT "Lora Tracker 1W" // if you want to send any comment change the APRS_COMMENT - // and also beacon_config.h > SendComment = true -#endif \ No newline at end of file