diff --git a/ChronoBLE.cpp b/ChronoBLE.cpp index 8800146..44e6019 100644 --- a/ChronoBLE.cpp +++ b/ChronoBLE.cpp @@ -4,11 +4,12 @@ // Flag to signal that a new reading is ready to be processed volatile bool newReadingAvailable = false; volatile int lastReadFPS = 0; - +static NimBLEScan* pScan; static NimBLEClient* _pClient = nullptr; static ChronoBLE::ConnectionState currentState; static const NimBLEAdvertisedDevice* advDevice = nullptr; -static uint32_t scanTimeMs = 5000; +static uint32_t scanTimeMs = 1000; //5000 +static uint32_t scanTimeoutMs = 1000; static NimBLEUUID deviceUUID("0000180a-0000-1000-8000-00805f9b34fb"); static NimBLEUUID serviceUUID("00001623-88EC-688C-644B-3FA706C0BB75"); static NimBLEUUID speedCharacteristicUUID("00001624-88EC-688C-644B-3FA706C0BB75"); @@ -58,7 +59,8 @@ class ScanCallbacks : public NimBLEScanCallbacks { /** Callback to process the results of the completed scan or restart it */ void onScanEnd(const NimBLEScanResults& results, int reason) override { //Serial.printf("Scan Ended, reason: %d, device count: %d; Restarting scan\n", reason, results.getCount()); - NimBLEDevice::getScan()->start(scanTimeMs, false, true); + delay(scanTimeoutMs); + pScan->start(scanTimeMs, false, false); } } scanCallbacks; @@ -94,11 +96,11 @@ ChronoBLE::ChronoBLE() { void ChronoBLE::init() { NimBLEDevice::init("FX-Chrono-Client"); NimBLEDevice::setPower(3); /** 3dbm */ - NimBLEScan* pScan = NimBLEDevice::getScan(); + pScan = NimBLEDevice::getScan(); pScan->setScanCallbacks(&scanCallbacks, false); pScan->setInterval(100); - pScan->setWindow(100); - pScan->setActiveScan(true); + pScan->setWindow(99); + pScan->setActiveScan(false); } void ChronoBLE::_setState(ConnectionState state){ currentState=state; @@ -122,7 +124,7 @@ bool ChronoBLE::foundDevice(){if (advDevice!=nullptr){return true;}return false; void ChronoBLE::startScan(){ Serial.println("starting scan!!!"); _setState(SCANNING); - NimBLEDevice::getScan()->start(scanTimeMs, false, true); + pScan->start(scanTimeMs, false, false); } void ChronoBLE::_disconnectDevice(){ _setState(IDLE); diff --git a/ChronoDisplay.ino.bin b/ChronoDisplay.ino.bin new file mode 100644 index 0000000..0d94f4c Binary files /dev/null and b/ChronoDisplay.ino.bin differ diff --git a/ChronoDisplay.ino.ota.bin b/ChronoDisplay.ino.ota.bin new file mode 100644 index 0000000..e465a1b Binary files /dev/null and b/ChronoDisplay.ino.ota.bin differ diff --git a/ChronoWebServer.cpp b/ChronoWebServer.cpp index 7f233ac..4a96fd5 100644 --- a/ChronoWebServer.cpp +++ b/ChronoWebServer.cpp @@ -7,208 +7,47 @@ #include #include #include "Display.h" +#include + +static const char *SSID_KEY = "wifi_ssid"; +static const char *PASSWORD_KEY = "wifi_password"; +static Preferences preferences; + +String getWifiSsid() { + String ssid = ""; + if (preferences.begin("wifi", true)) { + ssid = preferences.getString(SSID_KEY, ""); + preferences.end(); + } + return ssid; +} + +String getWifiPassword() { + String password = ""; + if (preferences.begin("wifi", true)) { + password = preferences.getString(PASSWORD_KEY, ""); + preferences.end(); + } + return password; +} + +void saveWifiCredentials(const String& ssid, const String& password) { + preferences.begin("wifi", false); + preferences.putString(SSID_KEY, ssid); + preferences.putString(PASSWORD_KEY, password); + preferences.end(); +} -const char *ssid = "routeguy"; -const char *password = "wrangleR621!"; WebServer _server(80); void (*testModeCallback)(); // Constructor implementation ChronoWebServer::ChronoWebServer() {} void ChronoWebServer::_handleRoot() { - String temp="\ - \ - FX Chronograph Display Settings\ - \ - \ - \ - \ -

