From bb9b151493bd83996738fa5366a34c5bceb3a780 Mon Sep 17 00:00:00 2001 From: sam rolfe Date: Mon, 8 Dec 2025 12:43:46 +1100 Subject: [PATCH] LED functionality change. --- voice_assistant.ino | 147 ++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 81 deletions(-) diff --git a/voice_assistant.ino b/voice_assistant.ino index 22393e7..9b00367 100644 --- a/voice_assistant.ino +++ b/voice_assistant.ino @@ -13,14 +13,14 @@ const char* MQTT_USER = "MQTT_USER_REDACTED"; const char* MQTT_PASS = "MQTT_PASS_REDACTED"; const char* TOPIC_AUDIO = "voice/audio_stream"; -const char* TOPIC_ACK = "voice/status"; +const char* TOPIC_STATUS = "voice/status"; // --- HARDWARE --- #define I2S_SCK 4 #define I2S_WS 5 #define I2S_SD 6 #define I2S_PORT I2S_NUM_0 -#define LED_PIN 1 +#define LED_PIN 1 // Updated to Pin 1 #define NUM_LEDS 12 // --- TUNING --- @@ -28,12 +28,18 @@ const char* TOPIC_ACK = "voice/status"; const int BLOCK_SIZE = 512; int16_t sBuffer[BLOCK_SIZE]; -// --- OBJECTS --- WiFiClient espClient; PubSubClient mqtt(espClient); Freenove_ESP32_WS2812 strip(NUM_LEDS, LED_PIN, 0, TYPE_GRB); -enum DeviceState { STATE_IDLE, STATE_RECORDING, STATE_TRANSMITTING, STATE_ACK_RECEIVED }; +// --- STATES --- +enum DeviceState { + STATE_IDLE, + STATE_STREAMING, // Sending audio (LED OFF) + STATE_LISTENING, // Wake Word Confirmed (LED BLUE) + STATE_PROCESSING, // Sending to Whisper (LED RED) + STATE_SUCCESS // Done (LED GREEN) +}; DeviceState currentState = STATE_IDLE; unsigned long stateTimer = 0; @@ -56,95 +62,72 @@ const i2s_pin_config_t pin_config = { .data_in_num = I2S_SD }; +// --- LED HELPER --- void setRingColor(uint8_t r, uint8_t g, uint8_t b) { strip.setAllLedsColor(r, g, b); strip.show(); } -void updateLEDs() { - if (currentState == STATE_ACK_RECEIVED) { - for (int j = 0; j < 255; j += 20) { - for (int i = 0; i < NUM_LEDS; i++) { - byte pos = (i * 256 / NUM_LEDS + j) & 255; - strip.setLedColorData(i, pos, 255-pos, 0); // Simple fast rainbow - } - strip.show(); - delay(5); - } - currentState = STATE_IDLE; - setRingColor(0,0,0); - } -} - +// --- MQTT HANDLING --- void mqttCallback(char* topic, byte* payload, unsigned int length) { - Serial.print("MSG Recv: "); Serial.println(topic); - currentState = STATE_ACK_RECEIVED; + char msg[length + 1]; + memcpy(msg, payload, length); + msg[length] = '\0'; // Null terminate + + String message = String(msg); + Serial.print("Status Recv: "); Serial.println(message); + + if (message == "WAKE") { + // Server heard "Hey Jarvis" + currentState = STATE_LISTENING; + setRingColor(0, 0, 255); // BLUE + } + else if (message == "OK") { + // Command executed + currentState = STATE_SUCCESS; + stateTimer = millis(); + setRingColor(0, 255, 0); // GREEN + } } void setup() { - delay(3000); // Wait for Serial + delay(2000); Serial.begin(115200); - Serial.println("\n\n=== BOOTING DEBUG MODE ==="); - // 1. LEDs + mqtt.setBufferSize(2048); + strip.begin(); strip.setBrightness(30); - setRingColor(50, 50, 50); // White - Serial.println("1. LEDs Ready"); + setRingColor(50, 50, 50); // White on Boot - // 2. I2S - if (i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL) != ESP_OK) { - Serial.println("ERR: I2S Driver Fail"); - } else { - i2s_set_pin(I2S_PORT, &pin_config); - Serial.println("2. I2S Ready"); - } + i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); + i2s_set_pin(I2S_PORT, &pin_config); - // 3. WiFi - Serial.print("3. WiFi Connecting: "); - Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASS); - - int wifi_timeout = 0; while (WiFi.status() != WL_CONNECTED) { delay(500); - Serial.print("."); - setRingColor(0, 0, 255); delay(100); setRingColor(0,0,0); - wifi_timeout++; - if(wifi_timeout > 20) { - Serial.println("\nERR: WiFi Timeout! Checking Creds..."); - wifi_timeout = 0; // Keep trying or reset? - } + setRingColor(0, 0, 100); delay(100); setRingColor(0,0,0); } - Serial.print("\n WiFi Connected! IP: "); - Serial.println(WiFi.localIP()); - // 4. MQTT mqtt.setServer(MQTT_BROKER, MQTT_PORT); mqtt.setCallback(mqttCallback); - mqtt.setBufferSize(2048); // Vital for audio - Serial.println("4. MQTT Configured"); - setRingColor(0,0,0); - Serial.println("=== SYSTEM READY ==="); + setRingColor(0,0,0); // Idle = Off } void loop() { - // MQTT Reconnect Handler if (!mqtt.connected()) { - Serial.print("MQTT Connecting to "); Serial.print(MQTT_BROKER); Serial.print(" ... "); if (mqtt.connect("ESP32Mic", MQTT_USER, MQTT_PASS)) { - Serial.println("CONNECTED"); - mqtt.subscribe(TOPIC_ACK); - setRingColor(0, 255, 0); delay(500); setRingColor(0,0,0); // Flash Green on Connect - } else { - Serial.print("FAIL rc="); Serial.println(mqtt.state()); - delay(2000); - return; + mqtt.subscribe(TOPIC_STATUS); } } mqtt.loop(); - updateLEDs(); + + // Reset Success/Green LED after 3 seconds + if (currentState == STATE_SUCCESS && millis() - stateTimer > 3000) { + currentState = STATE_IDLE; + setRingColor(0,0,0); + } size_t bytesRead; i2s_read(I2S_PORT, &sBuffer, sizeof(sBuffer), &bytesRead, portMAX_DELAY); @@ -157,42 +140,44 @@ void loop() { sBuffer[i] = (int16_t)boosted; } + // Calculate Volume long sum = 0; for (int i = 0; i < bytesRead / 2; i++) { sum += abs(sBuffer[i]); } int avg = sum / (bytesRead / 2); - - // Uncomment to debug sensitivity - // Serial.printf("Vol: %d\n", avg); - // Trigger Logic + // --- LOGIC --- + + // 1. Detect Sound (Invisible) if (currentState == STATE_IDLE && avg > VAD_THRESHOLD) { - Serial.println("TRIGGERED"); - currentState = STATE_RECORDING; + currentState = STATE_STREAMING; stateTimer = millis(); - setRingColor(0, 255, 0); // Green + // LED stays OFF (We don't know if it's Jarvis yet) - // START OF SENTENCE FIX: Send the trigger buffer immediately + // Send trigger buffer mqtt.publish(TOPIC_AUDIO, (const uint8_t*)sBuffer, bytesRead); } - if (currentState == STATE_RECORDING) { + // 2. Stream Audio + // We stream if we are just hearing noise OR if we are actively listening for a command + if (currentState == STATE_STREAMING || currentState == STATE_LISTENING) { mqtt.publish(TOPIC_AUDIO, (const uint8_t*)sBuffer, bytesRead); if (avg > VAD_THRESHOLD) stateTimer = millis(); + // Silence Timeout (1.5s) if (millis() - stateTimer > 1500) { - Serial.println("SILENCE DETECTED"); - currentState = STATE_TRANSMITTING; - mqtt.publish("voice/status", "processing"); - setRingColor(0, 0, 255); // Blue + if (currentState == STATE_LISTENING) { + // If we were listening, now we process + currentState = STATE_PROCESSING; + mqtt.publish(TOPIC_STATUS, "processing"); + setRingColor(255, 0, 0); // RED (Thinking) + } else { + // If we were just streaming noise and never heard Jarvis, go back to sleep + currentState = STATE_IDLE; + setRingColor(0, 0, 0); + } } } - - if (currentState == STATE_TRANSMITTING && millis() - stateTimer > 4000) { - Serial.println("TIMEOUT WAIT"); - currentState = STATE_IDLE; - setRingColor(0,0,0); - } }