From 3943b00dace6587cb7f3483592013f0cc353b837 Mon Sep 17 00:00:00 2001 From: sam rolfe Date: Mon, 8 Dec 2025 13:30:40 +1100 Subject: [PATCH] Led yellow on response, returns to standby if no response. --- voice_assistant.ino | 56 +++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/voice_assistant.ino b/voice_assistant.ino index 9b00367..e5605b1 100644 --- a/voice_assistant.ino +++ b/voice_assistant.ino @@ -20,7 +20,7 @@ const char* TOPIC_STATUS = "voice/status"; #define I2S_WS 5 #define I2S_SD 6 #define I2S_PORT I2S_NUM_0 -#define LED_PIN 1 // Updated to Pin 1 +#define LED_PIN 1 #define NUM_LEDS 12 // --- TUNING --- @@ -35,10 +35,11 @@ Freenove_ESP32_WS2812 strip(NUM_LEDS, LED_PIN, 0, TYPE_GRB); // --- 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) + STATE_STREAMING, // Noise detected (Green) + STATE_LISTENING, // Wake Word Confirmed (Blue) + STATE_PROCESSING, // Sending to Server (Red) + STATE_SUCCESS, // Done (Yellow) + STATE_ERROR // Timeout (Blink Red) }; DeviceState currentState = STATE_IDLE; unsigned long stateTimer = 0; @@ -72,21 +73,22 @@ void setRingColor(uint8_t r, uint8_t g, uint8_t b) { void mqttCallback(char* topic, byte* payload, unsigned int length) { char msg[length + 1]; memcpy(msg, payload, length); - msg[length] = '\0'; // Null terminate + msg[length] = '\0'; String message = String(msg); - Serial.print("Status Recv: "); Serial.println(message); + // Serial.print("Recv: "); Serial.println(message); // Debug if (message == "WAKE") { - // Server heard "Hey Jarvis" + // Server heard "Hey Jarvis" -> Turn BLUE currentState = STATE_LISTENING; - setRingColor(0, 0, 255); // BLUE + stateTimer = millis(); // Reset timer to prevent premature timeout + setRingColor(0, 0, 255); } else if (message == "OK") { - // Command executed + // Command executed -> Turn YELLOW currentState = STATE_SUCCESS; stateTimer = millis(); - setRingColor(0, 255, 0); // GREEN + setRingColor(255, 200, 0); // Yellow/Orange } } @@ -98,7 +100,7 @@ void setup() { strip.begin(); strip.setBrightness(30); - setRingColor(50, 50, 50); // White on Boot + setRingColor(50, 50, 50); // White Boot i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); i2s_set_pin(I2S_PORT, &pin_config); @@ -112,7 +114,7 @@ void setup() { mqtt.setServer(MQTT_BROKER, MQTT_PORT); mqtt.setCallback(mqttCallback); - setRingColor(0,0,0); // Idle = Off + setRingColor(0,0,0); // Idle } void loop() { @@ -123,7 +125,18 @@ void loop() { } mqtt.loop(); - // Reset Success/Green LED after 3 seconds + // --- TIMEOUT LOGIC (Fixes the "Lock Up") --- + if (currentState == STATE_PROCESSING && millis() - stateTimer > 6000) { + // We waited 6 seconds for an answer, but got nothing. + // Blink Red 3 times then Reset. + for(int i=0; i<3; i++) { + setRingColor(255, 0, 0); delay(200); + setRingColor(0, 0, 0); delay(200); + } + currentState = STATE_IDLE; + } + + // Reset "Success" yellow light after 3 seconds if (currentState == STATE_SUCCESS && millis() - stateTimer > 3000) { currentState = STATE_IDLE; setRingColor(0,0,0); @@ -140,27 +153,25 @@ 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); - // --- LOGIC --- + // --- AUDIO LOGIC --- - // 1. Detect Sound (Invisible) + // 1. Detect Noise -> Green if (currentState == STATE_IDLE && avg > VAD_THRESHOLD) { currentState = STATE_STREAMING; stateTimer = millis(); - // LED stays OFF (We don't know if it's Jarvis yet) + setRingColor(0, 255, 0); // Green (I hear you) // Send trigger buffer mqtt.publish(TOPIC_AUDIO, (const uint8_t*)sBuffer, bytesRead); } // 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); @@ -169,12 +180,13 @@ void loop() { // Silence Timeout (1.5s) if (millis() - stateTimer > 1500) { if (currentState == STATE_LISTENING) { - // If we were listening, now we process + // We were talking to Jarvis, now we wait for reply currentState = STATE_PROCESSING; + stateTimer = millis(); // Start timeout timer mqtt.publish(TOPIC_STATUS, "processing"); - setRingColor(255, 0, 0); // RED (Thinking) + setRingColor(255, 0, 0); // Red (Thinking/Wait) } else { - // If we were just streaming noise and never heard Jarvis, go back to sleep + // Just noise, never woke up currentState = STATE_IDLE; setRingColor(0, 0, 0); }