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.
This commit is contained in:
91
data/index.html
Normal file
91
data/index.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ESP32 Piano Spectrum Analyzer</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
#spectrum-container {
|
||||
position: relative;
|
||||
height: 400px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Piano Spectrum Analyzer</h1>
|
||||
<div id="spectrum-container">
|
||||
<canvas id="spectrumChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const ctx = document.getElementById('spectrumChart').getContext('2d');
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: Array.from({length: 512}, (_, i) => i * (8000 / 1024)),
|
||||
datasets: [{
|
||||
label: 'Frequency Spectrum',
|
||||
data: Array(512).fill(0),
|
||||
borderColor: 'rgb(75, 192, 192)',
|
||||
tension: 0.1,
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: {
|
||||
duration: 0
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 5000
|
||||
},
|
||||
x: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Frequency (Hz)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const wsUrl = `ws://${window.location.hostname}/ws`;
|
||||
const ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
const spectrum = JSON.parse(event.data);
|
||||
chart.data.datasets[0].data = spectrum;
|
||||
chart.update();
|
||||
};
|
||||
|
||||
ws.onclose = function() {
|
||||
console.log('WebSocket connection closed');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
91
src/main.cpp
91
src/main.cpp
@@ -1,4 +1,9 @@
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <SPIFFS.h>
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user