Waldemar Sakalus
Published © LGPL

Echo Dot Smart Control of Internal Speaker with 3.5mm Audio

When the 3.5mm audio is plugged in, it disconnects internal speaker. This project takes control of the behavior of the speaker.

IntermediateFull instructions provided4 hours7,113
Echo Dot Smart Control of Internal Speaker with 3.5mm Audio

Things used in this project

Hardware components

Echo Dot
Amazon Alexa Echo Dot
×1
Photon
Particle Photon
×1
optocoupler sharp pc817
×1
sunfounder 2 channel relay
×1

Software apps and online services

AWS Lambda
Amazon Web Services AWS Lambda

Story

Read more

Schematics

PCB

shortening pins 1&2 and 3&4 routes the audio to the internal speaker

Optocoupler interface to amplifier 12V trigger

Code

Photon code for Alexa internal speaker control (and serial controller)

Arduino
/*
  Krell- serial controller
  Waldemar Sakalus - SAKA
  version 01022018
 */

unsigned long resetTimer = millis();

TCPClient node;
byte nodeIP[] = { 192, 168, 1, 182 }; //put your Node_IP_address
String nodeResponse;

String nodeStatus = "Status";
String nodePlay = "Play";
String nodePause = "Pause";
String nodeSkip = "Skip";
String nodeBack = "Back";

const unsigned long smartInterval = 1000; //1s probing time, how often Node is checked whether playing/ stopped
unsigned long smartTimer = millis();

String nodeState = "";
String previousState = "";

int builtInLED = 7;
int ampOpto = D3;
int relayControl = D4;

byte triggerPreviousState;
byte alexaSpeaker = LOW;


void setup() {
    Serial1.blockOnOverrun(false);
    Serial1.begin(9600, SERIAL_8N1);
    Particle.function("KrellSerial", controlAmplifier);
    Particle.function("Node", controlNode);
    
    pinMode(builtInLED, OUTPUT);
    pinMode(ampOpto, INPUT);
    pinMode(relayControl, OUTPUT);
    
    triggerPreviousState = digitalRead(ampOpto);
    checkAmp();
    digitalWrite(relayControl, HIGH);
}

void loop() {
    if (digitalRead(ampOpto) != triggerPreviousState) {
        if (!checkAmp()) digitalWrite(relayControl, HIGH);
        triggerPreviousState = digitalRead(ampOpto);
    }
    if (smartTimer < millis()) {
        nodeCommand(nodeStatus);
        nodeState = tryExtractString(readNodeResponse(),"<state>","</state>");
        if (previousState != nodeState) {
            if (nodeState == "play" || nodeState == "stream") {
                Serial1.println("1PWRZ");
                Serial1.println("SS2MZ");
            }
            else if (nodeState == "pause") {
                Serial1.println("0PWRZ");
            }
            previousState = nodeState;
        }
        smartTimer = millis() + smartInterval;
    }
    
    // Reset after 12h of operation
    // ==================================
    if (millis() - resetTimer > 43200000) {
        System.reset();
    }
}

int controlAmplifier(String command)
{
    if (command != NULL) {
        if (command.startsWith("0PWRZ")) {
            Serial1.println("SS1MZ"); //defaults to input S1 before switching amplifier off
            Serial1.flush();
            //if (command.endsWith("bluesoundOff")) {
            stopNode();
            //}
            Serial1.println("0PWRZ");
            resetAlexaSpeaker;
        }
        else if (!(command.startsWith("1PWRZ"))) {
            Serial1.println(command);
            if (command.startsWith("SS2MZ")) startNode();
            else if (command.startsWith("SS1MZ") || command.startsWith("SS2MZ")) stopNode();
        }
        else if (command.startsWith("1PWRZ")) {
            Serial1.println("1PWRZ");
            Serial1.flush();
            if (command.endsWith("stereoOn")){
                Serial1.println("SS3MZ"); //defaults to input S3
                digitalWrite(relayControl, LOW);
                alexaSpeaker = HIGH;
            }
            else if (command.endsWith("recordOn")) {
                Serial1.println("SS1MZ"); //defaults to input S1
                resetAlexaSpeaker; 
            }
            else if (command.endsWith("bluesoundOn")) {
                Serial1.println("SS2MZ"); //defaults to input S2
                startNode();
                resetAlexaSpeaker;
            }
        }
        return 1;
    }
    else return -1;
}

void resetAlexaSpeaker()
{
    if (alexaSpeaker) {
        digitalWrite(relayControl, HIGH);
        alexaSpeaker = LOW;
    }
}

int controlNode(String command)
{
    if (command != NULL) {
        if (command == "Play") nodeCommand(nodePlay);
        else if (command == "Pause") nodeCommand(nodePause);
        else if (command == "Stop") nodeCommand(nodePause);
        else if (command == "Next") nodeCommand(nodeSkip);
        else if (command == "Previous") nodeCommand(nodeBack);
        return 1;
    }
    else return -1;
}

void startNode() {
    nodeCommand(nodeStatus);
    nodeState = tryExtractString(readNodeResponse(),"<state>","</state>");
    if (nodeState == "pause") nodeCommand(nodePlay);
}

void stopNode() {
    nodeCommand(nodeStatus);
    nodeState = tryExtractString(readNodeResponse(),"<state>","</state>");
    if (nodeState == "play" || nodeState == "stream") nodeCommand(nodePause);
}

void nodeCommand(String command)
{
    if (node.connect(nodeIP, 11000))
    {
        String post = "GET /";
        post += command;
        post += " HTTP/1.1\r\n";
        post += "Host: ";
        post += nodeIPString();
        post += ":1400\r\n";
        post += "Cache-Control: no-cache\r\n\r\n";
        //Serial.println(post);
        node.print(post);

        delay(10);
    }
    else Serial.println("connection failed");
}

byte checkAmp () {
    byte ampRead = digitalRead(ampOpto);
    if (ampRead) {
        digitalWrite(builtInLED, LOW);
        return LOW;
    }
    else {
        digitalWrite(builtInLED, HIGH);
        return HIGH;
    }
}

String readNodeResponse() {
    unsigned long lastdata = millis();
    String nodeResponse = "";
    while (node.connected()  || (millis()-lastdata < 500)) { //500ms timeout
        if (node.available()) {
            char c = node.read();
            nodeResponse += c;
            lastdata = millis();
        }
    }
    node.flush();
    node.stop();
    return nodeResponse;
}


String nodeIPString(){
    String addressIP = "";
    for (int i = 0; i < 4; i++) {
        addressIP += nodeIP[i];
        if (i < 3) {
            addressIP += ".";
        }
    }
    return addressIP;
}

String tryExtractString(String str, const char* start, const char* end) {
    if (str == NULL) {
        return "";
    }

    int idx = str.indexOf(start);
    if (idx < 0) {
        return "";
    }

    int endIdx = str.indexOf(end);
    if (endIdx < 0) {
        return "";
    }

    return str.substring(idx + strlen(start), endIdx);
}

Credits

Waldemar Sakalus

Waldemar Sakalus

4 projects • 18 followers

Comments