ChronoDisplay Settings

\ -
\ -

Control Panel

\ - \ - \ - \ - \ -
\ -
\ -

OTA Firmware Update

\ -

Current Version: Unknown

\ - \ -

1. Select a .bin firmware file to update over-the-air

\ - \ -

2. Click OTA Upgrade to install

\ -
\ -
\ -

Gun Profiles

\ - \ - "; - ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); - - String currentGunName=chronoReadings.getProfile().getGunProfile().getName(); - int currentGunPowerLevel=chronoReadings.getProfile().getGunProfile().getPowerLevel(); - LinkedList& gprofiles= chronoReadings.getGunProfiles(); - for(int i=0;i"; - } - else{ - temp +=""; - } - temp +=""; - } - -temp +="
NameType
"+name+""+type+"
\ - \ -
\ -
\ -

Projectile Profiles

\ - \ - "; - String currentProjectileProfileName=chronoReadings.getProfile().getProjectileProfile().getName(); - float currentProjectileProfileWeight=chronoReadings.getProfile().getProjectileProfile().getWeight(); - LinkedList& profiles= chronoReadings.getProjectileProfiles(); - for(int i=0;i"; - } - else{ - temp +=""; - } - temp +=""; - } - - - temp +="
NameTypeCaliberWeight
"+name+""+type+""+cal+""+weight+"
\ - \ -
\ - \ -"; - _server.send(200, "text/html", temp); + String temp="ChronoDisplay

ChronoDisplay

Latest Reading

--
FPS
--
FPE
0
Shots
--
Avg
--
Low
--
High

Reading History

ShotFPSFPEGunPowerProjectileCalWt

Gun Profiles

NameType

Projectile Profiles

NameTypeCalWt

WiFi

Mode: ?
WiFi: --

After saving, device will restart.

OTA Update

Version: ?

Control

