#include "ChronoWebServer.h" #include #include #include #include #include #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(); } WebServer _server(80); void (*testModeCallback)(); // Constructor implementation ChronoWebServer::ChronoWebServer() {} void ChronoWebServer::_handleRoot() { String temp="\ \ FX Chronograph Display Settings\ \ \ \ \

ChronoDisplay Settings

\
\

Control Panel

\ \ \ \ \
\
\

WiFi Configuration

\

Mode: Unknown

\

Current WiFi: Not configured

\
\
\
\
\
\
\ \
\

After saving, the device will attempt to connect to the new WiFi network.

\ \
\
\
\

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); } void ChronoWebServer::_handleGunProfile(){ String temp="\ \ Gun Profile\ \ \ \ \

Add Gun Profile

\
\

Name

\ \

Type

\ \
\
\ \ "; _server.send(200, "text/html", temp); } void ChronoWebServer::_handleAddGunProfile(){ if (_server.method() == HTTP_POST){ String name="Default"; GunProfile::GunProfileType type=GunProfile::PROFILE_TYPE_AIR_GUN_FAC; float caliber=0.0; float weight=0.0; if (_server.hasArg("name")){name=_server.arg("name");} if (_server.hasArg("type")){ String st=_server.arg("type"); if (strcmp(st.c_str(),"0")==0){type=GunProfile::PROFILE_TYPE_BOW_AIRSOFT;} else if (strcmp(st.c_str(),"1")==0){type=GunProfile::PROFILE_TYPE_CO2_PISTOL;} else if (strcmp(st.c_str(),"2")==0){type=GunProfile::PROFILE_TYPE_AIR_PISTOL;} else if (strcmp(st.c_str(),"3")==0){type=GunProfile::PROFILE_TYPE_AIR_GUN_UK;} else if (strcmp(st.c_str(),"4")==0){type=GunProfile::PROFILE_TYPE_AIR_GUN_FAC;} } ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); GunProfile p(name,type); chronoReadings.addGunProfile(p); } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleSetGunProfile(){ if (_server.method() == HTTP_POST){ if (_server.hasArg("id")){ int id=_server.arg("id").toInt(); ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); chronoReadings.setGunProfile(id); //update profile with chronograph int type=chronoReadings.getProfile().getGunProfile().getPowerLevel(); ChronoBLE::changeGunType(type); //update display Display::updateProfile(chronoReadings.getProfile()); Display::refreshDisplay(); } } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleRemoveGunProfile(){ if (_server.method() == HTTP_POST){ if (_server.hasArg("id")){ int id=_server.arg("id").toInt(); ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); chronoReadings.removeGunProfile(id); } } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleProjectileProfile(){ String temp="\ \ Projectile Profile\ \ \ \ \

Add Projectile Profile

\
\

Name

\ \

Type

\ \

Caliber

\ \

Weight

\ \
\
\ \ "; _server.send(200, "text/html", temp); } void ChronoWebServer::_handleSetProjectileProfile(){ if (_server.method() == HTTP_POST){ if (_server.hasArg("id")){ int id=_server.arg("id").toInt(); ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); chronoReadings.setProjectileProfile(id); Display::updateProfile(chronoReadings.getProfile()); Display::refreshDisplay(); } } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleAddProjectileProfile(){ String message = "Got request...\n\n"; message += "URI: "; message += _server.uri(); message += "\nMethod: "; message += (_server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += _server.args(); message += "\n"; for (uint8_t i = 0; i < _server.args(); i++) { message += " " + _server.argName(i) + ": " + _server.arg(i) + "\n"; } Serial.println(message); if (_server.method() == HTTP_POST){ String name=""; ProjectileProfile::ProjectileType type=ProjectileProfile::PELLET; float caliber=0.0; float weight=0.0; if (_server.hasArg("name")){name=_server.arg("name");} if (_server.hasArg("type")){ String st=_server.arg("type"); if (strcmp(st.c_str(),"slug")==0){ type=ProjectileProfile::SLUG; } } if (_server.hasArg("cal")){caliber=_server.arg("cal").toFloat();} if (_server.hasArg("weight")){weight=_server.arg("weight").toFloat();} ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); ProjectileProfile pp(name,type,caliber,weight); chronoReadings.addProjectileProfile(pp); } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleRemoveProjectileProfile(){ if (_server.method() == HTTP_POST){ if (_server.hasArg("id")){ int id=_server.arg("id").toInt(); ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); chronoReadings.removeProjectileProfile(id); } } _server.send(200, "text/html", "ok"); } void ChronoWebServer::_handleExport(){ ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); LinkedList& readings=chronoReadings.getChronographReadings(); int count=readings.size(); Serial.print("exporting "); Serial.print(count); Serial.println(" readings to csv..."); //return csv data String csvData = "Shot #,FPS,FPE,Gun,Power,Projectile,Type,Caliber,Weight\n"; for (int i=0; i 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); _server.on("/gunprofile/set", _handleSetGunProfile); _server.on("/gunprofile/remove", _handleRemoveGunProfile); _server.on("/gunprofile", _handleGunProfile); _server.on("/projectileprofile/set", _handleSetProjectileProfile); _server.on("/projectileprofile/add", _handleAddProjectileProfile); _server.on("/projectileprofile/remove", _handleRemoveProjectileProfile); _server.on("/projectileprofile", _handleProjectileProfile); _server.on("/export", _handleExport); _server.on("/reset", _handleReset); _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(){ _server.handleClient(); } void ChronoWebServer::_handleVersion() { 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); }