Simon Fell > Its just code > Power Amp trigger from Roon

Saturday, January 19, 2019

I recently got a new power amp for my hifi setup, and it has a 12v trigger input. The trigger input allows for an external signal to turn the amplifer on or off. Its usually connected to a central item so that everything can turned on/off together. I also use Roon, which is a great network music player.

While remembering to turn the amp on is not a problem, remembering to turn it off can be a problem for various reasons. I thought it'd be a fun little project to use the Roon API to have the amp turn on automatically when roon starts playing, and to have it automatically turn off in the evening.

I hatched a plan, using the Sparkfun Thing board, this is a little Wifi enabled processor that has some basic I/O pins and can be programmed using the Arduino software.

  • A node app using the roon api listens for state changes in a particular output zone.
  • It sends a TCP message over Wifi to the Thing board which turns a relay on.
  • The relay is inline in the trigger connection from the preamp to the power amp.
  • At a particular time of day, the node app sends the message to turn the relay off.


The Hardware

I used the Sparkfun Thing Dev Board and a Relay Kit. The actual relay in the kit is overkill for this use case of switching a low current low voltage signal, but it'll work fine.



First up, build the relay kit, the sparkfun instructions are clear & detailed, and its an easy build for anyone who's used a soldering iron before.


Next up, I used a breadboard to connect the relay board to the Thing board, the Thing board conviently has 5v & ground pins you can use to power the relay board, and I connected Thing's GPIO pin 4 to the control input on the relay board.


After testing with the software, I installed the 2 boards in a little box and connected a pair of mono 3.5mm jacks to the relay switch.


Thing Software

You can program the Thing using the Arduino IDE over USB, simple!. What we need for this is to join the Wifi network, listen on a TCP port, read messages from a client and turn pin 4 on or off.

I used a simple 4 byte TCP message format that supported 3 request messages, STAT, UON & UOFF, which return the current state, turn the output on and turn the ouput off.

The core loop ends up looking like

        void loop() {
          // Check if a client has connected
          WiFiClient client = server.available();
          if (!client) {
            return;
          }
          // Wait til there's a 4 byte message ready
          while (client.available() < 4) {
            delay(5);
          }
          uint8_t buff[4];
          int x = client.read(buff, 4);
          if (buff[0] == 'S' && buff[1] == 'T' && buff[2] == 'A' && buff[3] == 'T') {
              int state = digitalRead(RELAY_PIN);
              client.print(state == HIGH ?"ON  \n": "OFF \n");

          } else if (buff[0] == 'U' && buff[1] == 'O' && buff[2] == 'N') {
              digitalWrite(RELAY_PIN, HIGH);
              delay(1000);
              client.print("ON  \n");

          } else if (buff[0] == 'U' && buff[1] == 'O' && buff[2] == 'F' && buff[3] == 'F') {
              digitalWrite(RELAY_PIN, LOW);
              delay(1000);
              client.print("OFF \n");
          }
          client.flush();
          client.stop();
        }
    

Roon API Software

The Roon API ships as a node.js based library. Our code is pretty straightforward
  • Do a dance to connect to a Roon server.
  • Listen for zone state changes for a particular zone.
  • If the zone started playing send the 'UON ' message to the thing endpoint.
  • At a certain time of day, send the 'UOFF' message to the thing endpoint.
Sending a TCP message is easy enough from node.js,
    var client = new net.Socket();    
    client.connect(triggerPort, triggerHost, function() {
        // Write a message to the socket as soon as the client is connected, the server will receive it as message from the client 
        client.write(msg);
    });

    // Add a 'data' event handler for the client socket
    // data is what the server sent to this socket
    client.on('data', function(data) {
        console.log('TRIGGER SAID: ' + data.slice(0,4));
        // Close the client socket completely
        client.destroy();
        callback(data)
    });
    
You need somewhere you can leave this running, I run it on the Raspberry Pi I have that runs pihole.

Wrap-up

This was a fun little project, and a nice change of scenery from my day job. The Thing is a great little board for building integrations like this. The full code for both the Thing & the Roon integration is available on Github.