"; + _server.send(200, "text/html", temp); } + void ChronoWebServer::_handleGunProfile(){ String temp="\ \ @@ -508,21 +347,107 @@ void handleOtaUpdateEnd() { ESP.restart(); } } -void ChronoWebServer::init(){ - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); +void setupSoftAp(const char* ssid, const char* password) { + + WiFi.mode(WIFI_AP); + IPAddress local_ip(192, 168, 4, 1); + IPAddress gateway(192, 168, 4, 1); + IPAddress subnet(255, 255, 255, 0); + + WiFi.softAPConfig(local_ip, gateway, subnet); + delay(100); + + WiFi.softAP(ssid, password);//, password); + delay(100); + + Serial.print("AP started: "); Serial.println(ssid); Serial.print("IP address: "); - Serial.println(WiFi.localIP()); + Serial.println(WiFi.softAPIP()); +} - if (MDNS.begin("esp32")) { - Serial.println("MDNS responder started"); +bool attemptStaConnection(const String& ssid, const String& password, int timeoutMs) { + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + + int attempts = 0; + int maxAttempts = timeoutMs / 500; + + while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) { + delay(500); + Serial.print("."); + attempts++; + } + + return WiFi.status() == WL_CONNECTED; +} + +void ChronoWebServer::init(){ + // Initialize NVS flash and erase WiFi config partition + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + Serial.println("NVS partition was truncated, erasing..."); + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + // Erase WiFi storage in NVS + nvs_handle_t handle; + err = nvs_open("storage", NVS_READWRITE, &handle); + if (err == ESP_OK) { + nvs_erase_all(handle); + nvs_commit(handle); + nvs_close(handle); + Serial.println("WiFi NVS storage erased"); + } else { + Serial.println("No WiFi NVS storage to erase"); + } + + WiFi.disconnect(true, true); + WiFi.mode(WIFI_OFF); + delay(100); + + // Try to load saved WiFi credentials + String savedSsid = getWifiSsid(); + String savedPassword = getWifiPassword(); + + Serial.print("Saved SSID from Preferences: '"); + Serial.print(savedSsid); + Serial.println("'"); + Serial.print("Saved Password length: "); + Serial.println(savedPassword.length()); + + bool connected = false; + + if (savedSsid.length() > 0) { + Serial.print("Attempting to connect to saved WiFi: "); + Serial.println(savedSsid); + connected = attemptStaConnection(savedSsid, savedPassword, 7000); + + if (connected) { + Serial.println(""); + Serial.print("Connected to "); + Serial.println(savedSsid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } else { + Serial.println(""); + Serial.println("Failed to connect to saved WiFi - starting AP mode"); + WiFi.disconnect(true, true); + WiFi.mode(WIFI_OFF); + delay(100); + } + } else { + Serial.println("No saved WiFi credentials - starting AP mode"); + } + + if (!connected) { + setupSoftAp("ChronoDisplay", "12345678"); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } } _server.on("/gunprofile/add", _handleAddGunProfile); @@ -538,9 +463,14 @@ void ChronoWebServer::init(){ _server.on("/format", _handleFormat); _server.on("/testmode", _handleTestMode); _server.on("/ota", HTTP_POST, [](){handleOtaUpdateEnd();}, [](){handleOtaUpdate();}); + _server.on("/wifi", HTTP_GET, _handleWifi); + _server.on("/wifisave", HTTP_POST, _handleWifiSave); + _server.on("/clearwifi", HTTP_POST, _handleClearWifi); + _server.on("/wifimode", HTTP_GET, _handleWifiMode); _server.on("/version", HTTP_GET, _handleVersion); _server.on("/", _handleRoot); _server.begin(); + } void ChronoWebServer::process(){ @@ -548,6 +478,53 @@ void ChronoWebServer::process(){ } void ChronoWebServer::_handleVersion() { - String versionJson = String("{\"version\":\"") + CHRONO_VERSION + "\",\"major\":" + String(CHRONO_VERSION_MAJOR) + ",\"minor\":" + String(CHRONO_VERSION_MINOR) + ",\"patch\":" + String(CHRONO_VERSION_PATCH) + "}"; + String versionJson = String("{'version':'") + CHRONO_VERSION + "','major':" + String(CHRONO_VERSION_MAJOR) + ",'minor':" + String(CHRONO_VERSION_MINOR) + ",'patch':" + String(CHRONO_VERSION_PATCH) + "}"; _server.send(200, "application/json", versionJson); +} + +void ChronoWebServer::_handleWifi() { + String ssid = getWifiSsid(); + _server.send(200, "text/plain", ssid); +} + +void ChronoWebServer::_handleWifiSave() { + if (_server.method() == HTTP_POST) { + String ssid = ""; + String password = ""; + if (_server.hasArg("ssid")) { + ssid = _server.arg("ssid"); + } + if (_server.hasArg("password")) { + password = _server.arg("password"); + } + saveWifiCredentials(ssid, password); + _server.send(200, "text/html", "ok"); + delay(1000); + ESP.restart(); + } +} + +void ChronoWebServer::_handleClearWifi() { + if (_server.method() == HTTP_POST) { + preferences.begin("wifi", false); + preferences.clear(); + preferences.end(); + _server.send(200, "text/html", "ok"); + delay(1000); + ESP.restart(); + } +} + +void ChronoWebServer::_handleWifiMode() { + String mode; + if (WiFi.getMode() == WIFI_STA) { + mode = "STA"; + } else if (WiFi.getMode() == WIFI_AP) { + mode = "AP"; + } else if (WiFi.getMode() == WIFI_AP_STA) { + mode = "AP+STA"; + } else { + mode = "NONE"; + } + _server.send(200, "text/plain", mode); } \ No newline at end of file diff --git a/ChronoWebServer.h b/ChronoWebServer.h index 3e0ad0b..219576f 100644 --- a/ChronoWebServer.h +++ b/ChronoWebServer.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "ChronoVersion.h" @@ -36,6 +37,10 @@ class ChronoWebServer { static void _handleTestMode(); static void _handleOta(); static void _handleVersion(); + static void _handleWifi(); + static void _handleWifiSave(); + static void _handleClearWifi(); + static void _handleWifiMode(); };