The Sonos Port has a trigger port (3.5mm mono jack) that supplies 200mA, and has 12v when music is playing. 2 minutes after music has stopped, the voltage drops.

I didn't like the idea of the amp staying on. And I didn't want to have to go upstairs to turn it on when I wanted to play music.

To make the solution work across most amps I decided to use infrared (IR). (my Amp was a multi-room Teac, also had an RS232 remote but I've not seen that very often so decided to stick with IR). I found that my Teac Amp AG980 used NEC IR codes. For testing I tried in on my receiver in the front-room (Sony).

I am a novice when it comes to electronics but thought this was a genuinely useful device. I spent ages searching online to piece together what was needed so thought this may help others if I post online.

I used an ESP32 Firebeetle due to it only consuming around 20mA (in slower CPU modes) - but other boards may have similar current consumption and be cheaper - you don't need Bluetooth, wifi or a fast CPU.

You could also use a native Arduino board. There are different libraries for ESP32 IR control to Arduino. My first attempt was using an Arduino - I got it working relatively quickly. Decided to move to a cheaper/smaller ESP32 board - but took a while to get it working due to library issues.

I also found doing it in two steps is easier - first build a device to read the IR remotes codes, note them down. Simple to do - lots of online examples. Then build the main device using a visible LED so you can see it flicker when transmitting. Then replace the LED with the IR LED.

If I had more time (I have a day job!) you could make this into a hybrid "learning" and "sending" device. Hold down one button to learn "turn off" commands, hold another to learn "turn on" commands. Because 12v triggers are standard across a lot of audio devices- could be useful for a range of purposes.

For troubleshooting I found my laptop camera could see the IR LED flicker when transmitting (my iphone camera could not - apparently newer models have an IR filter).

The main challenge was turning off the amp when the 12v signal goes because the ESP32 no longer has power. I wanted to use a capacitor which would get charged when live, then the ESP32 would send the IR codes when power goes. I ended up using a super capacitor (5.5v 1F). This may be overkill but it isn't too large (cost £10) - it will power the ESP32 for about 10 seconds (more than enough time).

Remember that a capacitors voltage drops on discharge. This means it starts supplying the ESP32 5v (output from the regulator). The esp32 can function down to 2.55v which means as the capacitor discharges we have time to perform our shutdown commands. However, if you use an Arduino that needs a minimum of 5v you could supply it directly with the 12v from the Sonos Port but then design a way of detecting the voltage drop. My first version (before I moved to ESP32 and the regulator) was based on this

I bought a voltage regulator to convert the 12v from the Sonos Port to 5v for ESP32. I found one with a PG (Power-Good) output, this signals the ESP32 that the power has dropped when the music has stopped. This particular board has a number of other safety features. I didn't need to use rectifier diodes to block backvoltage from the capacitor.

Some IR LEDs consume a lot of power which drains the capacitor too quickly. Because long distances are not necessary, I went for lower power ones (after struggling with higher power ones which can consume 200ma and deplete the capacitor too quickly).

And used a 75ohm resistor on the IR LED.

I've drawn a pretty awful diagram of the wiring - I'm not sure of the proper symbols, sorry.

Sonos 12V to input of regulator

VCC - +Out of Regulator

Gnd - Gnd of regulator

IO Pin 27 - connects to PG (power good) on regulator.

IO Pin 5 - 75ohm resistor > IR LED

Super Capacitor goes across VCC Gnd on ESP32

To decode IR Codes you will need an IR receiver. This is on IO PIN 15.

You can write any code you want in the TurnOn() and TurnOff() routines.

So you could send multiple commands to adjust input, change volume.

The supercapacitor provides enough time to also do more when shutting things down (ie you may put this on a receiver in your front room and may want it to switch it back to the TV input once music has stopped?)

Some other websites with helpful guides relevant to this.

The code contains everything to read and send IR codes. But I've commented out the reading part.

The code:

#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "WiFi.h" 
#include "driver/adc.h"
#include <esp_wifi.h>
#include <esp_bt.h>
#include <IRremote.h>
int RECV_PIN = 15;
int PG_PIN=27;
int powergood=0;
int pre_powergood=99;
int pg_count[2];
IRrecv irrecv(RECV_PIN);
IRsend irsend;
decode_results results;

void setup() {
  // put your setup code here, to run once:
 //WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 setCpuFrequencyMhz(80); // reduces power consumption by around 10mA

pinMode(PG_PIN, INPUT_PULLUP ); // Needed to read Power Good
//      irrecv.enableIRIn();  // Enable when you want to read IR codes


void loop() {
  // put your main code here, to run repeatedly:

// I used an array as I occasionally found a stay 1 come through so it needs to check the pin state a few times

if (powergood!=pre_powergood) {

if (pg_count[powergood]<10) pg_count[powergood]++;
if (pg_count[1]==3) {         // HIGH
if (pg_count[0]==3 ){           // LOW


if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    Serial.print(" - ");
    switch (results.decode_type){
        case NEC: Serial.println("NEC"); break ;
        case SONY: Serial.println("SONY"); break ;
        case RC5: Serial.println("RC5"); break ;
        case RC6: Serial.println("RC6"); break ;
        case DISH: Serial.println("DISH"); break ;
        case SHARP: Serial.println("SHARP"); break ;
        case JVC: Serial.println("JVC"); break ;
        case SANYO: Serial.println("SANYO"); break ;
 //       case MITSUBISHI: Serial.println("MISUBISHI"); break ;
        case SAMSUNG: Serial.println("SAMSUNG"); break ;
        case LG: Serial.println("LG"); break ;
        case WHYNTER: Serial.println("WHYNTER"); break ;
 //       case AIWA_RC_T501: Serial.println("AIWARC_T501"); break ;
        case PANASONIC: Serial.println("PNASONIC"); break ;
        case DENON: Serial.println("DENON"); break ;
        case UNKNOWN: Serial.println("UNKNOWN"); break ;
    irrecv.resume(); // Receive the next value


void turnOn() {

  for (int i = 0; i < 3; i++) {

    irsend.sendNEC(0x81CEE01F,32); // on
    //irsend.sendSony(21516, 15); //15        


void turnOff() {

  for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x81CE906F,32); // standby
    // irsend.sendSony(21516, 15);