From 91b24e0da004dda2f5a2498a699d5984d3ae9645 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 25 Apr 2025 19:00:28 +0200 Subject: [PATCH] feat(data) undefined: Added new HTML file for piano spectrum analyzer. fix(Config.h): Updated WiFi settings and web configuration portal details. refactor(Arduino sketch): Added WiFi and WebSocket support, enabling real-time spectrum data transmission over the - New HTML file added to the `data` directory for a piano spectrum analyzer. - Updated `Config.h` with WiFi settings and web configuration portal details. - Update the Arduino sketch with WiFi and WebSocket support, enabling real-time spectrum data transmission over the web. --- data/index.html | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ include/Config.h | 6 ++++ src/main.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 data/index.html diff --git a/data/index.html b/data/index.html new file mode 100644 index 0000000..c4ad5a3 --- /dev/null +++ b/data/index.html @@ -0,0 +1,91 @@ + + + + ESP32 Piano Spectrum Analyzer + + + + +
+

Piano Spectrum Analyzer

+
+ +
+
+ + + + \ No newline at end of file diff --git a/include/Config.h b/include/Config.h index f229331..bf8eccc 100644 --- a/include/Config.h +++ b/include/Config.h @@ -6,6 +6,12 @@ namespace Config { // Serial Configuration constexpr int SERIAL_BAUD_RATE = 115200; // Serial communication baud rate + // WiFi Configuration + constexpr const char* WIFI_AP_NAME = "ESP32Piano"; // AP name when in configuration mode + constexpr const char* WIFI_AP_PASSWORD = "12345678"; // AP password when in configuration mode + constexpr uint32_t WIFI_CONFIG_TIMEOUT = 180; // Seconds to wait for WiFi configuration + constexpr uint32_t WIFI_CONFIG_PORT = 80; // Web configuration portal port + // I2S Pin Configuration constexpr int I2S_MIC_SERIAL_CLOCK = 8; // SCK constexpr int I2S_MIC_LEFT_RIGHT_CLOCK = 9; // WS/LRC diff --git a/src/main.cpp b/src/main.cpp index cd8a0cd..cd5e978 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,9 @@ #include +#include +#include +#include +#include +#include #include "Config.h" #include "I2SConfig.h" #include "AudioLevelTracker.h" @@ -9,15 +14,55 @@ static int16_t raw_samples[Config::SAMPLE_BUFFER_SIZE]; static AudioLevelTracker audioLevelTracker; static NoteDetector noteDetector; +WiFiManager wifiManager; +AsyncWebServer server(80); +AsyncWebSocket ws("/ws"); // Timing and state variables static uint32_t lastNotePrintTime = 0; static uint32_t lastSpectrumPrintTime = 0; +static uint32_t lastWebUpdateTime = 0; static bool showSpectrum = false; // Note names for display const char* noteNames[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; +void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { + switch (type) { + case WS_EVT_CONNECT: + Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); + break; + case WS_EVT_DISCONNECT: + Serial.printf("WebSocket client #%u disconnected\n", client->id()); + break; + case WS_EVT_DATA: + break; + case WS_EVT_ERROR: + break; + } +} + +void initWebServer() { + if (!SPIFFS.begin(true)) { + Serial.println("An error occurred while mounting SPIFFS"); + return; + } + + ws.onEvent(onWebSocketEvent); + server.addHandler(&ws); + + // Serve static files from SPIFFS + server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html"); + + // Handle not found + server.onNotFound([](AsyncWebServerRequest *request) { + request->send(404, "text/plain", "Not found"); + }); + + server.begin(); + Serial.println("HTTP server started"); +} + void handleSerialCommands() { if (Serial.available()) { char cmd = Serial.read(); @@ -55,19 +100,54 @@ void printNoteInfo(const DetectedNote& note) { noteNames[noteIndex], octave, note.frequency, note.magnitude, duration); } +void initWiFi() { + // Set configuration portal timeout + wifiManager.setConfigPortalTimeout(Config::WIFI_CONFIG_TIMEOUT); + + // Set custom portal settings + wifiManager.setAPStaticIPConfig(IPAddress(192,168,4,1), IPAddress(192,168,4,1), IPAddress(255,255,255,0)); + + // Try to connect to saved WiFi credentials + if(!wifiManager.autoConnect(Config::WIFI_AP_NAME, Config::WIFI_AP_PASSWORD)) { + Serial.println("Failed to connect and hit timeout"); + ESP.restart(); + } + + Serial.println("Successfully connected to WiFi"); + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); +} + void setup() { Serial.begin(Config::SERIAL_BAUD_RATE); while(!Serial) { delay(10); } + initWiFi(); + initWebServer(); initI2S(); + Serial.println("Piano Note Detection Ready (C2-C6)"); Serial.println("Press 'h' for help"); noteDetector.beginCalibration(); } +void sendSpectrumData() { + if (ws.count() > 0 && !noteDetector.isCalibrating()) { + const auto& spectrum = noteDetector.getSpectrum(); + String json = "["; + for (size_t i = 0; i < Config::FFT_SIZE/2; i++) { + if (i > 0) json += ","; + json += String(spectrum[i], 2); + } + json += "]"; + ws.textAll(json); + } +} + void loop() { + ws.cleanupClients(); handleSerialCommands(); size_t bytes_read = 0; @@ -88,11 +168,16 @@ void loop() { uint32_t currentTime = millis(); const auto& detectedNotes = noteDetector.getDetectedNotes(); + // Update web clients with spectrum data + if (currentTime - lastWebUpdateTime >= 50) { // Update web clients every 50ms + sendSpectrumData(); + lastWebUpdateTime = currentTime; + } + // Show spectrum if enabled if (showSpectrum && !noteDetector.isCalibrating() && currentTime - lastSpectrumPrintTime >= Config::DEBUG_INTERVAL_MS) { - SpectrumVisualizer::visualizeSpectrum(noteDetector.getSpectrum(), Config::FFT_SIZE); lastSpectrumPrintTime = currentTime; } @@ -106,6 +191,6 @@ void loop() { } } - // Small delay to prevent serial buffer overflow - delay(10); + // Small delay to prevent WDT reset + delay(1); } \ No newline at end of file