Waldemar Sakalus
Published © GPL3+

Automate Bluesound's Node with Amplifier and Alexa Control

The Node is an audiophile streamer. However the convenience is hampered by the need to switch on/off the amplifier. This automates the task.

IntermediateFull instructions provided4 hours2,546
Automate Bluesound's Node with Amplifier and Alexa Control

Things used in this project

Hardware components

Photon
Particle Photon
×1
ns-rs232
×1

Software apps and online services

AWS Lambda
Amazon Web Services AWS Lambda
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit

Story

Read more

Schematics

Seral controller

For detailed description see https://www.hackster.io/saka/alexa-voice-control-for-almost-any-amplifier-tv-cd-dvd-87fff1

Code

Particle Photon firmware

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

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 = "";


void setup() {
    Serial1.blockOnOverrun(false);
    Serial1.begin(9600, SERIAL_8N1);
    Particle.function("KrellSerial", controlAmplifier);
    Particle.function("Node", controlNode);
}

void loop() {
    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");
        }
        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
            else if (command.endsWith("recordOn")) Serial1.println("SS1MZ"); //defaults to input S1
            else if (command.endsWith("bluesoundOn")) {
                Serial1.println("SS2MZ"); //defaults to input S2
                startNode();
            }
            else if (command.endsWith("echoOn")) Serial1.println("SS3MZ"); //defaults to input S3
        }
        return 1;
    }
    else return -1;
}

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");
}

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

Add projectSign up / Login